0

I want to select nodes of a XML document using XPath. But it does not work when the XML document contains xml-namespaces. How can I search for nodes with XPath considering the namespaces?

This is my XML Document (simplified):

<ComponentSettings xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/Company.Product.Components.Model">
  <Created xmlns="http://schemas.datacontract.org/2004/07/Company.Configuration">2016-12-14T10:29:28.5614696+01:00</Created>
  <LastLoaded i:nil="true" xmlns="http://schemas.datacontract.org/2004/07/Company.Configuration" />
  <LastSaved xmlns="http://schemas.datacontract.org/2004/07/Company.Configuration">2016-12-14T16:31:37.876987+01:00</LastSaved>
  <RemoteTracer>
    <TraceListener>
      <Key>f987d7bb-9dea-49b4-a689-88c4452d98e3</Key>
      <Url>http://192.168.56.1:9343/</Url>
    </TraceListener>
  </RemoteTracer>
</ComponentSettings>

I want to get all Url tags of a TraceListener tag of a RemoteTracer tag. This is how i get them, but this only work if the XML document don't use namespaces:

componentConfigXmlDocument = new XmlDocument();
componentConfigXmlDocument.LoadXml(myXmlDocumentCode);
var remoteTracers = componentConfigXmlDocument.SelectNodes("//RemoteTracer/TraceListener/Url");

Currently, my workaround is to remove all namespaces from the XML raw string using regular expression, before loading the XML. Then my SelectNodes() works fine. But that is no proper solution.

rittergig
  • 715
  • 1
  • 5
  • 16

1 Answers1

1

You have two namespaces here. First is

http://schemas.datacontract.org/2004/07/Company.Product.Components.Model

Root element (ComponentSettings), RemoteTracer and everything below it belong to this namespace. Second namespace is

http://schemas.datacontract.org/2004/07/Company.Configuration

Created, LastLoaded and Saved belong to it.

To get the node you need, you have to prefix all elements in your xpath query with their respective namespace prefixes. Mapping of those prefixes to actual namespaces you can do like this:

var componentConfigXmlDocument = new XmlDocument();            
componentConfigXmlDocument.LoadXml(File.ReadAllText(@"G:\tmp\xml.txt"));
var ns = new XmlNamespaceManager(componentConfigXmlDocument.NameTable);
ns.AddNamespace("model", "http://schemas.datacontract.org/2004/07/Company.Product.Components.Model");
ns.AddNamespace("config", "http://schemas.datacontract.org/2004/07/Company.Configuration");

And then query like this:

var remoteTracers = componentConfigXmlDocument.SelectNodes("//model:RemoteTracer/model:TraceListener/model:Url", ns);
Evk
  • 98,527
  • 8
  • 141
  • 191
  • Thanks this works. I tried a much and searched for examples that matched my starting situation, but i didn't make a find. But this works. Thanks! – rittergig Dec 22 '16 at 15:04
  • How do you know which namespace a given element belongs to? I.e. how to know dynamically what I need to prefix RemoteTracer with in order to get it's value? – Alex Oct 28 '22 at 06:16
  • If you have some xml, you are expected to know it's structure to be able to extract some info from it. Namespace is basically part of element name, so you need to know the name beforehand. – Evk Oct 28 '22 at 06:24