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

Published Wednesday, November 24, 2010 10:24 PM by hajan
Filed under: , ,

Comments

# Case-insensitive search using XPath query in ASP.NET - Hajan's Blog

Pingback from  Case-insensitive search using XPath query in ASP.NET - Hajan's Blog

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

Wednesday, November 24, 2010 6:18 PM by Ali Khalid

What about just using "fn:lower-case(string)" www.w3schools.com/.../xpath_functions.asp

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

Wednesday, November 24, 2010 6:55 PM by hajan

@Ali Khalid, thats nice question, thanks.

Well the implementation with this function should be something like this:

string query = "/root/people/person/*[lower-case(local-name())='name']";

XmlNamespaceManager namespaceManager = new XmlNamespaceManager(doc.NameTable);

namespaceManager.AddNamespace("fn", "www.w3.org/.../xpath-functions");

XmlNodeList nodes = doc.SelectNodes(query, namespaceManager);

foreach (XmlNode node in nodes)

{

   Response.Write(node.InnerText + "<br />");

}

But this won't work since as I know, its part of XPath 2.0 which is not really supported in .NET. Check the following Mvp.Xml library - http://mvpxml.codeplex.com/, which may help in this (I haven't tried it yet).

Otherwise, you can't just do fn:lower-case(string) since first - fn is not defined as a xml namespace prefix and, second - it will make string lower-case like this /root/people/person/Name[lower-case(.)] - but we have different letter sizes in each name, this will make the found Name to name. So, thats why we have to use the function from my post to make this work.

Regards,

Hajan

# Dew Drop &ndash; November 24, 2010 | Alvin Ashcraft&#039;s Morning Dew

Wednesday, November 24, 2010 8:09 PM by Dew Drop – November 24, 2010 | Alvin Ashcraft's Morning Dew

Pingback from  Dew Drop &ndash; November 24, 2010 | Alvin Ashcraft&#039;s Morning Dew

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

Wednesday, October 05, 2011 9:33 AM by Miles

How about writing the found string back to the file again?  How difficult is that?

Leave a Comment

(required) 
(required) 
(optional)
(required)