VSP
VSP

Reputation: 2393

SelectNodes with XPath ignoring cases in node names

I have a problem similar to the question SelectNodes with XPath ignoring cases but in my case the uppercase/lowercase problem is in the node with the name 'application' (Sometimes is 'Application' other times 'application').

How would i apply the solution of the other post? or a different one applies in this case?

xml:

<?xml version="1.0" encoding="utf-16" ?>
<application>
  <forms>
    <action type="update">
      <form uid="" >
      </form>
    </action>
  </forms>
</application>

In C# 3.5:

XmlNode nodex= oXMLDoc1.SelectSingleNode("Application/forms/action/form/@uid")
nodex.Value="UniqueIDx";//nodex is null :S

Upvotes: 4

Views: 23165

Answers (5)

Nico
Nico

Reputation: 322

I found the easiest approach was to load the XML file as all lowercase and then just make sure that any subsequent XPath expressions were all lower-case.

Example:

var xmlDoc = new System.Xml.XmlDocument();
var rawFile = System.IO.File.ReadAllText(@"\Path\To\File.xml");
xmlDoc.LoadXml(rawFile.ToLower());

XmlNode node = xmlDoc.SelectSingleNode("//some/path[@attribute1='somevalue' and @attribute2='anothervalue']");

Upvotes: 0

mykhailovskyi
mykhailovskyi

Reputation: 680

We may convert xml and our variables to lower case.

string value = "aBc";
XmlNode xmlnode = xmldoc.SelectSingleNode(string.Format("/some/path/add[translate(@key, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz') = '{0}']", value.ToLower()));

Upvotes: 6

Martin Honnen
Martin Honnen

Reputation: 167716

If the root element is the only element where the case of letters can change then you should simply do e.g.

XmlDocument doc = new XmlDocument();
doc.Load("input.xml");
XmlNode nodex= oXMLDoc1.DocumentElement.SelectSingleNode("forms/action/form/@uid");

as already suggested in a comment.

With XDocument you would do e.g.

XDocument doc = XDocument.Load("input.xml");
doc.Root.Element("forms").Element("action").Element("form").SetAttributeValue("uid", "UniqueIDx");

[edit] A comment claims the first example path throws an exception, here is a complete sample that does not throw an exception for me and uses the same path a posted before:

            string xml = @"<application>
  <forms>
    <action type=""update"">
      <form uid="""" >
      </form>
    </action>
  </forms>
</application>";
            XmlDocument doc = new XmlDocument();
            doc.LoadXml(xml);
            XmlNode nodex = doc.DocumentElement.SelectSingleNode("forms/action/form/@uid");
            nodex.Value = "UniqueIDx";

            doc.Save(Console.Out);

Upvotes: 1

Dimitre Novatchev
Dimitre Novatchev

Reputation: 243569

Just use:

*[translate(name(), 'APPLICATION', 'application')='application']
     /forms/action/form/@uid

This selects the wanted attribute correctly in all cases when the current (initial context) node has a child with name, that is any capitalization of the string "application".

XSLT - based verification:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output method="text"/>

 <xsl:template match="/">
     <xsl:value-of select=
      "*[translate(name(), 'APPLICATION', 'application')='application']
          /forms/action/form/@uid"/>
 </xsl:template>
</xsl:stylesheet>

When this transformation is applied on the following XML document:

<aPPliCatioN>
 <forms>
   <action>
    <form uid="xyz"/>
   </action>
 </forms>
</aPPliCatioN>

the wanted node is selected and its string value is copied to the output:

xyz

Explanation:

Proper use of the standard XPath functions name() and translate().

Upvotes: 5

Gertjan Assies
Gertjan Assies

Reputation: 1900

First of all I want to mention that xml is case sensitive, so Application means something else then application, looks to me this should be fixed in the code that generates this xml but if you have no control over that maybe try something like this as your xpath:

"Application/forms/action/form/@uid | application/forms/action/form/@uid"

The | operator will combine the node-sets that are returned from both xpath's in this case it will be one or the other

Upvotes: 2

Related Questions