In my last two articles, I showed you how to create and read XML files in WSH. Today, I’m going to bring this series to a close by showing you how to modify XML files. This includes modifying the text data in the file as well as modifying the XML structure.
Contributed by Nilpo Rating: / 5 December 08, 2008
To begin, you'll need an XML file to work with. If you don't have the example file from the last two articles, you can grab it here.
Perhaps the most common reason for modifying an XML file is to append data. This is comparable to adding a new record to a database. Let's take our example XSPF playlist and add another set of track information as follows:
The script first needs to open the XML file and load its document tree.
Set objXmlDoc = CreateObject("Microsoft.XMLDOM")
objXmlDoc.async = False
objXmlDoc.load("C:Playlist.xml")
This portion of the script returns an XML Document object by creating an instance of Microsoft's XML Parser. Next, the async property is set to false to help ensure that the script does not continue to execute until the file is fully loaded. Finally, the load method is used to load the XML document into the parser.
Set objRoot = objXmlDoc.documentElement
The XML Document object exposes a documentElement method which has the net effect of returning the first, or root, element of the document. By creating a reference to the root element, you can traverse the entire document tree from the top down. We don't have a need for this in today's example, but it's important to keep this in mind.
In order to add a new element, we must first create a reference to the new element's parent object. This is most easily done by using a query string. In this case, we need to add a new track element. If you examine the XML file, you will see that track elements are children of the trackList element.
Set objTrackList = objXmlDoc.selectSingleNode("/playlist/trackList")
The selectSingleNode method is used to return a single node based upon the query string provided. In this case, it returns a reference to the trackList element.
Set objTrack = objXmlDoc.createElement("track")
objTrackList.appendChild objTrack
Next, you can use the XML Document object's createElement method to create a new track element. It is then attached to the document as a child of the trackList node by using the appendChild method exposed by that object.
Set objLocation = objXmlDoc.createElement("location")
Set objTrackNum = objXmlDoc.createElement("trackNum")
objTrackNum.Text = "2"
objTrack.appendChild objTrackNum
Each of the property elements can then be added to the newly created track element in the same manner. The text property of each newly created child element is set using the text property.
objXmlDoc.save "C:Playlist.xml"
Once you've added all of the required elements, a call to the XML Document object's save method will write those changes to the XML file.
The previous example demonstrates the simplest approach to adding new records by appending them as children to the existing document tree. Sometimes, however, you may find that you don't want your newly created element to appear as the last element on the tree. For example, perhaps you wish for it to be the first element.
Set objTrackList = objXmlDoc.selectSingleNode("/playlist/trackList")
Set objFirstChild = objTrackList.firstChild
In this example, I'm taking a slightly different approach. The selectSingleNode method returns a reference to the trackList element. That reference exposes a firstChild method that returns a reference to the object's first child object. In our case, this is the first track element.
Set objTrack = objXmlDoc.createElement("track")
objTrackList.insertBefore objTrack, objFirstChild
Now, we can create a new track element and place it in the document as the first child. To do so, we'll need to use the insertBefore method of the trackList object. It accepts two parameters: the first is an object reference to the element to be inserted into the document tree and the second is an object reference to the element before which it should be inserted. In this case, the insertBefore method is inserting the newly created track element as a sibling immediately before the first existing track element.
There are several other methods available that can be used to place newly created elements into the document tree as well.
The firstChild method has a counterpart lastChild method. The lastChild method will return a reference to the last child element for an object.
Along with the firstChild and lastChild method, you can also find references to other elements using the previousSibling and nextSibling methods. Just as their names imply, these methods return references to the elements immediately preceding and following an object, respectively. These methods can often be used in conjunction to create the desired affect.
Set objTrackList = objXmlDoc.selectSingleNode("/playlist/trackList")
This example will insert the newly created element as the second record. It first uses the firstChild method to return a reference to the first track element. Then, the nextSibling method is used to return a reference to the second track element. Finally, the insertBefore method is used to insert the newly created track element before the second existing one, thus making the new element the second element.
The second most common reason for modifying an XML file is probably to change the data that is stored in it-much like updating a record in a database. There are two distinct approaches you can take when modifying data in an XML file. The first of these is to simply change the text value of an existing element. Take our newly added song for instance. If you look at the links, the song title should have been "Cold," not "Dead Skin." Let's go ahead and change that now.
Here the selectSingleNode is used to return a reference to the title element of the track record whose title is currently set to "Dead Skin." That object's text property can then be used to set the title element to a new value. You can also update multiple records at one time.
In this case, the selectNodes method is used to return a collection of any and all elements matching the criteria. A For Each loop can then be used to modify each matching instance.
Another approach to manipulating the data in an XML file is to replace one element with another. With this method, you can effectively overwrite an element with an updated element. For example, what if we didn't want to add this last song as a new record, but rather wanted to replace an existing song with this one instead?
Set objTrackList = objXmlDoc.selectSingleNode("/playlist/trackList")
This is accomplished using the replaceChild method. The first of its two parameters specifies the newly created object and the second specifies the object that it is to replace. Here, I am simply creating a new track element and replacing the last one in the list.
Finally, you may find that you wish to remove a record (or element) to effectively delete it from the database. Each node object exposes a removeChild method for this. Let's remove the new song that we've just added.
Set objTrack = objXmlDoc.selectSingleNode( _
"/playlist/trackList/track [title = 'Cold']")
objTrack.parentNode.removeChild objTrack
I've used the selectSingleNode method to return a reference to the track element for the song we've just added to the XML file. In order to remove this element, I must access it from its parent element. Notice how I've used the track object's parentNode method to return a reference to its parent element. Then I've immediately called the removeChild method from the parent and supplied the track object as its parameter. I know that it seems a bit counter-intuitive, but unfortunately, there is no way to remove an element directly.
Set colTracks = objXmlDoc.selectNodes("/playlist/trackList/track")
For Each objTrack In colTracks
objTrack.parentNode.removeChild objTrack
Next
As you probably imagined, you could use this technique for a collection of objects as well. The example above will return every track element and then remove them one by one.
That wraps up this series on working with XML files. Over the course of three articles you've learned how to use the Microsoft XML Parser to create, read, and modify XML files. You'll find the more you use this, the easier it becomes. It's not half as hard as it seems on the surface. Until next time, keep coding!