xml


One of my friends asked me how to sort a xml file which is deserialized and put into a treeview.
The xml lookes something like the one shown below:

  <?xml version=”1.0″ encoding=”us-ascii” ?>
– <TreeView>
– <node text=”Topics”>
  <node text=”Animal Health” /> 
– <node text=”Tools”>
– <node text=”Corporate”>
   <node text=”knowledge management” />
   <node text=”Media relations” />
   <node text=”Agency management” />
   <node text=”Messaging” />
   <node text=”Communications planning” />
   <node text=”Newsflow” />
  </node>
  </node>
  </node>
  </node>
  </TreeView>

As you can see the xml dosen’t look sorted, So in order to sort it alphabetically, xsl may be the
easiest route. Here’s the transform to sort alphabetically:

<?xml version=”1.0″ encoding=”us-ascii” ?>
<xsl:stylesheet version=”1.0″ xmlns:xsl=”http://www.w3.org/1999/XSL/Transform” xmlns:fo=”http://www.w3.org/1999/XSL/Format“>
<xsl:template match=”node”>
            <xsl:copy>
                  <xsl:copy-of select=”@*”/>
<xsl:apply-templates select=”node”>
      <xsl:sort select=”@text”/>
</xsl:apply-templates>
 </xsl:copy>
      </xsl:template>
</xsl:stylesheet>

Now, we can use XSL Transform to Transform the XML data using the loaded XSLT stylesheet. See the Code Below

string strSortFile = @”C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\TEMPLATE\LAYOUTS\sort.xsl”;
string filename = @”C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\TEMPLATE\LAYOUTS\BizFocus.xml”;
XmlDocument doc = new XmlDocument();
doc.Load(fileName);
MemoryStream sstream = new MemoryStream();
// Modify the XML file.
XmlElement root = doc.DocumentElement;
// Create an XPathNavigator to use for the transform.
XPathNavigator nav = root.CreateNavigator();
// Transform the file.
System.Xml.Xsl.XslTransform xtr = new System.Xml.Xsl.XslTransform();
xtr.Load(strSortFile);
//XmlTextWriter writer = new XmlTextWriter(fileName, null);
XmlTextWriter writer1 = new XmlTextWriter(sstream, null);
xtr.Transform(nav, null, writer1, null);
XmlTextReader reader = null;
sstream.Position = 0;

/*Insert Logic to add node to treeview from XMLTextReader*/
You might get the error ‘Root element is Missing’, but do not worry, it isn’t a problem with the input file or the transform script. The problem is that the XslTransform.Transform function leaves the stream position set to the end of the stream. There’s no root element because the XmlDocument.Load function thinks the stream has a 0 byte length. The fix is to simply set the position to 0.

Suppose we have a xml document, now we need to search for an item in it.
We can do this using SelectSingleNode method which is used to locate an element. The SelectSingle-Node method requires an XPath query to be passed into the method. See the sample xml document below,

<?xml version=”1.0″ encoding=”us-ascii” ?>
<TreeView>
<node text=”Topics”>
<node text=”Corporate”>
<node text=”Best Places to Work”>
<node text=”Health Fairs” />
</node>
<node text=”Pharma”>
<node text=”General Medicines”>
<node text=”Arthritis “>
<node text=”Osteoporosis” />
<node text=”Oral calcitonin” />
</node>
</node>
</TreeView>

So, if I want to find an item ‘Arthritis’ in the xml document, I have to do this,

string BzFocusxmlpath = @”C:\Program Files\ BizFocus.xml”;

 

string strParentVal = “”;       

XmlDocument xmlDoc = new XmlDocument();

xmlDoc.Load(BzFocusxmlpath);

XmlNode node;

node = xmlDoc.SelectSingleNode(“//node[@text=‘Arthritis’]”);

string snode = node.OuterXml;

 

Now, snode will return a value <node text=\”Arthritis”><node text=\”Osteoporosis\” /><node text=\”Oral calcitonin\” /></node>
which is the value of all nodes under General medicines, so, how do we extract only “Arthritis”?
Here, some C# coding will help,

int intindex = snode.IndexOf(“>”);

string strsubstr = snode.Substring(0, intindex); //will return “<node text=\”Arthritis “”

string[] strstarray = strsubstr.Split(‘=’);

string strStoreBizVal = strstarray[1].ToString(); // will give “\”Arthritis 

string strStoreBizValParent = “”;

// For removing “\” and “/” characters from string

strStoreBizVal = strStoreBizVal.Replace(“\””, “”);

strStoreBizVal = strStoreBizVal.Trim();

if (strStoreBizVal.Contains(“/”))

{

    strStoreBizVal = strStoreBizVal.Replace(“/”, “”);

    strStoreBizVal = strStoreBizVal.Trim();

}

So, our strStoreBizVal now  contains, ‘Arthritis’.

 

Now, suppose we want the hierarchy of the item in the xml file, like,

‘Arthritis’ is under parent node ‘General Medicine’, ‘General Medicine’ is under ‘Pharma’ and that is under ‘Topics’.

So, what if we want to display the whole hierarchy as,

Topics|Pharma|General Medicines|Arthritis” ?

For this, we need to traverse the xml document to get the hierarchy of parent and child, we can do this using simple recursive C# code, refer to the above xml code where the top most node is <TreeView> so, we traverse the Parent nodes till we reach there, see below

while (node.ParentNode.OuterXml.StartsWith(“<TreeView>”) == false)

{

    strParentVal = node.ParentNode.OuterXml;

    int intindexParent = strParentVal.IndexOf(“>”);

    string strsubstrParent = strParentVal.Substring(0, intindexParent);

    string[] strstarrayParent = strsubstrParent.Split(‘=’);

    strStoreBizValParent = strstarrayParent[1].ToString();

    strStoreBizValParent = strStoreBizValParent.Replace(“\””, “”);

    strStoreBizValParent = strStoreBizValParent.Trim();

    if (strStoreBizValParent.Contains(“/”))

    {

strStoreBizValParent = strStoreBizValParent.Replace(“/”, “”);

strStoreBizValParent = strStoreBizValParent.Trim();

    }

    strStoreBizVal += “|” + strStoreBizValParent;

    node = node.ParentNode;

}

string strFinalBizVal = strStoreBizVal;

 

// Now we get “Arthritis|General Medicines|Pharma|Topics“, since we are traversing from below so the top most node appears last, so we have to reverse the string to get “Topics|Pharma|General Medicines|Arthritis

 

string strReverseBizVal = “”;

string[] strReverseBizValArr = strFinalBizVal.Split(‘|’);

for (int j = strReverseBizValArr.Length -1; j >= 0; j–)

{

    strReverseBizVal += strReverseBizValArr[j].ToString() + “|”;

}

strReverseBizVal = strReverseBizVal.Remove(strReverseBizVal.LastIndexOf(‘|’));

 

This will give me, “Topics|Pharma|General Medicines|Arthritis”