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
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);
XmlNamespaceManager
but the point is you shouldn't have to. The XDocument
stuff lets you just say XNamespace ns = new XNamespace(...); new XElement(ns + "nodeName"...);
- no namespace resolver required. Having to then add a resolver is going to duplicate your namespace definitions. –
Maidenhead 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);
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);
XmlNamespaceManager
but the point is you shouldn't have to. The XDocument
stuff lets you just say XNamespace ns = new XNamespace(...); new XElement(ns + "nodeName"...);
- no namespace resolver required. Having to then add a resolver is going to duplicate your namespace definitions. –
Maidenhead 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
© 2022 - 2024 — McMap. All rights reserved.