Kirk Evans Blog

.NET From a Markup Perspective

Getting Path from an XmlNode

Getting Path from an XmlNode

  • Comments 6

I actually posted this about a year ago, but just ran across a need for the snippet again.  Thought posting here might benefit others as well as serve as a repository.  This allows you to get the path of a given XML node, as well as getting the qualified name of the node.

  private string GetQName(XmlNode node)
  {
   string qname = string.Empty;

   if (node.NamespaceURI.CompareTo(string.Empty) != 0)
   {
    if (node.Prefix.CompareTo(string.Empty) != 0)
    {
     //If the prefix is present, use it.

     if (node.NodeType == XmlNodeType.Attribute){qname = "@";}
     qname =  qname + node.Prefix + ":" + node.LocalName ;
    }
    else
    {
     //The node is in the default namespace, the prefix is not
     //present.
     if (node.NodeType == XmlNodeType.Attribute)
      qname = "@*[local-name() = '" + node.LocalName + "' and
namespace-uri()='" + node.NamespaceURI  + "']";
     else
      //QName is a misnomer here, but the current node belongs in a
non-prefixed namespace...
      qname = "node()[local-name() = '" + node.LocalName + "' and
namespace-uri()='" + node.NamespaceURI  + "']";
    }
   }
   else
   {
    if (node.NodeType == XmlNodeType.Attribute)
     qname = "@" + node.Name;
    else
     qname = node.Name;
   } return(qname);
  }


  private string GetPathFromNode(XmlNode baseNode)
  {
   string path = "";
   XmlNodeList nodes = null;
   if(baseNode.NodeType == XmlNodeType.Attribute )
   {
    nodes = baseNode.SelectNodes("ancestor::*");
   }
   else
   {
    nodes = baseNode.SelectNodes("ancestor-or-self::* |
ancestor-or-self::@*");
   }
   foreach(XmlNode node in nodes)
   {
    int nodePosition =
node.SelectNodes("preceding-sibling::*[local-name()='" + node.LocalName + "'
and namespace-uri()='" + node.NamespaceURI + "']").Count +1;
    path += "/" + GetQName(node) + "[" + nodePosition.ToString() + "]";
   }
   if(baseNode.NodeType == XmlNodeType.Attribute)
    path += "/" + GetQName(baseNode);
   return(path);
  }

  • What about the inverse situation?

    I want to put an element/value at a specified XPath location in an xml document that may or may not contain the element. Is there a way to do this without jumping through hoops?
  • What about the inverse situation?

    I want to put an element/value at a specified XPath location in an xml document that may or may not contain the element. Is there a way to do this without jumping through hoops?
  • You can use the DOM for this.

    XmlDocument doc = new XmlDocument();
    doc.Load(filePath);
    XmlNode node = doc.SelectSingleNode("/foo/bar[@baz='test']");
    if(null == bar)
    {
    XmlNode barr = foo.AppendChild(doc.CreateElement("bar"));
    XmlAttribute a = bar.Attributes.Add(doc.CreateAttribute("baz"));
    a.Value = "test";
    }
  • I'm curious what's going on with this XPath statement, "ancestor-or-self::* |
    ancestor-or-self::@*". In my app it keeps on crashing giving me a system error.
  • The statement selects along the ancestor node, including the current context node, looking for any elements or attributes.

    Sounds like a pretty ambiguous description of the fault. Have you tried debugging to any reasonable level of isolation? There are several versions of the .NET framework available (beta, 1.0, 1.1, 2.0 beta), anything beta is unsupported. If you are querying a huge document (huge being absolutely relative to your system's RAM and avialable memory w.r.t. other running applications), then you might be receiving some type of out of memory exception?

    Let's remember to be safe out there, people... don't try to run XPath statements over 5 Gig documents. It just doesn't make sense. You wouldn't pull back 50,000 rows from a database and filter on the client side, you would limit the amount of data you pull back from the database. Amazingly, the same rules of conservative memory usage apply to XML: there are 2 models, the DOM and the pull-based XmlReader parser... the DOM pulls everything into memory, the XmlReader reads one node at a time.
  • Wow, thanks for the quick response. I'm running .NET 1.1.4322.573. If I go in deeper to see what the exception is I get this: "System.Xml.XPath.XPathException

    The expression passed to this method should result in a NodeSet."

    The XmlDocument only has 3 nodes in it for testing.

    The real part of the XPath that my app doesn't seem to like is, "ancestor-or-self::@*". The other half of the or works fine by itself. I hope that's some more information for you.

    By the way, these msdn blogs are pretty sweet. You guys always seem to have goo dtings to say.
Page 1 of 1 (6 items)
Leave a Comment
  • Please add 3 and 7 and type the answer here:
  • Post
Translate This Page
Search
Archive
Archives