In this HOWTO I will explain how to generate XPath expressions using a simple XML Document, a custom object collection and a few foreach loops. The end result is a list of XPath expressions that map to each node of the specified XML Document. This can be very useful for XML that is large or XML you are not familiar with but is does begin to fall apart when you get into very complext XML.
Custom Collection Object
Create 2 new Classes:
XNode.cs will hold the XML Node Name, the XPath exp and a collection of ChildNodes (XNodes)
XNodes.cs is the collection of XNode's
XNode.cs
-
using System;
-
-
public class XNode
-
{
-
public string name;
-
public string xpath;
-
-
public XNode(string name, string xpath)
-
{
-
this.name = name;
-
this.xpath = xpath;
-
}
-
-
public XNode(string name, string xpath,XNodes xnodes)
-
{
-
this.name = name;
-
this.xpath = xpath;
-
this.xnodes = xnodes;
-
}
XNodes.cs
This is the short version of this class which is missing the find and remove methods.
-
using System;
-
using System.Collections;
-
-
public class XNodes: System.Collections.CollectionBase
-
{
-
-
public XNode Add(string name,string xpath)
-
{
-
-
this.InnerList.Add(xnode);
-
return xnode;
-
}
-
-
public XNode Add(string name,string xpath,XNodes xnodes)
-
{
-
this.InnerList.Add(xnode);
-
return xnode;
-
}
-
}
WebForm and Code-behind
the web form is where the action will take place. To get started create 2 text boxes and a button.
- TextBox1 will hold the XML
- TextBox2 will hole the XPath results
- Button1
In the code-behind of the default.aspx.cs page you will add 3 methods:
BuildXPath which will generate the XPath exp's and add them to the XNode collection.
ReadXNode which will place the XPath exp's from the XNode collection in a textbox.
button_click which does the following:
- get the XML from TextBox1 and bind it to an XMLDocument
- create the first (Parent) XNode object
- loop over each XmlNode in the XmlDocument
- loop over each XNode in the Parent XNode
BuildXPath takes 3 parameters:
XNode xParent - The Parent XNode that we will be adding XNodes to
XmlNode xnode - the current XML Node we are getting information about
string xpath - the current value of the XPath exp
We will invoke this method from the button click event.
-
foreach(XmlNode xnode in xDoc.DocumentElement)
-
{
-
BuildXPath(objXNode,xnode,"//");
-
}
-
private void BuildXPath(XNode xParent, XmlNode xnode,string xpath)
-
{
This methods works by getting the Name value from the xnode and adds that to the xpath string. Then it creates a NEW XNode using the xnode.Name and the xpath value and then trims off any trailing "/'s".
-
xpath +=xnode.Name+"/";
-
newnode.xpath = xpath.Remove(xpath.Length-1,1);
At this point we have our first child node defined so we'll add it to the XNode collection.
-
xParent.xnodes.Add(newnode);
Now we need to check to see if the current XmlNode has any attributes, check to see the count of attributes and finnally process accordingly.
-
if(xnode.Attributes!=null)
-
{
-
if(xnode.Attributes.Count != 0)
-
{
If there are any attributes then we'll loop over them and extract the XPath exp using the attribute name and value. We start by first creating a new XNode using the current XmlNode name but an empty Xpath exp, and tempXpath strinag and a foreach xnode attributes.
-
string tempXpath = string.Empty;
-
foreach(XmlAttribute att in xnode.Attributes)
-
{
When we step into the foreach we are getting the attribute Name and Value and placing them in a string with the extra charcters need for Xpath.
-
foreach(XmlAttribute att in xnode.Attributes)
-
{
-
tempXpath += "@"+att.Name+"='"+att.Value+"' and ";
-
}
As you can see we are uings the "+=" oprator to append the tempXpath string to its' self and we are adding the "@" decleration to indicate to XPath that this is an attribute as well as adding the string " and " to the end.
Once we reach the end of the loop we will add out XPath exp to the current XNodes' xpath property. You'll notice that we are first removing the last charter from the parent XPath, adding our newly created XPath and then removing the trailing " and " string.
The we add this XNode to its' currnt parent XNode.xnode collection.
-
anode.xpath = xpath.Remove(xpath.Length-1,1)+"["+tempXpath.Remove(tempXpath.Length-4,4).TrimEnd()+"]";
-
newnode.xnodes.Add(anode);
Once this processess is complete we need to check to see if the current XML Node has any child nodes. We do this by doing another foreach loop over the current XmlNode and then use the conditional HasChildren. If it does have any child nodes we step into the BuildXPath method and start processing nodes.
-
foreach(XmlNode newxnode in xnode)
-
{
-
if(newxnode.HasChildNodes)
-
{
-
BuildXPath(xParent,newxnode,xpath);
-
}
-
}
Once the BuildXPath method has completed we will have a collection XNode objects in single XNode object. To extract the XPath exp's and display them in a text box we'll use a second method ReadXNode.
ReadXNode functions similar to the BuildXPath method but it takes a single XNode parameter. Thie method is also invoked from the button click event but not until after the BuildXPath method has completed. It works by looping over each XNode in the Parent XNode XNodes collection.
-
foreach(XNode xobjNode in objXNode.xnodes)
-
{
-
ReadXNode(xobjNode);
-
}
As you can see below this method is very short.
-
private void ReadXNode(XNode xParent)
-
{
-
foreach(XNode xobjNode in xParent.xnodes)
-
{
-
this.TextBox2.Text += xobjNode.xpath + System.Environment.NewLine;
-
if(xobjNode.xnodes.Count> 0)
-
{
-
ReadXNode(xobjNode);
-
}
-
}
-
}
Once inside the ReadXNode it starts off by doing a foreach loop over the current XNodes xNode collection.
Then foreach XNode it gets the xpath property value and adds it into the textbox. It then checks to see if the child node has a a populated XNode collection and if it does it steps back into the ReadXNode method using the current child node as the new Parent to inspect.
The end result is the XPath TextBox will have an XPath expression for each node that was added to the XNode collection.
Download the Source Code Here
How can i write above code in Java
Thanks for your howto.
I just write function, inspired by howto, doing similar work:
private IEnumerable BuildLazyXPath(string parentXpath, XmlNode parentNode)
{
foreach (XmlNode childXmlNode in parentNode)
{
string childXpath = parentXpath + "/" + childXmlNode.Name;
yield return childXpath;
if (childXmlNode.Attributes != null && childXmlNode.Attributes.Count > 0)
{
foreach (XmlAttribute attr in childXmlNode.Attributes)
{
yield return parentXpath + "/" + childXmlNode.Name + "[@" + attr.Name + "]";
}
}
foreach (string childXpaths in BuildLazyXPath(childXpath, childXmlNode))
{
yield return childXpaths;
}
}
}
call:
using (Stream xmlStream = File.OpenRead(@"c:\my.xml"))
{
XmlReader reader = XmlReader.Create(xmlStream);
XmlDocument xDoc = new XmlDocument();
xDoc.Load(reader);
foreach (string xpath in BuildLazyXPath("/" + xDoc.DocumentElement.Name, xDoc.DocumentElement))
{
// ...
}
}
I have no clue. I don't know Java.