View this PageEdit this PageAttachments to this PageHistory of this PageHomeRecent ChangesSearch the SwikiHelp Guide
Hotspots: Admin Pages | Turn-in Site |
Current Links: Cases Final Project Summer 2007

Smalltalk and XML

Smalltalk and XML

by Drew Roberts - gtg229x


Part 1 - Why use XML?

XML, or eXtensible Markup Language, is most commonly used to represent structured data in a manner that can easily be used across multiple platforms. XML provides a programmer with the ability to abstract useful information from an application and store in an organized, logical manner. Visualworks Smalltalk provides an XML package that allows a user to create XML documents with either the Domain Object Model (DOM) or SAX API's (Simple API for XML). For the purposes of this tutorial, we will reference only the DOM. In the following sections, you will learn how to create XML documents, add elements to a document, as well as how to write an XML document to a file.

Part 2 - Creating an XML Document and Adding the Root Node

To create a new XML document in Smalltalk, simply create a new instance of XML.Document:
document := XML.Document new

This stores a new XML document in the variable
document
Now that you have created an XML document you can begin to add nodes to the document. Simply put, a node is the most basic element of XML document. A node can contain either information about the node or a node can contain other nodes. A node is quit similar to a class in an OO language in that a node holds information and other nodes just as a class holds information about the class and also possibly contains refereces to other classes. All XML documents must contain a root node. The root node is at the top of the hierarchial structure and all to other nodes are added to the root node. To add the root node to a document, you first add the XML Processing Instruction element to the document:
document addNode: (XML.PI name: 'xml' text: 'version="1.0"')

The Processing Intruction element (or PI) provides the document with the information it needs to add nodes to the document. After adding the PI, you add an element to the document:
document addNode: (XML.Element tag: 'root')

XML.Element is the object you will be adding to the document each time you want to add a new node. You will learn more about elements in later section but for now just know that an element roughly correlates to a node. In the element, that tag is simply what you would like the node, or element, to be called. If you were to write your document to a file at this point (more about writing to a file later), your document would look like this:
<?xml version="1.0" ?> 
<root>
</root>

Looking at this XML, you can see that we have an XML 1.0 document with the root node added.

Part 3 - Adding More Nodes to a Document

Now we will talk about adding nodes to your document. To add another node to your document, you use the same message as you used for the root node:
document addNode: (XML.Element tag: 'node1')

We can continue to add more nodes in this manner:
document addNode: (XML.Element tag: 'node2').
document addNode: (XML.Element tag: 'node3').

Now our document will look like this:
<?xml version="1.0" ?>
<root>
   <node1>
   </node1>
   <node2>
   </node2>
   <node3>
   </node3>
</root>

Another useful aspect of XML is the ability to nest nodes within other nodes. This can be done in one of two ways. The first way to produce nested nodes is the send the addNode: message in sequence with other addNode: messages:
document addNode: (XML.Element tag: 'node1')
    addNode: (XML.Element tag: 'nestedNode1')
        addNode: (XML.Element tag: 'nestedNode2')

This code produces the following XML document:
<?xml version="1.0" ?>
<root>
   <node1>
      <nestedNode1>
         <nestedNode2>
         </nestedNode2>
      <nestedNode1>
   </node1>
</root>

You can also produce this code by sending the addNode: message to an element:
| node1 nestedNode1 nestedNode2 |
node1 := (XML.Element tag: 'node1').
nestedNode1 := (XML.Element tag: 'nestedNode1').
nestedNode2 := (XML.Element tag: 'nestedNode2').
nestedNode1 addNode: nestedNode2.
node1 addNode: nestedNode1.
document addNode: node1.

This produces the same XML document as before:
<?xml version="1.0" ?>
<root>
   <node1>
      <nestedNode1>
         <nestedNode2>
         </nestedNode2>
      <nestedNode1>
   </node1>
</root>

You can now use what you know to create the basic framework of an XML document. You should now understand why XML is useful for organizing structured data and see how XML correlates with an object-oriented language. Next, you will learn how to add values to the nodes you have been creating.

Part 4 - Adding Values to Nodes

It's good that you can now add nodes and nested nodes to your XML document. However, what good are all those nodes if the nodes don't contain any information! Adding values to nodes is where Smalltalk XML gets a little tricky. To add a node with a value, you must create an element object using the tag:, attributes:, and elements: messages. The tag: message is used just as explained earlier. It provides the name of the node. The attributes: element will almost always take the value nil. Attributes are specify special features of an element. However, attributes are difficult to use and are less important than a node value. For that reason, attributes have been left out of this tutorial. Finally, the elements: message is what specifies the value of the element. This may all seem a bit confusing so lets take a look at an example:
| value |
value := OrderedCollection with: (XML.Text text: '12345').
document addNode: (XML.Element tag: 'node1' attributes: nil element: value).

This code will produce te following XML document:
<?xml version="1.0" ?>
<root>
   <node1>12345</node1>
</root>

Now, I must say, I have yet to find any logical reasoning behind having to create an OrderedCollection for the elements: message. Maybe there is something far greater the developers of Smalltalk had envisioned for the XML package, but, for now, simply use OrderedCollections to please the language. Moving on now, You can also use values just as you did earlier with nested elements:
| value1 |
value1 := OrderedCollection with: (XML.Text text: 'A').
document addNode: (XML.Element tag: 'node1')
    addNode: (XML.Element tag: 'nestedNode1')
        addNode: (XML.Element tag: 'nestedNode2' attributes: nil elements: value1).

This code produces the following XML document:
<?xml version="1.0" ?>
<root>
   <node1>
      <nestedNode1>
         <nestedNode2>A</nestedNode2>
      </nestedNode1>
   </node1>
</root>

Values provide a way to store information about a node while keeping with the structured manner of XML. This has been just a brief explanation of values. More about values and XML can be found in the BasicLibraries document found in the documentation that comes with Visualworks Smalltalk. In the following section, you will learn how to write your XML document to a file.

Part 5 - Writing Your Document to a File

In this final section, you will learn how to write your XML document to a file. This is rather simple so let's take a look at the code that write the document and I will explain how it works:
| file fileName writer |
fileName :=  SaveFileDialog new select.
file := fileName asFilename writeStream.
writer := XML.SAXWriter new output: file.
[document saxDo: writer] ensure: [file close].

This code does the following:
  1. Opens a file dialog and allows the user to select the file to write to
  2. Takes the user selected file and turns it into a write stream by sending it the writeStream message.
  3. Create a new XML file writer with the specified file.
  4. Writes the document to the file and ensure that the file is closed upon completion.
This is all it takes to write your document to a file. Of course, you could manually type in your filename. However, the previously used file dialog is a lot easier to use.

Conclusion
Hopefully this tutorial has helped you understand how to create and write XML documents in Visualworks Smalltalk. Check out the Cuthroat Trout project page for a change set that contains example of XML from the CS2340 Fall 2006 final project.

Links to this Page