Case-insensitive XPath query search on XML Document in ASP.NET

Sometimes we need to read XML files that are manually written by users and find some elements in the XML tree. Using .NET library, we can easily navigate throughout the whole XML file since the library has excellent support for working with XML files. One of the challenges you may come across is when you want to search for specific node in the XML file, but you are not sure about the letter case (lower, upper or even mixed) of the XML elements.

Lets say we have the following XML file

<?xml version="1.0" encoding="utf-8" ?>
<root>
    <people>
        <person>
            <name>Sylvester</name>
            <surname>Stallone</surname>
        </person>
        <person>
            <name>Tom</name>
            <surname>Cruise</surname>
        </person>
        <person>
            <name>James</name>
            <surname>Bond</surname>
        </person>
    </people>
</root>

So, we want to read all the names and write in our ASP.NET web application or any .NET project.

The XPath seems easy, we can construct it on the following way

xpath = “root/people/person/name” – this will go only to the specified path. This is not equal to "root/people/person/Name" since it's case sensitive.

or “//name” – this will find all name elements, so if we would have name on a different level of the XML tree or simply not as a child of people/person, it will be matched element too.

Ok, this is quite well-known thing. So, the implementation in ASP.NET is like this:

 

XmlDocument doc = new XmlDocument();
try
{
    doc.Load(Server.MapPath("/XML/people.xml"));
    string query = "root/people/person/name";

    XmlNodeList nodes = doc.SelectNodes(query);
    foreach (XmlNode node in nodes)
    {
        Response.Write(node.InnerText + "<br />");
    }
}
catch (XmlException ex)
{
    //throw new XmlException
}
catch (FileNotFoundException ex)
{
    //throw new FileNotFoundException
}

and the result on the page is

Sylvester
Tom
James

Ok. Now, what if the user writes the XML file on the following way:

<?xml version="1.0" encoding="utf-8" ?>
<root>
    <people>
        <person>
            <NAME>Sylvester</NAME>
            <surname>Stallone</surname>
        </person>
        <person>
            <Name>Tom</Name>
            <surname>Cruise</surname>
        </person>
        <person>
            <NaME>James</NaME>
            <surname>Bond</surname>
        </person>
    </people>
</root>

Oh… the names are not in same letter case. The first is in UPPERCASE, the second is in FirstUpper rest lowercase, and the third is in mixed letter case. Now what? Are we going to handle each case and will create XPath query dynamically? Well, you can do that, but that’s much longer way than the following one:

Xpath = "root/people/person/*[translate(local-name(), 'ABCDEFGHIJKLMNOPQRSTUVWXYZ','abcdefghijklmnopqrstuvwxyz')='name']";

What is translate?


fn:translate(string1,string2,string3)
Converts string1 by replacing the characters in string2 with the characters in string3

Example: translate('12:30','30','45')
Result: '12:45'

Example: translate('12:30','03','54')
Result: '12:45'

Example: translate('12:30','0123','abcd')
Result: 'bc:da'

from http://www.w3schools.com/Xpath/xpath_functions.asp


Ahaaam. We have three parameters

#1 local-name() – we get the current local node from the XML file

#2 A-Z – from A to Z UPPERCASE

#3 a-z – from a to z lowercase

For example when we get the NAME node (#1), replacing each UPPERCASE character (#2) (all four characters) with the LOWECASE characters (#3) – so the result will be name which is equal (=) with ‘name’.

So, this will provide total CASE INSENSITIVE search and we will not worry at all since we can “catch” all the elements no matter of the letter case (of course XML file has to be valid first :) ).

The complete code now is

XmlDocument doc = new XmlDocument();
try
{
    doc.Load(Server.MapPath("/XML/people.xml"));
    string query = "root/people/person/*[translate(local-name(),"+
        "'ABCDEFGHIJKLMNOPQRSTUVWXYZ','abcdefghijklmnopqrstuvwxyz')='name']";

    XmlNodeList nodes = doc.SelectNodes(query);
    foreach (XmlNode node in nodes)
    {
        Response.Write(node.InnerText + "<br />");
    }
}
catch (XmlException ex)
{
    //throw new XmlException
}
catch (FileNotFoundException ex)
{
    //throw new FileNotFoundException
}

Hope you like it.

Regards,
Hajan

1 Comment

Comments have been disabled for this content.