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.
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']");