This post originated from an RSS feed registered with Agile Buzz
by James Robertson.
Original Post: Enriching VW's DOM
Feed Title: Michael Lucas-Smith
Feed URL: http://www.michaellucassmith.com/site.atom
Feed Description: Smalltalk and my misinterpretations of life
I thought I might talk a bit about some of the changes we've made to the VisualWorks system in our pursuit of WithStyle. There's one particular area of the system that, although minor, deserves a fair bit of attention, as these facilities have uses outside the scope of WithStyle.
The package is called WsXMLCore and if you've signed up for your own copy of Kyx, the second technology Preview of WithStyle WebUI, you'll be able to tune in and take a look for yourself at the innards and outards of the system.
But, as always, you'll be looking at out of date software. Just yesterday I added a host of new features to this package which will, I hope, make you eager to get your hands on the next version (coming soon).
Better reflection
Better reflection is very important in Smalltalk. One area that seemed to be lacking were methods such as #attributes, which were accessable only on XML.Element's, not any kind of node. Small changes such as implementing it to return ^#() make the system much more approachable to the lasy message sender (most of us)
sourceURI
In WithStyle, nearly all the information you deal with comes from somewhere. Whether that somewhere is a method, or a http address, or a file address, we don't really care, but sometimes you need to be able to remember where you came from. For this purpose, XML.Document responds to #sourceURI: and #sourceURI. In fact, if you're using WithStyle's resourcing protocols 'http://www.w3.org' asURI wsResource, then the DOM tree you get back will already have sourceURI set.
relative URI's
To carry on from sourceURI, one immediate use is to resolve relative URL's in to absolute URL's. On any XML node you can send self resolvedHref: aHref, which will resolve it to be absolute if it is relative, or leave it as it is if it's already absolute. If your XML.Element subclass responds to #href, then you can call #resolvedHref without the argument and it will default to using self href to get the parameter.
Language
There is an XML standard for switching XML elements based on language, and it's the attribute xml:lang="en", where the value is the standard international language codes. Using #currentLanguage: and #currentLanguage, you can set the language you are using the XML document in. Calls to #elementsInCurrentLanguage will filter out xml:lang's that aren't of the current language, while including languageless nodes.
ExtraDetails
Sometimes there's just information that you want to keep on an XML document, such as, default CSS for the document, default XSD for the document, etc. I can hear you all saying, why not just use #userData? - Well, the idea behind extraDetails is that it is more portable than userData.
Changes
You can send #hasChanged to your XML.Document any time you like now and it'll tell you if any DOM action has been performed upon it, such as addNode:, removeNode:, etc, etc. To mark and unmark whether a DOM tree has changed, you can send #markChanged and #markUnchanged to XML.Document
Processing Instructions
To get at the processing instructions of your document, we've made a quick convenience method called #processingInstructions, which filters out all the other noise of the document to get you back the root level PI's.
Post Initialize
Sometimes you need to perform some more actions once an XML document has been parsed. Your XML.Node's can now implement #postInitialize to do whatever it is they need to do, and to kick it all off, send XML.Document the message #doPostInitialize.
XML Output
Don't use printString on an XML.Document to get your XML document out - for a couple of reasons. Unicode characters are not transformed in to XML Entities and XML namespaces are not written out at the top of the document either!. Instead, one should use the Sun canonical printer.. but alas there is no easy way to invoke it. Now, you can call #printSunCanonical on XML.Document
Undo Redo stack
And this is the Gem I added just yesterday. All DOM modification methods, such as addNode:, addAttribute:, replaceNode:with:, etc, now endevour to record both an undo and a redo record on to the XML.Document. The result being that you can send the message #undo and #redo to an XML.Document and watch the DOM tree transform before your eyes.
To kick it off, you need to wrap up your changes to your DOM tree inside the method whileRecordingUndoRedoDo:. This creates an UndoRedoAction object in the XML.Document for XML.Node's to use. All change will be recorded in to this single object until your block ends. Calling #undo will now issue the undo part of the action. The action is moved to the #redo side of the protocol. But if you do more actions before doing the redo, the redo is reset.
While undo and redo are running, no undo actions will be recorded. To record your own actions in your own DOM changing methods, you simple call self recordRedo: #addNode: undo: #removeNode: argument: aNode. This simple inclusion for all DOM tree's to have an undo/redo history has given WithStyle an undo/redo ability for editing documents and showing the changes as the occur! This will be demo'd at Smalltalk Solutions.
Modifications
We've extended the DOM modification protocols quite a bit. Here's my list: #addAttribute:, #addAttributeNamed:value:, #addAttributeNamed:value:namespace:, #addNewNode:, #addNewNodeNamed:, #addNode:, #addNode:after:, #addNode:at:, #addNode:before:, #addNodeFirst:, #addText:, #addText:after:, #addText:before:, #addTextFirst:, #removeAttribute:, #removeFromParent, #removeNode:, #replaceNode:with:, #splitAt:, #splitAtNode:, #splitText:at:
And there are many more things we've done to it, but those are the major points I wanted to share with you. If you want to get your hands on this stuff, drop me an email or go through the request procedure on our website, http://www.softwarewithstyle.com