Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get xpath from an XmlNode instance

Could someone supply some code that would get the xpath of a System.Xml.XmlNode instance?

Thanks!

like image 660
joe Avatar asked Oct 27 '08 20:10

joe


People also ask

Can the Dom help you find specific elements in an XML file?

The XML Document Object Model (DOM) contains methods that allow you to use XML Path Language (XPath) navigation to query information in the DOM. You can use XPath to find a single, specific node or to find all nodes that match some criteria.


1 Answers

Okay, I couldn't resist having a go at it. It'll only work for attributes and elements, but hey... what can you expect in 15 minutes :) Likewise there may very well be a cleaner way of doing it.

It is superfluous to include the index on every element (particularly the root one!) but it's easier than trying to work out whether there's any ambiguity otherwise.

using System; using System.Text; using System.Xml;  class Test {     static void Main()     {         string xml = @" <root>   <foo />   <foo>      <bar attr='value'/>      <bar other='va' />   </foo>   <foo><bar /></foo> </root>";         XmlDocument doc = new XmlDocument();         doc.LoadXml(xml);         XmlNode node = doc.SelectSingleNode("//@attr");         Console.WriteLine(FindXPath(node));         Console.WriteLine(doc.SelectSingleNode(FindXPath(node)) == node);     }      static string FindXPath(XmlNode node)     {         StringBuilder builder = new StringBuilder();         while (node != null)         {             switch (node.NodeType)             {                 case XmlNodeType.Attribute:                     builder.Insert(0, "/@" + node.Name);                     node = ((XmlAttribute) node).OwnerElement;                     break;                 case XmlNodeType.Element:                     int index = FindElementIndex((XmlElement) node);                     builder.Insert(0, "/" + node.Name + "[" + index + "]");                     node = node.ParentNode;                     break;                 case XmlNodeType.Document:                     return builder.ToString();                 default:                     throw new ArgumentException("Only elements and attributes are supported");             }         }         throw new ArgumentException("Node was not in a document");     }      static int FindElementIndex(XmlElement element)     {         XmlNode parentNode = element.ParentNode;         if (parentNode is XmlDocument)         {             return 1;         }         XmlElement parent = (XmlElement) parentNode;         int index = 1;         foreach (XmlNode candidate in parent.ChildNodes)         {             if (candidate is XmlElement && candidate.Name == element.Name)             {                 if (candidate == element)                 {                     return index;                 }                 index++;             }         }         throw new ArgumentException("Couldn't find element within parent");     } } 
like image 142
Jon Skeet Avatar answered Oct 13 '22 01:10

Jon Skeet