Creating XML Trees with the XmlTextWriter and XmlDocument Objects - Adding More
(Page 6 of 7 )
Now, you've just seen how the XmlDocument object can be easily manipulated to write an XML file. However, the example on the previous page didn't mention adding attributes. And with good reason -- adding that particular capability is no small task. But hey, I did it for you anyway.
<%@ Page Language="C#" Debug="true" %>
<%@ import namespace="System.Xml"%>
<%@ import namespace="System.Collections"%>
<html>
<head>
<script runat="server">
XmlElement MyElement(XmlDocument objXmlDocument, String strElementName, String strElementText, Hashtable htAttrs) {
XmlElement objElement = objXmlDocument.CreateElement(strElementName,null);
if(htAttrs != null && htAttrs.Count != 0) {
IDictionaryEnumerator enumAttr = htAttrs.GetEnumerator();
while (enumAttr.MoveNext()) {
objElement.SetAttribute(enumAttr.Key.ToString(),enumAttr.Value.ToString());
}
}
objElement.AppendChild(objXmlDocument.CreateTextNode(strElementText));
return objElement;
}
void Page_Load() {
// initialize an XmlTextWriter object
XmlDocument objXmlDocument = null;
// path to the XML file
String strXmlFile = " E:/Inetpub/wwwroot/xml/library.xml ";
// start the "try" block
try {
// instantiate an XmlDocument object
objXmlDocument = new XmlDocument();
// create an XmlDeclaration object
// and append it to XmlDocument object
XmlDeclaration objXmlDec = objXmlDocument.CreateXmlDeclaration("1.0", null, "no");
objXmlDocument.AppendChild(objXmlDec);
// create a root element
XmlElement objRootElement = objXmlDocument.CreateElement("library",null);
// create first level element
XmlElement objElementLeveOne = objXmlDocument.CreateElement("book",null);
objElementLeveOne.SetAttribute("bkid","MFRE001");
// append elements at second level to first level element
objElementLeveOne.AppendChild(MyElement(objXmlDocument,
"title","XML and PHP", null));
objElementLeveOne.AppendChild(MyElement(objXmlDocument,
"author","Vikram Vaswani", null));
objElementLeveOne.AppendChild(MyElement(objXmlDocument,
"description","Learn to manage your XML data with PHP", null));
// define an Hashtable to store
// attribute name(s) and value(s)
Hashtable htAttrs = new Hashtable();
htAttrs.Add("currency", "USD");
objElementLeveOne.AppendChild(MyElement(objXmlDocument, "price","24.95",htAttrs));
// clear the Hashtable and
// store new attribute name(s) and value(s)
htAttrs.Clear();
htAttrs.Add("reorder", "10");
htAttrs.Add("maximum", "200");
objElementLeveOne.AppendChild(MyElement(objXmlDocument,
"quantity","150",htAttrs));
// append first level to ROOT element
objRootElement.AppendChild(objElementLeveOne);
// append the entire hierarchy built above to XMLDocument object
objXmlDocument.AppendChild(objRootElement);
// save file
objXmlDocument.Save(strXmlFile);
} catch (XmlException e) {
output.Text = "An XML Exception occurred: " + e.Message;
} catch (Exception e) {
output.Text = "A General Exception occurred: " + e.Message;
} finally {
// close the XmlDocument object
if(objXmlDocument != null) {
objXmlDocument = null;
}
}
}
</script>
</head>
<body>
<asp:label id="output" runat="server" text="It's all done." />
</body>
</html>
Here's what the output looks like:
<?xml version="1.0" standalone="no"? >
<library>
<book bkid="MFRE001">
<title>XML and PHP</title>
<author>Vikram Vaswani</author>
<description>Learn to manage your XML data with PHP</description>
<price currency="USD">24.95</price>
<quantity maximum="200" reorder="10">150</quantity>
</book>
</library>
First, let me highlight the code that handles adding attributes to elements. The process is pretty straightforward via the SetAttribute() method of the XmlElement object. As seen below, this method takes two parameters: the name of the attribute and its value.
<%
// create first level element
XmlElement objElementLeveOne = objXmlDocument.CreateElement("book",null);
objElementLeveOne.SetAttribute("bkid","MFRE001");
%>
Things become more interesting when it comes to rewriting the custom MyElement() method to support this. Two important things to keep in mind here: attributes are optional, and it should be possible to add more than one attribute at a time to an element. This is where the Hashtable, an object belonging to the System.Collections library comes in handy, as its ability to store key-value pairs maps very well into my requirements here.
Take a look:
<%
// define an Hashtable to store
// the attribute name(s) and value(s)
Hashtable htAttrs = new Hashtable();
htAttrs.Add("currency", "USD");
objElementLeveOne.AppendChild(MyElement(objXmlDocument,
"price","24.95",htAttrs));
// clear the above Hashtable and
// store new attribute name(s) and value(s)
htAttrs.Clear();
htAttrs.Add("reorder", "10");
htAttrs.Add("maximum", "200");
objElementLeveOne.AppendChild(MyElement(objXmlDocument,
"quantity","150",htAttrs));
%>
Once the attribute-value pairs have been stored in a Hashtable, it's time to pull them out and append them to their respective elements. This calls for an update to the MyElement() function defined earlier:
<%
XmlElement MyElement(XmlDocument objXmlDocument, String strElementName, String strElementText, Hashtable htAttrs) {
XmlElement objElement = objXmlDocument.CreateElement(strElementName,null);
// check if the htAttrs Hashtable has been passed
if(htAttrs != null && htAttrs.Count != 0) {
// get an Enumerator to iterate through our Hashtable
IDictionaryEnumerator enumAttr = htAttrs.GetEnumerator();
while (enumAttr.MoveNext()) {
objElement.SetAttribute(enumAttr.Key.ToString(),enumAttr.Value.ToString());
}
}
objElement.AppendChild(objXmlDocument.CreateTextNode(strElementText));
return objElement;
}
%>
The first step is, obviously, to alter the function signature to support a fourth input parameter, the Hashtable containing the attributes and values. Once that's done, it's necessary to check if this Hashtable contains any items at all (remember, attributes are optional) via its Count property. If it does, the GetEnumerator() method can be used to create an IDictionaryEnumerator to iterate over the Hashtable.
Now, all that remain is the actual task of iterating over the Hashtable - this is possible using the MoveNext() method of the enumerator. You can easily retrieve each name-value pair using the Key and Value properties, convert the values to strings with the ToString() function, and set them with the SetAttribute() method.
Phew!
Next: Linking Out >>
More XML Articles
More By Harish Kamath (c) Melonfire