XPathSelectElements always return empty in XML with namespace?

Viewed 70

I'm working on XML string as follows:

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" 
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
       xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <soap:Body>
    <Get_x0020_Remain_x0020_VacationResponse xmlns="http://tempuri.org/">
      <Get_x0020_Remain_x0020_VacationResult>
        <Period>0:0</Period>
        <Month>0:0</Month>
        <YearPeriod>16:0</YearPeriod>
        <YearMonth>32:0</YearMonth>
        <CurrentPeriod>0:0</CurrentPeriod>
        <CurrentMonth>14:0</CurrentMonth>
        <PeriodName>Davazdah</PeriodName>
        <MonthName>bahman</MonthName>
        <RemainUpToNowPeriod>0:0</RemainUpToNowPeriod>
        <RemainUpToNowMonth>0:0</RemainUpToNowMonth>
        <RemainUpToEndOfThisYearPeriodic>0:0</RemainUpToEndOfThisYearPeriodic>
        <RemainUpToEndOfThisYearMonthly>16:0</RemainUpToEndOfThisYearMonthly>
      </Get_x0020_Remain_x0020_VacationResult>
    </Get_x0020_Remain_x0020_VacationResponse>
  </soap:Body>
</soap:Envelope>

I want to access RemainUpToEndOfThisYearMonthly element using XPATH
My code:

var xDocument = XDocument.Parse(xmlString);
var xmlNamespaceManager = new XmlNamespaceManager(xDocument.CreateReader().NameTable 
    ?? new NameTable());
xmlNamespaceManager.AddNamespace("soap", "http://schemas.xmlsoap.org/soap/envelope/");
xmlNamespaceManager.AddNamespace("xsi", "http://www.w3.org/2001/XMLSchema-instance");
xmlNamespaceManager.AddNamespace("xsd", "http://www.w3.org/2001/XMLSchema");
xmlNamespaceManager.AddNamespace("", "http://tempuri.org/");
var nodeRemainUpToEndOfThisYearMonthly = 
     xDocument.XPathSelectElements("//RemainUpToEndOfThisYearMonthly",
        xmlNamespaceManager); // always is empty

But nodeRemainUpToEndOfThisYearMonthly is always empty.
How should I do that?

1 Answers

This is included in the docs:

XPath treats the empty prefix as the null namespace. In other words, only prefixes mapped to namespaces can be used in XPath queries. This means that if you want to query against a namespace in an XML document, even if it is the default namespace, you need to define a prefix for it.

So, as stated, you need to add a prefix. Let's say temp:

xmlNamespaceManager.AddNamespace("temp", "http://tempuri.org/");

var nodeRemainUpToEndOfThisYearMonthly = 
     xDocument.XPathSelectElements("//temp:RemainUpToEndOfThisYearMonthly",
        xmlNamespaceManager);

I'd also note that none of the other prefixes need to be added unless you're going to be using them.

Having said that, I'd suggest that just using the LINQ to XML API is more straightforward and type-safe:

XNamespace temp = "http://tempuri.org/";

var remainUpToEndOfThisYearMonthly = (string) xDocument
    .Descendants(temp + "RemainUpToEndOfThisYearMonthly")
    .SingleOrDefault();
Related