This article, the second of three parts, explains what MSXML is and how to access an XML document using JavaScript. It is excerpted from chapter 10 of XML DeMYSTified, written by Jim Keogh and Ken Davidson (McGraw-Hill/Osborne, 2005; ISBN: 0072262109).
The InsertFirst() method is called when the user decides to place information about the new CD at the beginning of the XML document. Here’s the InsertFirst() method:
function InsertFirst() { var objNewNode = LoadNewNode(); if(objNewNode == null) { return; } var root = objXML.documentElement; root.insertBefore(objNewNode, root.firstChild); document.all("xmlresult").value = objXML.xml; }
The first line calls the LoadNewNode() method, which returns a reference to the root node of the information about the new CD. The reference is assigned to the objNewNode variable.
The second line determines if the value of the objNewNode is null. It’s null if the LoadNewNode() method doesn’t return a reference to the root node. If this happens, then the InsertFirst() method returns without inserting information about the new CD at the beginning of the XML document.
The third line is executed if the LoadNewNode() method returns a root node. The root node is a reference to an IXMLDOMElement object. This line assigns the value of the IXMLDOMElement object’s documentElement property of the new CD information to a variable called root.
The fourth line calls the insertBefore() method of the IXMLDOMElement object. The insertBefore() method has two arguments. The first argument is a reference to the node that’s being inserted into the document. This reference is returned by the LoadNewNode() method. The second argument is the node that will come after the new CD in the XML document.
The first CD in the XML document is 602498678299 (see the “Getting Down and Dirty with MSXML” section earlier in this chapter). The new CD will be inserted before CD 602498678299, making the new CD appear first in the XML document and CD 602498678299 second.
The second argument to the insertBefore() method is reference to CD 602498678299. CD 602498678299 is first in the XML document and, therefore, it can be identified by using the firstChild property of the IXMLDOMElement object.
The fifth line displays the code output of the XML representation of the DOMDocument into the text area of the HTML form. The output looks something like this:
<?xml version="1.0"?> <!DOCTYPE catalog SYSTEM "catalog.dtd"> <catalog> <cd upc="75596280822"> <artist>Phish</artist> <title>Live Phish, Vol. 15</title> <price>26.99</price> <label>ELEKTRA/WEA </label> <date>2002-10-29</date> </cd> <cd upc="602498678299"> <artist>U2</artist> <title>How to Dismantle an Atomic Bomb</title> <price>13.98</price> <label>Interscope Records</label> <date>2004-11-23</date> </cd> <cd upc="75679244222"> <artist>Led Zeppelin</artist> <title>Physical Graffiti</title> <price>22.99</price> <label>Atlantic</label> <date>1994-08-16</date> </cd> <cd upc="75678367229"> <artist>Rush</artist> <title>Rush in Rio</title> <price>13.98</price> <label>Atlantic</label> <date>2003-10-21</date> </cd> <cd upc="74646938720"> <artist>Billy Joel</artist> <title>Songs in the Attic</title> <price>10.99</price> <label>Sony</label> <date>1998-10-20</date> </cd> <cd upc="75678263927"> <artist>Led Zeppelin</artist> <title>Houses of the Holy</title> <price>10.98</price> <label>Atlantic</label> <date>1994-07-19</date> </cd> <cd upc="8811160227"> <artist>Jimi Hendrix</artist> <title>Are You Experienced?</title> <price>12.99</price> <label>Experience Hendrix</label> <date>1997-04-22</date> </cd> <cd upc="74640890529"> <artist>Bob Dylan</artist> <title>The Times They Are A-Changin'</title> <price>9.99</price> <label>Sony</label> <date>1990-10-25</date> </cd> </catalog>
The InsertLast() method is called when the user wants to place information about the new CD at the bottom of the XML document. Here’s the InsertLast() method:
function InsertLast() { var objNewNode = LoadNewNode(); if(objNewNode == null) { return; } var root = objXML.documentElement; root.appendChild(objNewNode); document.all("xmlresult").value = objXML.xml; }
You’ll notice that the InsertLast() method is nearly the same as the InsertFirst() method, except the appendChild() method is called instead of calling the insertBefore() method. The appendChild() method places information about the new CD at the end of the XML document.
The appendChild() method requires one argument, which is reference to information about the new CD. This reference is returned by the LoadNewNode() method.
Here’s the XML document after calling the InsertLast() method. You’ll notice that the first and last items in the XML document are the same CD because in our example we selected the InsertFirst option and then the InsertLast option. Each placed the same CD into different areas of the XML document. We’ve shown it this way to demonstrate that you can continue altering the document to get it into its desired final state. For the remaining examples, refresh the document using the LoadDocument() function so it only shows the current change.
<?xml version="1.0"?> <!DOCTYPE catalog SYSTEM "catalog.dtd"> <catalog > <cd upc="75596280822"> <artist>Phish</artist> <title>Live Phish, Vol. 15</title> <price>26.99</price> <label>ELEKTRA/WEA</label> <date>2002-10-29</date> </cd> <cd upc="602498678299"> <artist>U2</artist> <title>How to Dismantle an Atomic Bomb</title> <price>13.98</price> <label>Interscope Records</label> <date>2004-11-23</date> </cd> <cd upc="75679244222"> <artist>Led Zeppelin</artist> <title>Physical Graffiti</title> <price>22.99</price> <label>Atlantic</label> <date>1994-08-16</date> </cd> <cd upc="75678367229"> <artist>Rush</artist> <title>Rush in Rio</title> <price>13.98</price> <label>Atlantic</label> <date>2003-10-21</date> </cd> <cd upc="74646938720"> <artist>Billy Joel</artist> <title>Songs in the Attic</title> <price>10.99</price> <label>Sony</label> <date>1998-10-20</date> </cd> <cd upc="75678263927"> <artist>Led Zeppelin</artist> <title>Houses of the Holy</title> <price>10.98</price> <label>Atlantic</label> <date>1994-07-19</date> </cd> <cd upc="8811160227"> <artist>Jimi Hendrix</artist> <title>Are You Experienced?</title> <price>12.99</price> <label>Experience Hendrix</label> <date>1997-04-22</date> </cd> <cd upc="74640890529"> <artist>Bob Dylan</artist> <title>The Times They Are A-Changin'</title> <price>9.99</price> <label>Sony</label> <date>1990-10-25</date> </cd> <cd upc="75596280822"> <artist>Phish</artist> <title>Live Phish, Vol. 15</title> <price>26.99</price> <label>ELEKTRA/WEA</label> <date>2002-10-29</date> </cd> </catalog>
The InsertBefore() function is called when the user specifies the position of the new CD in the XML document. The user does this by entering the UPC code of the CD that will come after the new CD in the XML document. Here’s the InsertBefore() function:
function InsertBefore(upc) { var objNewNode = LoadNewNode(); if(objNewNode == null) { return; } var root = objXML.documentElement; var objNodes = objXML.selectNodes( "/catalog/cd[@upc='" + upc + "']"); if(objNodes.length == 0) { alert("Could not find node with upc " + upc); return; } root.insertBefore(objNewNode, objNodes.item(0)); document.all("xmlresult").value = objXML.xml; }
The UPC of the CD that will come after the new CD in the XML document is passed as an argument to the InsertBefore() function by the statement that calls the InsertBefore() function (see the “Getting Down and Dirty with MSXML” section in this chapter).
The first four lines of the InsertBefore() function are the same as those for the InsertFirst() and InsertLast() functions.
Line five calls the selectNodes() method of the DOMDocument object. This method requires one argument containing an XPath expression (see Chapter 5) to identify the node that will come after the new CD in the XML document.
This expression says, Look in the /catalog element for a cd element whose upc attribute is equal to the UPC passed to the selectNodes() method. There can be more than one match. Therefore, the selectNodes() method returns a collection that contains references of matching nodes.
Line six evaluates the value of the length property of the node list returned by the selectNodes() method. If the length is zero, then the CD entered by the user can’t be located in the XML document and an alert message is displayed; then the function returns to the statement that called it.
Line seven executes if the selectNodes() method returned a node indicating that the CD was found in the XML document. Line seven calls the insertBefore() method, which is also called by the InsertFirst() function and InsertLast() function. The insertBefore() method requires two arguments. The first argument references the new CD and the second argument references the first CD that will come after the new CD in the XML document. The second argument is the first node the collection returned by the selectNodes() method.
Line eight is the same as it was in the previous functions.
Here’s the XML document after the InsertBefore() function executes:
<?xml version="1.0"?> <!DOCTYPE catalog SYSTEM "catalog.dtd"> <catalog> <cd upc="602498678299"> <artist>U2</artist> <title>How to Dismantle an Atomic Bomb</title> <price>13.98</price> <label>Interscope Records</label> <date>2004-11-23</date> </cd> <cd upc="75679244222"> <artist>Led Zeppelin</artist> <title>Physical Graffiti</title> <price>22.99</price> <label>Atlantic</label> <date>1994-08-16</date> </cd> <cd upc="75596280822"> <artist>Phish</artist> <title>Live Phish, Vol. 15</title> <price>26.99</price> <label>ELEKTRA/WEA</label> <date>2002-10-29</date> </cd> <cd upc="75678367229"> <artist>Rush</artist> <title>Rush in Rio</title> <price>13.98</price> <label>Atlantic</label> <date>2003-10-21</date> </cd> <cd upc="74646938720"> <artist>Billy Joel</artist> <title>Songs in the Attic</title> <price>10.99</price> <label>Sony</label> <date>1998-10-20</date> </cd> <cd upc="75678263927"> <artist>Led Zeppelin</artist> <title>Houses of the Holy</title> <price>10.98</price> <label>Atlantic</label> <date>1994-07-19</date> </cd> <cd upc="8811160227"> <artist>Jimi Hendrix</artist> <title>Are You Experienced?</title> <price>12.99</price> <label>Experience Hendrix</label> <date>1997-04-22</date> </cd> <cd upc="74640890529"> <artist>Bob Dylan</artist> <title>The Times They Are A-Changin'</title> <price>9.99</price> <label>Sony</label> <date>1990-10-25</date> </cd> </catalog>
The InsertAfter() function is called when the user specifies a CD in the XML document that comes before the new CD. Here’s the InsertAfter() function:
function InsertAfter(upc) { var objNewNode = LoadNewNode(); if(objNewNode == null) { return; } var root = objXML.documentElement; var childNodes = root.childNodes; for(var i=0; i < childNodes.length; i++) { var node = childNodes.item(i); var nodeUPC = node.getAttribute("upc"); if(nodeUPC == upc) { root.insertBefore(objNewNode, childNodes.item(i+1)); document.all("xmlresult").value = objXML.xml; return; } } alert("Could not find node with upc " + upc); }
The first three lines are the same as they are in previous functions.
The fourth line assigns the childNodes property of the IXMLDOMElement object to the childNodes variable. The childNodes property contains all the child nodes of the <catalog > element in the document.
The fifth line executes a for loop that steps through each child node looking for the child node whose upc attribute matches the UPC code that the user entered. The item() method is called to retrieve the node from the list. Next, the getAttribute() method is called and passed the name of the attribute whose value you want returned. And then an if statement is used to compare the value of the upc attribute of the current child node to the UPC that the user entered.
If they match, then the insertBefore() method is called to insert the new CD into the XML document. The insertBefore() method requires two arguments. The first argument references information about the new CD and the second argument references the existing node in the XML document. The second argument jumps one node ahead by using i+1. In this way, it’s going to the next node and inserting before that. The API does not have an insertAfter() method so this is another way to accomplish the same thing. Suppose you were inserting after the last node in the list. i+1 would not reference a valid node because it’s beyond the boundary of the list. The second argument would evaluate to null. When the method sees null as the second argument, it puts the new node last in the list. It’s equivalent to calling appendNode(). The XML document is then displayed before the function returns to the statement that called the InsertAfter() function.
If they don’t match, then the function returns without changing the XML document.
Here’s the XML document after the new CD is inserted:
<?xml version="1.0"?> <!DOCTYPE catalog SYSTEM "catalog.dtd"> <catalog> <cd upc="602498678299"> <artist>U2</artist> <title>How to Dismantle an Atomic Bomb</title> <price>13.98</price> <label>Interscope Records</label> <date>2004-11-23</date> </cd> <cd upc="75679244222"> <artist>Led Zeppelin</artist> <title>Physical Graffiti</title> <price>22.99</price> <label>Atlantic</label> <date>1994-08-16</date> </cd> <cd upc="75678367229"> <artist>Rush</artist> <title>Rush in Rio</title> <price>13.98</price> <label>Atlantic</label> <date>2003-10-21</date> </cd> <cd upc="75596280822"> <artist>Phish</artist> <title>Live Phish, Vol. 15</title> <price>26.99</price> <label>ELEKTRA/WEA</label> <date>2002-10-29</date> </cd> <cd upc="74646938720"> <artist>Billy Joel</artist> <title>Songs in the Attic</title> <price>10.99</price> <label>Sony</label> <date>1998-10-20</date> </cd> <cd upc="75678263927"> <artist>Led Zeppelin</artist> <title>Houses of the Holy</title> <price>10.98</price> <label>Atlantic</label> <date>1994-07-19</date> </cd> <cd upc="8811160227"> <artist>Jimi Hendrix</artist> <title>Are You Experienced?</title> <price>12.99</price> <label>Experience Hendrix</label> <date>1997-04-22</date> </cd> <cd upc="74640890529"> <artist>Bob Dylan</artist> <title>The Times They Are A-Changin'</title> <price>9.99</price> <label>Sony</label> <date>1990-10-25</date> </cd> </catalog>
Now we’ll show you how to create a new <cd> element and its child elements and insert them into an XML document using a program. First you’ll create an HTML page that contains the input fields where you can enter values for the new CD:
You’re required to enter six values. These are the upc attribute and values for each of the five child elements. Click the hyperlink once you’re finished and the CreateAndAppendNode() function executes. Here’s the CreateAndAppendNode() function:
function CreateAndAppendNode() { var upc = document.all("createUpc").value; var artist = document.all("createArtist").value; var title = document.all("createTitle").value; var price = document.all("createPrice").value; var label = document.all("createLabel").value; var date = document.all("createDate").value; var elementCd = objXML.createElement("cd"); elementCd.setAttribute("upc", upc); var elementArtist = objXML.createElement("artist"); var textArtist = objXML.createTextNode(artist); elementArtist.appendChild(textArtist); elementCd.appendChild(elementArtist); var elementTitle = objXML.createElement("title"); var textTitle = objXML.createTextNode(title); elementTitle.appendChild(textTitle); elementCd.appendChild(elementTitle); var elementPrice = objXML.createElement("price"); var textPrice = objXML.createTextNode(price); elementPrice.appendChild(textPrice); elementCd.appendChild(elementPrice); var elementLabel = objXML.createElement("label"); var textLabel = objXML.createTextNode(label); elementLabel.appendChild(textLabel); elementCd.appendChild(elementLabel); var elementDate = objXML.createElement("date"); var textDate = objXML.createTextNode(date); elementDate.appendChild(textDate); elementCd.appendChild(elementDate); var root = objXML.documentElement; root.appendChild(elementCd); document.all("xmlresult").value = objXML.xml; }
The first six lines gather values from the HTML table and assign them to variables.
Line seven calls the createElement() method to create a new element. The createElement() method requires one argument, which is the name of the element that you want to create. In this example, you’re creating a cd element. The createElement() method returns a reference to the new element.
Line eight calls the setAttribute() method to assign a value to the attribute of the new element. The setAttribute() method requires two arguments. The first argument is the name of the attribute that’s being set and the second argument is the value assigned to the new attribute.
Lines 9 through 30 create child elements for the <cd> element. Notice that each child element is actually two nodes—one for the element and the other for the text. Line 31 displays the XML document, as we show here:
<?xml version="1.0"?> <!DOCTYPE catalog SYSTEM "catalog.dtd"> <catalog> <cd upc="602498678299"> <artist>U2</artist> <title>How to Dismantle an Atomic Bomb</title> <price>13.98</price> <label>Interscope Records</label> <date>2004-11-23</date> </cd> <cd upc="75679244222"> <artist>Led Zeppelin</artist> <title>Physical Graffiti</title> <price>22.99</price> <label>Atlantic</label> <date>1994-08-16</date> </cd> <cd upc="75678367229"> <artist>Rush</artist> <title>Rush in Rio</title> <price>13.98</price> <label>Atlantic</label> <date>2003-10-21</date> </cd> <cd upc="74646938720"> <artist>Billy Joel</artist> <title>Songs in the Attic</title> <price>10.99</price> <label>Sony</label> <date>1998-10-20</date> </cd> <cd upc="75678263927"> <artist>Led Zeppelin</artist> <title>Houses of the Holy</title> <price>10.98</price> <label>Atlantic</label> <date>1994-07-19</date> </cd> <cd upc="8811160227"> <artist>Jimi Hendrix</artist> <title>Are You Experienced?</title> <price>12.99</price> <label>Experience Hendrix</label> <date>1997-04-22</date> </cd> <cd upc="74640890529"> <artist>Bob Dylan</artist> <title>The Times They Are A-Changin'</title> <price>9.99</price> <label>Sony</label> <date>1990-10-25</date> </cd> <cd upc="75596280822"> <artist>Phish</artist> <title>Live Phish, Vol. 15</title> <price>26.99</price> <label>ELEKTRA/WEA</label> <date>2002-10-29</date> </cd> </catalog>
Please check back next week for the conclusion of this article.