Search code examples
c#xmlxpathdatacontractserializer

XPath not working in xml created using DataContractSerializer



I have a datacontract object and I am able to serialize it successfully to an xml using DataContractSerializer,but when I tried to access once of the node using XPath it is returning a null.I am unable to find out why it happens so.

This is what I have to so far.

namespace DataContractLibrary
{
    [DataContract]
    public class Person
    {
        [DataMember]
        public string FirstName { get; set; }

        [DataMember]
        public string LastName { get; set; }

        [DataMember]
        public int Age { get; set; }
    }
}

static void Main(string[] args)
{
    Person dataContractObject = new Person();
    dataContractObject.Age = 34;
    dataContractObject.FirstName = "SomeFirstName";
    dataContractObject.LastName = "SomeLastName";

    var dataSerializer = new DataContractSerializer(dataContractObject.GetType());

    XmlWriterSettings xmlSettings = new XmlWriterSettings { Indent = true, Encoding = Encoding.UTF8, OmitXmlDeclaration = true };
    using (var xmlWriter = XmlWriter.Create("person.xml", xmlSettings))
    {
        dataSerializer.WriteObject(xmlWriter, dataContractObject);
    }

    XmlDocument document = new XmlDocument();
    document.Load("person.xml");

    XmlNamespaceManager namesapceManager = new XmlNamespaceManager(document.NameTable);
    namesapceManager.AddNamespace("", document.DocumentElement.NamespaceURI);

    XmlNode firstName = document.SelectSingleNode("//FirstName", namesapceManager);

    if (firstName==null)
    {
        Console.WriteLine("Count not find the node.");
    }

    Console.ReadLine();
}

Can anyone let me know what went wrong for me? Your help would be much appreciated.


Solution

  • You're ignoring the XML namespace that gets put into the serialized XML:

    <Person xmlns:i="http://www.w3.org/2001/XMLSchema-instance" 
            xmlns="http://schemas.datacontract.org/2004/07/DataContractLibrary">
       <Age>34</Age>
       <FirstName>SomeFirstName</FirstName>
       <LastName>SomeLastName</LastName>
    </Person>
    

    So in your code, you need to reference that namespace:

    XmlNamespaceManager namespaceManager = new XmlNamespaceManager(document.NameTable);
    namespaceManager.AddNamespace("ns", document.DocumentElement.NamespaceURI);
    

    and then in your XPath, you need to use that namespace:

    XmlNode firstName = document.SelectSingleNode("//ns:FirstName", namespaceManager);
    
    if (firstName == null)
    {
       Console.WriteLine("Could not find the node.");
    }
    else
    {
       Console.WriteLine("First Name is: {0}", firstName.InnerText);
    }
    

    Now it works just fine - name gets printed onto the console.