Today's sample was created upon a request from my very nice and hard working office-mate Chris.  Last week Chris began learning HDi.  He whizzed through all the Jumpstart samples and the projects on my blog, and jumped into creating a project that would dynamically generate content on the fly.  After messing around with his project for a few days, Chris said I should write a blog how to do this for other people who had questions like his.  So, here it is. 

There is a sample project is attached at the end of this blog.  In this project, an XML file is parsed, data is extracted using XPath, text is dynamically added to the markup, and new "skins" are applied to the data by changing the loaded markup file.


XML Data
Let's say you have a project where you want to separate your data from your presentation layer.  Maybe you want to download new content from the network.  Maybe you want to be able to apply different skins to the same piece of content.  The obvious way to separate your data is by using XML. 

<?xml version="1.0" encoding="utf-8"?>

<data>

  <headline value="This Is The Header"/>

  <subheading value="Here's a Subheading"/>

  <paragraph>Lorem ipsum . . .</paragraph>

  <paragraph>Lorem ipsum . . .</paragraph>

</data>

In this project, the data is in a file called data.xml and it is included with the project.


XMLParser
Before the application does anything with this XML, we need to use the XMLParser to create a DOM.


XMLParser.parse(uri, parseCallback);

function parseCallback(status, dom)

{

if (status == XMLParser.OK)

{

//do something with dom

}

}


XMLParser.parse takes two arguments - uri is the full path of the xml file (file:///dvddisc/ADV_OBJ/data.xml in this project) and the callback function which is called when the XMLParser has completed and is ready to return the DOM.

XMLParser also has a method called parseString which will create a DOM from a string.  The parseString function returns the DOM directly without the callback.


var dom = XMLParser.parseString("<data><headline value=\"This Is The Header\"/></data>");


This can be very handy to use if your XML comes from getResponseString() from a network request or if you want to create a new empty DOM on the fly. (For more information on networking, read http://blogs.msdn.com/amyd/archive/2007/09/20/very-simple-network-example.aspx)


evaluateXPath
There are a couple of ways to can go through the newly created DOM.  We could cycle through all the childNodes using DOM Level 2 ECMAScript Language Binding.  Or, we can use XPath.  (Note, Xpath axes are not supported).  In this project, I've chosen to use some simple XPath calls to extract my data using evaluateXPath.


var nodes = dom.evaluateXPath("//headline", dom.documentElement);


evaluateXPath returns a nodeList.  Since I know I'm only expecting one headline here, if I do get a non-empty nodelist, I only need the first item and its value attribute.


var headline = nodes.item(0).getAttribute("value");


The call to evaluteXPath for paragraph from my DOM will return more than one node.  Also, the data here is in a text node, not an attribute.  This text node is the first child of the paragraph tag and its contents can be retrieved by calling nodeValue.


for (var i = 0; i < nodes.length; i++)

{

   // do something with nodes.item(i).firstChild.nodeValue;

}


I could go back to this DOM every time I need to get this data, but my application would take a performance hit.  So once I get my data, I cache it for use later.


Adding Text to Markup

Okay, the XML has been parsed and data cached, so now we can put it in the markup.  Here we will use the DOM Level 2 ECMAScript Language Binding to create new paragraph tags (elements that can hold text) and text nodes inside.


function addText(element, txt)

{

    var p = document.createElement("p");

    var text = document.createTextNode(txt);

    p.appendChild(text);

    element.appendChild(p);

}


And, of course once this is complete, we load the changes to the modified markup by calling document.load.  For more information on why you need to call document.load, read Peter Torr's blog on Live vs. Load DOM.


Switching Between Markup Files
And, finally, just for kicks, I've added the ability to load new markup pages in order to reskin the data using the link() function.

Happy Programming!