XPathNavigator can select from test input but not real input

86 Views Asked by At

Here's my XML, obtained by printing serviceListXml to the console as shown in the code below:

<?xml version="1.0" encoding="utf-8"?>
<service xml:base="https://fnord/live/api/v1" xmlns="http://www.w3.org/2007/app" xmlns:atom="http://www.w3.org/2005/Atom">
  <workspace>
    <atom:title type="text">Service List</atom:title>
    <collection href="Erp.BO.ABCCodeSvc">
      <atom:title type="text">Erp.BO.ABCCodeSvc</atom:title>
    </collection>
    <collection href="Erp.BO.AccountBudgetSvc">
      <atom:title type="text">Erp.BO.AccountBudgetSvc</atom:title>
    </collection>
    <collection href="Erp.BO.ACTTypeSvc">
      <atom:title type="text">Erp.BO.ACTTypeSvc</atom:title>
    </collection>
    <!-- hundreds more collection elements -->
  </workspace>
</service>

And here's my code:

var serviceListXml = client.GetStringAsync(serviceListUrl).GetAwaiter().GetResult();
//serviceListXml = "<foo><bar><collection/><collection/><collection/></bar></foo>";
Console.WriteLine(serviceListXml);
var doc = new XPathDocument(new StringReader(serviceListXml));
var nav = doc.CreateNavigator();
var foo = nav.Select("//collection");
Console.WriteLine("selected " + foo.Count + " elements");

This selects 0 elements. Why?

If I uncomment the line that sets serviceListXml to a test string, it finds 3 elements as expected. I thought there might be a BOM on my real XML, so I tried using serviceListXml.Substring(serviceListXml.IndexOf("<")) but it made no difference.

1

There are 1 best solutions below

1
On BEST ANSWER

This is because in your original XML collection sits in http://www.w3.org/2007/app namespace, which is default namespace for that XML. To be able to select collection element you have two options:

Option 1: Pass namespace into your XPathDocument, e.g.:

var ns = new XmlNamespaceManager(nav.NameTable);
ns.AddNamespace("ns", "http://www.w3.org/2007/app");
var foo = nav.Select("//ns:collection", ns);

Option 2: Use this XPath: var foo = nav.Select("//*[local-name() = 'collection']");