Andy
Andy

Reputation: 11482

How do I get an IXmlNamespaceResolver

I'm trying to call the XElement.XPathSelectElements() overload that requires an IXmlNamespaceResolver object. Can anyone show me how to get (or make) an IXmlNamespaceResolver? I have a list of the namespaces I want to use in my query

Upvotes: 14

Views: 9857

Answers (3)

iltzortz
iltzortz

Reputation: 2412

You can use an XmlNamespaceManager that implements that interface

Use the constructor which takes an XmlNameTable, passing into it an instance of System.Xml.NameTable via new NameTable(). You can then call AddNamespace function to add namespaces:

var nsMgr = new XmlNamespaceManager(new NameTable());
nsMgr.AddNamespace("ex", "urn:example.org");
nsMgr.AddNamespace("t", "urn:test.org");
doc.XPathSelectElements("/ex:path/ex:to/t:element", nsMgr);

Upvotes: 10

Jelgab
Jelgab

Reputation: 1910

I found this post while searching on how to use the overload of [XPathSelectElements()] to process a SOAP response so, I will post my answer in case it is usefull for others who have a document with several namespace definitions. In my case I have a document like this:

<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <soap:Body>
    <queryResponse xmlns="http://SomeUrl.com/SomeSection">
      <response>
        <theOperationId>105</theOperationId>
        <theGeneraltheDetailsCode>0</theGeneraltheDetailsCode>
        <theDetails>
          <aDetail>
            <aDetailId>111</aDetailId>
            <theValue>Some Value</theValue>
            <theDescription>Some description</theDescription>
          </aDetail>
          <aDetail>
            <aDetailId>222</aDetailId>
            <theValue>Another Value</theValue>
            <theDescription>Another description</theDescription>
          </aDetail>
          <aDetail>
            <aDetailId>333</aDetailId>
            <theValue>And another Value</theValue>
            <theDescription>And another description</theDescription>
          </aDetail>
        </theDetails>
      </response>
    </queryResponse>
  </soap:Body>
</soap:Envelope>

To create the [XDocument]:

var theDocumentXDoc = XDocument.Parse( theDocumentContent );

To create the [XmlNamespaceManager], I use:

var theNamespaceIndicator = new XmlNamespaceManager( new NameTable() );
theNamespaceIndicator.AddNamespace( "theSoapNS", "http://www.w3.org/2003/05/soap-envelope" );
theNamespaceIndicator.AddNamespace( "noSuffNS" , "http://SomeUrl.com/SomeSection" );

The names I use for the prefixes ( "theSoapNS" and "noSuffNS" ) are arbitrary. Use a name that is convenient for a readable code.

To select the [Envelope] element, I use:

var theEnvelope = theDocumentXDoc.XPathSelectElement( "//theSoapNS:Envelope", theNamespaceIndicator );

To select the [queryResponse] element:

var theQueryResponse = theDocumentXDoc.XPathSelectElement( "//theSoapNS:Envelope/theSoapNS:Body/noSuffNS:queryResponse", theNamespaceIndicator );

To select all details in [theDetails]:

var theDetails = theDocumentXDoc.XPathSelectElement( "//theSoapNS:Envelope/theSoapNS:Body/noSuffNS:queryResponse/noSuffNS:response/noSuffNS:theDetails", theNamespaceIndicator );

Here is an example program (C#6) using the selections:

//The usings you need:
using System;
using System.Linq;
using System.Xml;
using System.Xml.Linq;
using System.Xml.XPath;

namespace ProcessXmlCons
{
    class Inicial
    {
        static void Main(string[] args)
        {
            new Inicial().Tests();
        }

        private void Tests()
        {
            Test01();
        }

        private void Test01()
        {
            var theDocumentContent =
              @"<?xml version=""1.0"" encoding=""utf-8""?>
                    <soap:Envelope xmlns:soap=""http://www.w3.org/2003/05/soap-envelope"" xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xmlns:xsd=""http://www.w3.org/2001/XMLSchema"">
                        <soap:Body>
                        <queryResponse xmlns=""http://SomeUrl.com/SomeSection"">
                            <response>
                                <theOperationId>105</theOperationId>
                                <theGeneraltheDetailsCode>0</theGeneraltheDetailsCode>
                                <theDetails>
                                    <aDetail>
                                        <aDetailId>111</aDetailId>
                                        <theValue>Some Value</theValue>
                                        <theDescription>Some description</theDescription>
                                    </aDetail>
                                    <aDetail>
                                        <aDetailId>222</aDetailId>
                                        <theValue>Another Value</theValue>
                                        <theDescription>Another description</theDescription>
                                    </aDetail>
                                    <aDetail>
                                        <aDetailId>333</aDetailId>
                                        <theValue>And another Value</theValue>
                                        <theDescription>And another description</theDescription>
                                    </aDetail>
                                </theDetails>
                            </response>
                        </queryResponse>
                        </soap:Body>
                    </soap:Envelope>
                    ";

            var theDocumentXDoc = XDocument.Parse(theDocumentContent);
            var theNamespaceIndicator = new XmlNamespaceManager(new NameTable());
            theNamespaceIndicator.AddNamespace("theSoapNS", "http://www.w3.org/2003/05/soap-envelope");
            theNamespaceIndicator.AddNamespace("noSuffNS", "http://SomeUrl.com/SomeSection");

            var theEnvelope = theDocumentXDoc.XPathSelectElement("//theSoapNS:Envelope", theNamespaceIndicator);
            Console.WriteLine($"The envelope: {theEnvelope?.ToString()} ");

            var theEnvelopeNotFound = theDocumentXDoc.XPathSelectElement("//Envelope", theNamespaceIndicator);
            Console.WriteLine("".PadRight(120, '_')); //Visual divider
            Console.WriteLine($"The other envelope: \r\n {theEnvelopeNotFound?.ToString()} ");

            var theQueryResponse = theDocumentXDoc.XPathSelectElement("//theSoapNS:Envelope/theSoapNS:Body/noSuffNS:queryResponse", theNamespaceIndicator);
            Console.WriteLine("".PadRight(120, '_')); //Visual divider
            Console.WriteLine($"The query response: \r\n {theQueryResponse?.ToString()} ");

            var theDetails = theDocumentXDoc.XPathSelectElement("//theSoapNS:Envelope/theSoapNS:Body/noSuffNS:queryResponse/noSuffNS:response/noSuffNS:theDetails", theNamespaceIndicator);
            Console.WriteLine("".PadRight(120, '_')); //Visual divider
            Console.WriteLine($"The details: \r\n {theDetails?.ToString()} ");
            Console.WriteLine("".PadRight(120, '_')); //Visual divider

            foreach (var currentDetail in theDetails.Descendants().Where(elementToFilter => elementToFilter.Name.LocalName != "aDetail"))
            {
                Console.WriteLine($"{currentDetail.Name.LocalName}: {currentDetail.Value}");
            }

            //Not optimal. Just to show XPath select within another selection:
            Console.WriteLine("".PadRight(120, '_')); //Visual divider
            Console.WriteLine("Values only:");
            foreach (var currentDetail in theDetails.Descendants())
            {
                var onlyTheValueElement = currentDetail.XPathSelectElement("noSuffNS:theValue", theNamespaceIndicator);
                if (onlyTheValueElement != null)
                {
                    Console.WriteLine($"--> {onlyTheValueElement.Value}");
                }
            }
        }

    } //class Inicial
} //namespace ProcessXmlCons

Upvotes: 4

davidbludlow
davidbludlow

Reputation: 2173

Use new XmlNamespaceManager(new NameTable()).

For example, if you have an XML document that uses namespaces like

var xDoc = XDocument.Parse(@"<m:Student xmlns:m='http://www.ludlowcloud.com/Math'>
    <m:Grade>98</m:Grade>
    <m:Grade>96</m:Grade>
</m:Student>");

then you can get the Grade nodes by doing

var namespaceResolver = new XmlNamespaceManager(new NameTable());
namespaceResolver.AddNamespace("math", "http://www.ludlowcloud.com/Math");
var grades = xDoc.XPathSelectElements("//math:Student/math:Grade", namespaceResolver);

Upvotes: 11

Related Questions