Hi,
how can I have code executed after anIXMLDOMDocument has successfully loaded? I've been using |doc| doc := IXMLDOMDocument new. doc async: false. doc loadURL:'some.url.com'. root := doc documentElement. in a method, but will only work when I do "doc async: false". Would this be foreign function callback, event trigger or something else. Looking at the class doesn't give me any clues. Günther |
Guenther,
I assume that you want that execution done asynchonously. I'm not familiar with IXMLDOMDocument, so I don't know, what special mechanisms that class provides, but have you considered executing the whole block asynchronously, i.e. [ |doc| doc := IXMLDOMDocument new. doc async: false. doc loadURL:'some.url.com'. root := doc documentElement ] fork. If your coding depends on a certain variable being available at a particular time you might have to use a semaphore though, or perhaps instead of using #fork, you might be able to use a DeferredValue, which takes care of the semaphore handling for you. Bernhard Günther Schmidt wrote: > Hi, > > how can I have code executed after anIXMLDOMDocument has successfully > loaded? > > I've been using > > |doc| > > doc := IXMLDOMDocument new. > doc async: false. > doc loadURL:'some.url.com'. > root := doc documentElement. > > > in a method, but will only work when I do "doc async: false". > > Would this be foreign function callback, event trigger or something > else. Looking at the class doesn't give me any clues. > > Günther |
Dear Bernhard,
Bernhard Kohlhaas wrote: > Guenther, > > I assume that you want that execution done asynchonously. I'm not > familiar with IXMLDOMDocument, so I don't know, what special mechanisms > that class provides, but have you considered executing the whole block > asynchronously, i.e. > > [ |doc| > doc := IXMLDOMDocument new. > doc async: false. > doc loadURL:'some.url.com'. > root := doc documentElement ] fork. > > If your coding depends on a certain variable being available at a > particular time you might have to use a semaphore though, or perhaps > instead of using #fork, you might be able to use a DeferredValue, which > takes care of the semaphore handling for you. > How would I do either (using semaphore or DeferredValue)? This is entirely new ground for me. Günther |
In reply to this post by Günther Schmidt
Günther,
> how can I have code executed after anIXMLDOMDocument has successfully > loaded? I assume that you want to use asynchronous loading so that your application doesn't freeze while it's waiting for the download to complete ? If not then the following may not make much sense, or may be wrong... There seem to be at least two techniques (found by assiduous Googling, since I didn't know this stuff either...). Given: url := 'whatever.xml'. doc := IXMLDOMDocument new. One simple technique is just to pump Windows messages while you are waiting for the document's #readyState to become 4: doc loadURL: url. [doc readyState = 4] whileFalse: [SessionManager inputState pumpMessages]. doc documentElement inspect. That will process Windows messages "in-line", so your application will continue to respond to user-input while the #whileFalse: loop is ongoing. You'd probably need to set some flags to say that a download is underway, or else you might end up allowing the user to start another download while the first was still incomplete. A more complex way (that I admit I don't fully understand -- so I hope that someone will point out any errors I've made), is to use an AXEventSink to translate the "onreadystatechange" notifications into normal Dolphin events. That's a little tricky to illustrate in with code you can run in a workspace, but here's a nasty hack to set up an example event handler (real code would look nothing like this because you'd be able to use normal methods, rather than sending #value to a Block). target := Object new. handler := [(doc readyState = 4) ifTrue: [doc documentElement inspect]]. target when: #onreadystatechange send: #value to: handler. With that hack out of the way, we can now utter the mystical incantation that arranges for the #onreadystatechange event to be triggered off the target object: typeInfo := doc coclassTypeInfo defaultSourceInterface. sink := AXEventSink target: target sourceTypeInfo: typeInfo. sink connect: doc. and now we can start loading the URL asynchronously: doc loadURL: url. and the inspector should open once the download is complete. If you had the equivalent code (without the hack) in your application, then once you had executed the last line, your app would return to its normal event-driven mode, waiting for the next user-input and reacting to that as it happened. Also, at some later time, the event would be triggered and your handler code then would be executed. As with the #pumpMessages approach, you' might want to set some sort of flag to say that you were expecting a download to complete sooner or later, and use that to stop the user starting another download before the first had completed. BTW, if you do use flags like that, don't forget to test what happens when the download fails halfway, since you wouldn't want the flag to remain set in that case. (I have no idea how a IXMLDOMDocument behaves when a download fails like that, so I can't suggest a suitable way of handling it.) -- chris |
Chris,
Chris Uppal wrote: > Günther, > > >>how can I have code executed after anIXMLDOMDocument has successfully >>loaded? > > > I assume that you want to use asynchronous loading so that your application > doesn't freeze while it's waiting for the download to complete ? If not then > the following may not make much sense, or may be wrong... you're exactly right. Even if I put this into a "fork", which is what I've done first, the UI freezes. > > There seem to be at least two techniques (found by assiduous Googling, since I > didn't know this stuff either...). > > Given: > > url := 'whatever.xml'. > doc := IXMLDOMDocument new. > > One simple technique is just to pump Windows messages while you are waiting for > the document's #readyState to become 4: > > doc loadURL: url. > [doc readyState = 4] whileFalse: [SessionManager inputState pumpMessages]. > doc documentElement inspect. > > That will process Windows messages "in-line", so your application will continue > to respond to user-input while the #whileFalse: loop is ongoing. You'd > probably need to set some flags to say that a download is underway, or else you > might end up allowing the user to start another download while the first was > still incomplete. > > A more complex way (that I admit I don't fully understand -- so I hope that > someone will point out any errors I've made), is to use an AXEventSink to > translate the "onreadystatechange" notifications into normal Dolphin events. > That's a little tricky to illustrate in with code you can run in a workspace, > but here's a nasty hack to set up an example event handler (real code would > look nothing like this because you'd be able to use normal methods, rather than > sending #value to a Block). > > target := Object new. > handler := [(doc readyState = 4) ifTrue: [doc documentElement inspect]]. > target when: #onreadystatechange send: #value to: handler. > Chris if this works, that would be the best solution (I think). I already thought there would have to be some sort of Event meachanism but I couldn't find out what signals would be triggered. > With that hack out of the way, we can now utter the mystical incantation that > arranges for the #onreadystatechange event to be triggered off the target > object: > > typeInfo := doc coclassTypeInfo defaultSourceInterface. > sink := AXEventSink target: target sourceTypeInfo: typeInfo. > sink connect: doc. > > and now we can start loading the URL asynchronously: > > doc loadURL: url. > > and the inspector should open once the download is complete. > > If you had the equivalent code (without the hack) in your application, then > once you had executed the last line, your app would return to its normal > event-driven mode, waiting for the next user-input and reacting to that as it > happened. Also, at some later time, the event would be triggered and your > handler code then would be executed. As with the #pumpMessages approach, you' > might want to set some sort of flag to say that you were expecting a download > to complete sooner or later, and use that to stop the user starting another > download before the first had completed. > > BTW, if you do use flags like that, don't forget to test what happens when the > download fails halfway, since you wouldn't want the flag to remain set in that > case. (I have no idea how a IXMLDOMDocument behaves when a download fails like > that, so I can't suggest a suitable way of handling it.) > > -- chris > > All in all I'm surprised that there are no previous postings relating to this particular problem. I had thought a lot of people are use XML one way or the other. Thanks Günther |
In reply to this post by Günther Schmidt
Guenther Schmidt wrote:
[...] > How would I do either (using semaphore or DeferredValue)? This is > entirely new ground for me. I wasn't aware that the loading would block the entire UI. So my suggestions do not apply here, so just forget about them and follow Chris' suggestion. Sorry for the confusion, Bernhard |
Free forum by Nabble | Edit this page |