|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Announcements
Chapters
Services
Feature Zones
|
IntroductionAfter working with a couple of XML projects for the last six months, I am ready to share a class I wrote called Xml notationI believe it’s always easier to learn with actual examples, so to give you a brief tutorial about XML, I created the following "ZooTable". By the way, I have no idea about Zoos; it was the first thing that came to my mind when I decided to give an example:
There are two ways to represent this table, the first way which is the easier to read is by using "attributes". The second way to represent this table using XML is by using "elements". XmlDocument representation using attributes<?xml version="1.0" encoding="utf-8" ?>
<ZooRoot>
<ZooTable Name="Crazy Zoo" Address="32 Turtle Lane"
City="Austin" State="TX" Zip="12345" />
<ZooTable Name="Chicago Zoo" Address="23 Zebra Ave"
City="Chicago" State="IL" />
<ZooTable Name="Hungry Zoo" Address="45 Lion st"
City="Miami" State="FL" Zip="33122" />
</ZooRoot>
The field " Note: Each element is also called a node. When you create an XML document you always need a root element and then inside that element you can place any number of elements. In this case the root element is " I left the " If you have to create a child table of element " <?xml version="1.0" encoding="utf-8" ?>
<ZooRoot>
<ZooTable Name="Crazy Zoo" Address="32 Turtle Lane"
City="Austin" State="TX" Zip="12345">
<Classification Type="Reptiles" />
<Classification Type="Birds" />
<Classification Type="Primates" />
</ZooTable>
<ZooTable Name="Chicago Zoo" Address="23 Zebra Ave"
City="Chicago" State="IL" >
<Classification Type="Fish" />
<Classification Type="Mammals" />
<Classification Type="Primates" />
</ZooTable>
<ZooTable Name="Hungry Zoo" Address="45 Lion st"
City="Miami" State="FL" Zip="33122" >
<Classification Type="Arachnids" />
<Classification Type="Rodents" />
</ZooTable>
</ZooRoot>
Note that the notation of <ElementName attribute1="…" attribute2="…" />
to: <ElementName attribute1="…" attribute2="…" > </ElementName>
As you can see, it’s pretty simple to add child elements to the existing tables. XmlDocument representation using elementsWhen I started learning about XML, I noticed that the preferred notation by Visual Studio was by using "Elements", so I thought that this was the way we should always represent data; however, as I learned more about XML notation, I learned that if you are dealing mainly with table representations then you can use either elements or attributes to represent your XML data; therefore, I usually avoid representing data using elements because its notation uses more space and it is harder to read if you ever have to debug it. Keep in mind that although XML representation using attributes is more readable, it is less powerful because an attribute cannot contain child elements whereas elements can contain any number of child elements. The following representation is to show you the equivalent table using elements instead of attributes. For the rest of the examples I will use XML notation with attributes. <?xml version="1.0" encoding="utf-8" ?>
<ZooRoot>
<ZooTable>
<Name>Crazy Zoo</Name>
<Address>32 Turtle Lane</Address>
<City>Austin</City>
<State>TX</State>
<Zip>12345</Zip>
</ZooTable>
<ZooTable>
<Name>Chicago Zoo</Name>
<Address>23 Zebra Ave</Address>
<City>Chicago</City>
<State>IL</State>
</ZooTable>
<ZooTable>
<Name>Hungry Zoo</Name>
<Address>45 Lion st</Address>
<City>Miami</City>
<State>FL</State>
<Zip>33122</Zip>
</ZooTable>
</ZooRoot>
And the following XML representation shows you how to add the "Classification" child nodes using elements: <?xml version="1.0" encoding="utf-8" ?>
<ZooRoot>
<ZooTable>
<Name>Crazy Zoo</Name>
<Address>32 Turtle Lane</Address>
<City>Austin</City>
<State>TX</State>
<Zip>12345</Zip>
<Classification>
<Type>Reptiles</Type>
<Type>Birds</Type>
<Type>Primates</Type>
</Classification>
</ZooTable>
<ZooTable>
<Name>Chicago Zoo</Name>
<Address>23 Zebra Ave</Address>
<City>Chicago</City>
<State>IL</State>
<Classification>
<Type>Fish</Type>
<Type>Mammals</Type>
<Type>Primates</Type>
</Classification>
</ZooTable>
<ZooTable>
<Name>Hungry Zoo</Name>
<Address>45 Lion st</Address>
<City>Miami</City>
<State>FL</State>
<Zip>33122</Zip>
<Classification>
<Type>Arachnids</Type>
<Type>Rodents</Type>
</Classification>
</ZooTable>
</ZooRoot>
Using XmlHelper to create XmlDocuments from scratchNow I will show you how to use XmlDocument doc = XmlHelper.CreateXmlDocument();
All the new nodes that you add to your XmlNode newNode = doc.CreateElement("ZooRoot");
To add a child node use the " To add a child at the root of the XML document: XmlNode rootNode = doc.AppendChild(newNode);
The variable " ///
/// First Row
///
newNode = doc.CreateElement("ZooTable");
XmlHelper.CreateAttribute(newNode, "Name", "Crazy Zoo");
XmlHelper.CreateAttribute(newNode, "Address", "32 Turtle Lane");
XmlHelper.CreateAttribute(newNode, "City", "Austin");
XmlHelper.CreateAttribute(newNode, "State", "TX");
XmlHelper.CreateAttribute(newNode, "Zip", "12345");
rootNode.AppendChild(newNode);
///
/// Second Row
///
newNode = doc.CreateElement("ZooTable");
XmlHelper.CreateAttribute(newNode, "Name", "Chicago Zoo");
XmlHelper.CreateAttribute(newNode, "Address", "23 Zebra Ave");
XmlHelper.CreateAttribute(newNode, "City", "Chicago");
XmlHelper.CreateAttribute(newNode, "State", "IL");
rootNode.AppendChild(newNode);
///
/// Third Row
///
newNode = doc.CreateElement("ZooTable");
XmlHelper.CreateAttribute(newNode, "Name", "Hungry Zoo");
XmlHelper.CreateAttribute(newNode, "Address", "45 Lion st");
XmlHelper.CreateAttribute(newNode, "City", "Miami");
XmlHelper.CreateAttribute(newNode, "State", "FL");
XmlHelper.CreateAttribute(newNode, "Zip", "33122");
rootNode.AppendChild(newNode);
As you can see, the procedure is monotonous and simple, you just need to understand that when you add a new element you always use the " To add child nodes all we need is access to whoever the parent node is, so it is as simple as changing the line of code from: rootNode.AppendChild(newNode);
to: XmlNode zooTableNode = rootNode.AppendChild(newNode);
Now that you have access to the parent node you can create any number of child nodes, and the following lines show you how to add the child nodes needed for "Crazy Zoo": //Get a reference to the parent node
zooTableNode = rootNode.AppendChild(newNode);
// Add child nodes
XmlNode newChildNode = doc.CreateElement("Classification");
XmlHelper.CreateAttribute(newChildNode, "Type", "Reptiles");
zooTableNode.AppendChild(newChildNode);
newChildNode = doc.CreateElement("Classification");
XmlHelper.CreateAttribute(newChildNode, "Type", "Birds");
zooTableNode.AppendChild(newChildNode);
newChildNode = doc.CreateElement("Classification");
XmlHelper.CreateAttribute(newChildNode, "Type", "Primates");
zooTableNode.AppendChild(newChildNode);
As you can see the process is repetitive and simple. But what if the Before I can show you the answer, first I need to give you a brief tutorial of XPath queries. XPath queriesXML Path Language (XPath) is a general purpose query notation that can be used to filter elements and attributes of Single node selectionFor example, if we want to access the second row of " string xpathQuery = "/ZooRoot/ZooTable[@Name='Chicago Zoo']";
XmlNode selectedNode = doc.SelectSingleNode(xpathQuery);
There is a slight difference in the notation to access elements vs. the notation to access attributes. Following is the equivalent notation when you are dealing with a XML document that uses elements instead of attributes: string xpathQuery = "/ZooRoot/ZooTable/Name='Chicago Zoo'";
XmlNode selectedNode = doc.SelectSingleNode(xpathQuery);
So the only difference is that to access attributes you use brackets and the "@" sign. You can also create filters that match multiple fields for example: string xpathQuery =
"/ZooRoot/ZooTable/Name='Chicago Zoo' and @City=’Chicago’";
XmlNode selectedNode = doc.SelectSingleNode(xpathQuery);
This query is just for illustration purposes because it will return the same node. I just wanted to show you how to apply filters from multiple attributes. In the examples above I used For example: XmlNode anotherSelectedNode =
selectedNode.SelectSingleNode("Classification[@Type=’Reptiles’]";);
Multiple node selectionTo select multiple nodes you use the Following is an example: string xpathQuery =
"/ZooRoot/ZooTable/[@Name='Chicago Zoo']/Classification";
XmlNodeList nodeList = doc.SelectNodes(xpathQuery);
The example above shows how to select all the child nodes whose elements are named ‘ The following example shows you how to access all child nodes of a node whose attribute name is ‘Chicago Zoo’: string xpathQuery =
"/ZooRoot/ZooTable/[@Name='Chicago Zoo']/child::*";
XmlNodeList nodeList = doc.SelectNodes(xpathQuery);
Another way to access the child nodes of an element is by using the property Insert nodes to existing nodes of an XmlDocumentNow that you are more familiar with XPath queries, I will show you how to programmatically insert the " string xpathQuery = "/ZooRoot/ZooTable";
XmlNodeList nodeList = doc.SelectNodes(xpathQuery);
Next, you can use a int index = 0;
foreach (XmlNode nodeFromList in nodeList)
{
///
/// each 'nodeFromList' is going to
/// be the parent node to which
/// we need to add the 'Classification' child nodes
///
foreach (string classificationName in classificationData[index])
{
newNode = doc.CreateElement("Classification");
XmlHelper.CreateAttribute(newNode, "Type",
classificationName);
nodeFromList.AppendChild(newNode);
}
index++;
}
How to modify attribute values of existing nodesYou can use the method The following example shows how to modify all the classification nodes from ‘Primates’ to ‘Monkeys’: XmlNodeList nodeList = doc.SelectNodes(
"/ZooRoot/ZooTable/Classification[@Type='Primates']");
foreach (XmlNode node in nodeList)
{
XmlHelper.SetAttributeValue(node, "Type", "Monkeys");
}
Inserting nodes with children into existing nodesOccasionally, you will have some nodes that you want to copy from an existing location to another. In this example we want to add the "New York Zoo" which has the same "Classification" of animals as the "Chicago Zoo": ///
/// Get Access to the node that we need to copy
///
XmlNode nodeToCopy = doc.SelectSingleNode(
"/ZooRoot/ZooTable[@Name='Chicago Zoo']");
///
/// Copy the node
///
//true means that child nodes will be copied as well
XmlNode newNode = doc.ImportNode(nodeToCopy, true);
///
/// Change the attributes that are different
///
XmlHelper.SetAttributeValue(newNode, "Name", "New York Zoo");
XmlHelper.SetAttributeValue(newNode, "Address",
"235 Congestion Ave");
XmlHelper.SetAttributeValue(newNode, "City", "New York");
XmlHelper.SetAttributeValue(newNode, "State", "NY");
XmlHelper.SetAttributeValue(newNode, "Zip", "44444");
///
/// Add child node. Note that the new node
/// shares the same parent as the node
/// we are copying from, so we might as well
/// access the parent node from the node
/// that we are copying from.
///
nodeToCopy.ParentNode.AppendChild(newNode);
///
/// Create a new node and set its attributes
///
XmlNode newNode = doc.CreateElement("ZooTable");
XmlHelper.CreateAttribute(newNode, "Name", "New York Zoo");
XmlHelper.CreateAttribute(newNode, "Address",
"235 Congestion Ave");
XmlHelper.CreateAttribute(newNode, "City", "New York");
XmlHelper.CreateAttribute(newNode, "State", "NY");
XmlHelper.CreateAttribute(newNode, "Zip", "44444");
/// Get Access to the node that we need to copy
///
XmlNode nodeToCopy = doc.SelectSingleNode(
"/ZooRoot/ZooTable[@Name='Chicago Zoo']");
///
/// Copy all the attributes of the child nodes
///
foreach (XmlNode childNode in nodeToCopy.ChildNodes)
{
XmlNode newChildNode = doc.CreateElement("Classification");
XmlHelper.CreateAttribute(newChildNode, "Type", "");
XmlHelper.CopyAttribute(childNode, newChildNode, "Type");
newNode.AppendChild(newChildNode);
}
///
/// Add child node. Note that the new node
/// shares the same parent as the node
/// we are copying from, so we might as well
/// access the parent node from the node
/// that we are copying from.
///
nodeToCopy.ParentNode.AppendChild(newNode);
Using XmlHelper to get DataSources
To convert a XmlHelper.GetDataTable( XmlNodeList nodelist )
To convert a XmlHelper.GetDataTable( XmlNodeList nodelist,
string primaryKeyColumn, bool autoIncrement)
To update XML nodes from a XmlHelper.UpdateChildNodesWithDataTable(XmlNode parentNode,
DataTable table, string keyField)
To copy the elements of a XmlHelper.CopyAttributes(DataRow fromRow, XmlNode toNode)
To get an array that represents a column whose name corresponds to an attribute: XmlHelper.GetAttributeArray(XmlNodeList nodeList, string attributeName)
The following example illustrates how to fill a XmlNodeList nodeList = doc.SelectNodes("/ZooRoot/ZooTable");
this.lstZoos.DataSource =
XmlHelper.GetAttributeArray(nodeList, "Name");
The following example illustrates how to fill a DataGrid with the data from XmlNodeList nodeList = doc.SelectNodes("/ZooRoot/ZooTable");
this.grdZoos.DataSource = XmlHelper.GetDataTable(nodeList);
The following example shows you how you can update an existing ///
/// Get access to the DataTable that was modified in DataGrid
///
DataTable table = (DataTable)this.grdZoos.DataSource;
///
/// Get access to the parent node whose child are
/// part of the datatable
///
XmlNode parentNode = doc.SelectSingleNode("/ZooRoot");
///
/// Update the XmlDocument with changes made on DataGrid
///
XmlHelper.UpdateChildNodesWithDataTable(parentNode,
table, "Name");
Importing nodes from other XmlDocumentsAs a quick note I want to show you how you can import nodes from another In this example I will create an ///
/// Create a master XmlDocument that will organize data by Country
///
XmlDocument docMaster = XmlHelper.CreateXmlDocument();
XmlNode newNode = docMaster.CreateElement("root");
XmlNode rootNode = docMaster.AppendChild(newNode);
newNode = docMaster.CreateElement("Country");
XmlHelper.CreateAttribute(newNode, "Name", "USA");
XmlNode usaRoot = rootNode.AppendChild(newNode);
///
/// Select the nodes to be imported
///
XmlNodeList nodeList = doc.SelectNodes("/ZooRoot/ZooTable");
///
/// Import nodes
///
foreach (XmlNode sourceNode in nodeList)
{
newNode = docMaster.ImportNode(sourceNode, true);
usaRoot.AppendChild(newNode);
}
this.txtQueryResults.Text = XmlHelper.DocumentToString(docMaster);
Debugging your code with XmlHelper
Example: Trace.WriteLine(XmlHelper.NodeToString(currentNode))
Using Insert, Update, Delete and Query methodsThe first release of InsertThis method has several overloads to simplify your work. First of all, note that all methods require an Following is a list of the overloads and their functionality: Creates a node at the bottom of the hierarchy, creating the tree as required: XmlHelper.Insert(XmlDocument doc, string xpath)
Same as above but adds the fields (or attributes) with their corresponding values for each attribute: XmlHelper.Insert(XmlDocument doc, string xpath,
string[] fields, string[] values)
Same as above but uses XmlHelper.Insert(XmlDocument doc, string xpath,
NameValueCollection nameValuePairs)
Creates node at the bottom of the hierarchy and creates the attributes based on the column names from the XmlHelper.Insert(XmlDocument doc, string xpath, DataRow rowValues)
Same as above but inserts an entire XmlHelper.Insert(XmlDocument doc, string xpath, DataTable table)
The method below is analogous to inserting a column of data for the specified field at the end of the tree hierarchy: XmlHelper.Insert(XmlDocument doc, string xpath, string field, string[] values)
The following example shows a simplified version of how easily we can create the " ///
/// Create the XmlDocument and specify name of the root node
///
doc = XmlHelper.CreateXmlDocument("ZooRoot");
///
/// First Row
///
string[] fields = new string[]
{"Name", "Address", "City", "State", "Zip"};
string[] values = new string[]
{"Crazy Zoo", "32 Turtle Lane", "Austin", "TX", "12345"};
XmlHelper.Insert(doc, "ZooTable", fields, values);
///
/// Second Row (Zip is missing)
///
string[] fields2 = new string[]
{"Name", "Address", "City", "State"};
values = new string[]
{"Chicago Zoo", "23 Zebra Ave", "Chicago", "IL"};
XmlHelper.Insert(doc, "ZooTable", fields2, values);
///
/// Third Row
///
values = new string[]
{"Hungry Zoo", "45 Lion st", "Miami", "FL", "33122"};
XmlHelper.Insert(doc, "ZooTable", fields, values);
Now let’s add the Classification nodes for each of the ///
/// Insert Classification Data
///
values = new string[]{"Reptiles", "Birds", "Primates"};
XmlHelper.Insert(doc,
"ZooTable[@Name='Crazy Zoo']/Classification", "Type", values);
values = new string[] {"Fish", "Mammals", "Primates"};
XmlHelper.Insert(doc,
"ZooTable[@Name='Chicago Zoo']/Classification", "Type", values);
values = new string[] {"Arachnids", "Rodents"};
XmlHelper.Insert(doc,
"ZooTable[@Name='Hungry Zoo']/Classification", "Type", values);
The example above should give you a pretty good idea of how easily you can create any type of hierarchy for your application. UpdateIn a previous example I showed you how to modify all the Classification nodes from ‘Primates’ to ‘Monkeys’. Now we will do the same but using the XmlHelper.Update(doc,
"ZooTable/Classification[@Type='Primates']", "Type", "Monkeys");
DeleteFollowing are the overloaded methods available for Delete all records on the specified path: XmlHelper.Delete(XmlDocument doc, string xpath)
Delete a field (or attribute) from all records on the specified path: XmlHelper.Delete(XmlDocument doc, string xpath, string field)
QueryFollowing are the overloaded methods available for Returns a XmlHelper.Query(XmlDocument doc, string xpath)
Return a single string representing the value of the specified field for the first record encountered: XmlHelper.QueryScalar(XmlDocument doc, string xpath, string field)
Returns a string array for the specified field for all rows on the path (analogous to getting a column of data): XmlHelper.QueryField(XmlDocument doc, string xpath, string field)
ConclusionThe ReferencesFor full reference of XML I recommend the book named "Applied XML Programming for .NET" by Dino Esposito. This has been an excellent source to learn XML programming using .NET. For reference mainly on XML, I recommend the book named "XML Pocket Consultant" by William R. Stanek. For reference on the Revision history
| |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||