tags:

views:

4388

answers:

3

Consider this simple XML document. The serialized XML shown here is the result of an XmlSerializer from a complex POCO object whose schema I have no control over.

<My_RootNode xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="">
  <id root="2.16.840.1.113883.3.51.1.1.1" extension="someIdentifier" xmlns="urn:hl7-org:v3" /> 
  <creationTime xsi:nil="true" xmlns="urn:hl7-org:v3" />      
</My_RootNode>

The goal is to extract the value of the extension attribute on the id node. In this case, we are using the SelectSingleNode method, and given an XPath expression as such:

XmlNode idNode = myXmlDoc.SelectSingleNode("/My_RootNode/id");
//idNode is evaluated to null at this point in the debugger!
string msgID = idNode.Attributes.GetNamedItem("extension").Value;

The problem is that the SelectSingleNode method returns null for the given XPath expression.

Question: any ideas on this XPath query's correctness, or why this method call + XPath expression would return a null value? Perhaps the namespaces are part of the problem?

+1  A: 

Sorry, you forgot the namespace. You need:

XmlNamespaceManager ns = new XmlNamespaceManager(myXmlDoc.NameTable);
ns.AddNamespace("hl7","urn:hl7-org:v3");
XmlNode idNode = myXmlDoc.SelectSingleNode("/My_RootNode/hl7:id", ns);


In fact, whether here or in web services, getting null back from an XPath operation or anything that depends on XPath usually indicates a problem with XML namespaces.

John Saunders
Thanks John, actually the namespace is missing/blank in the test data! Do you suspect that's part of the problem?
p.campbell
The namespace on id. I'm editing my answer now.
John Saunders
I believe John is almost completely correct, because the full name of the "id" element is the pair "urn:h17-org:v3" and "id". You're searching for "" and "id" with your XPATH, so it won't find anything. However, to actually work, you need to pass the ns instance as the second parameter of SelectSingleNode.
Steven Sudit
Doh - spent all that time coming up with a test program, only to find you'd beaten me to it :)
Jon Skeet
@Jon: I should frame that. (ok, not really). Besides, Steven caught me leaving off the ",ns"
John Saunders
@Steven: good catch, and the most polite way of saying, "hey dummy, you forgot to use the object you just constructed" that I've heard in a while. "Almost completely correct" - I'll have to remember that.
John Saunders
+3  A: 

I strongly suspect the problem is to do with namespaces. Try getting rid of the namespace and you'll be fine - but obviously that won't help in your real case, where I'd assume the document is fixed.

I can't remember offhand how to specify a namespace in an XPath expression, but I'm sure that's the problem.

EDIT: Okay, I've remembered how to do it now. It's not terribly pleasant though - you need to create an XmlNamespaceManager for it. Here's some sample code that works with your sample document:

using System;
using System.Xml;

public class Test
{
    static void Main()
    {
        XmlDocument doc = new XmlDocument();
        XmlNamespaceManager namespaces = new XmlNamespaceManager(doc.NameTable);
        namespaces.AddNamespace("ns", "urn:hl7-org:v3");
        doc.Load("test.xml");
        XmlNode idNode = doc.SelectSingleNode("/My_RootNode/ns:id", namespaces);
        string msgID = idNode.Attributes["extension"].Value;
        Console.WriteLine(msgID);
    }
}
Jon Skeet
try //id to see if it is indeed a namespace issue.
ScottE
You can add namespaces when creating the xmldoc.
Oded
@Jon: thanks very much!
p.campbell
A: 

hey john thank u so much it was very helpfull

sweetie