How to read XML in C# using Xpath - c#

I have this XML
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap:Body>
<GetSKUsPriceAndStockResponse xmlns="http://tempuri.org/">
<GetSKUsPriceAndStockResult>
<RequestStatus>
<DateTime>2/28/2012 5:28:05 PM</DateTime>
<Message>S200</Message>
</RequestStatus>
<SKUsDetails>
<SKUDetails>
<SKU>N82E16834230265</SKU>
<Model>X54C-NS92</Model>
<Stock>true</Stock>
<Domain>newegg.com</Domain>
<SalePrice>439.99</SalePrice>
<ShippingCharge>0.00</ShippingCharge>
<Currency>USD</Currency>
</SKUDetails>
</SKUsDetails>
</GetSKUsPriceAndStockResult>
</GetSKUsPriceAndStockResponse>
</soap:Body>
</soap:Envelope>
How can I read <SKUDetails> Node using XPath?. What will be XNamespace for above XML?

Manipulate XML data with XPath and XmlDocument (C#)
or
its better to use LINQ to XML as your are using .net 4.0 and there is no need to learn XPath to traverse the xml tree.
Not sure about the xpath expression but you can code like this
string fileName = "data.xml";
XPathDocument doc = new XPathDocument(fileName);
XPathNavigator nav = doc.CreateNavigator();
// Compile a standard XPath expression
XPathExpression expr;
expr = nav.Compile("/GetSKUsPriceAndStockResponse/GetSKUsPriceAndStockResult/SKUsDetails/SKUDetails");
XPathNodeIterator iterator = nav.Select(expr);
try
{
while (iterator.MoveNext())
{
}
}
catch(Exception ex)
{
Console.WriteLine(ex.Message);
}

as #Kirill Polishchuk answered - SKUDetails is defined in http://tempuri.org/
he shows you how to get using XDocument
you can use alsow XmlDocument like this:
var dom = new XmlDocument();
dom.Load("data.xml");
var mgr = new XmlNamespaceManager(dom.NameTable);
mgr.AddNamespace("a", "http://tempuri.org/");
var res = dom.SelectNodes("//a:SKUDetails", mgr);

SKUsDetails is defined in http://tempuri.org/ namespace. You can use this code to select SKUsDetails using XPath:
var doc = XDocument.Load("1.xml");
var mgr = new XmlNamespaceManager(doc.CreateReader().NameTable);
mgr.AddNamespace("a", "http://tempuri.org/");
var node = doc.XPathSelectElement("//a:SKUsDetails", mgr);
To select SKUDetails use: //a:SKUsDetails/a:SKUDetails

Related

C# XML querying using XPath containing a namespace

In C# I'm struggling to understand how to query XML using XPath that includes a namespace.
XML:
<?xml version="1.0" encoding="utf-8"?>
<SomeEntity xmlns="http://www.example.com/Schemas/SomeEntity/2023/01">
<Child>
<TextValue>Some text</TextValue>
</Child>
</SomeEntity>
XPath:
/SomeEntity[#xmlns="http://www.example.com/Schemas/SomeEntity/2023/01"]/Child/TextValue
C#:
XmlNodeList nodes = doc.SelectNodes(xpath); \\ doc being of type XmlDocument
SelectNodes always results in an empty XmlNodeList.
What's the best way in C# to resolve XPath queries that include a namespace in this way?
I get the same result when using XDocument:
var doc = XDocument.Parse(xml);
string xpath = #"/SomeEntity[#xmlns=""http://www.example.com/Schemas/SomeEntity/2023/01""]/Child/TextValue";
var results = doc.XPathSelectElements(xpath);
It is better to use LINQ to XML.
There is no need to hardcode the default namespace. The GetDefaultNamespace() call gets it for you.
c#
void Main()
{
XDocument xdoc = XDocument.Parse(#"<SomeEntity xmlns='http://www.example.com/Schemas/SomeEntity/2023/01'>
<Child>
<TextValue>Some text</TextValue>
</Child>
</SomeEntity>");
XNamespace ns = xdoc.Root.GetDefaultNamespace();
string TextValue = xdoc.Descendants(ns + "TextValue")?.FirstOrDefault().Value;
Console.WriteLine("TextValue='{0}'", TextValue);
}
Output
TextValue='Some text'
For querying with the xmlns attibute condition, with #xmlns is not working. Instead, you need namespace-uri().
Pre-requisites:
Must add the XML namespace for query.
Provide the namespace prefix in the query.
For XmlDocument
string xpath = #"//se:SomeEntity[namespace-uri()='http://www.example.com/Schemas/SomeEntity/2023/01']/se:Child/se:TextValue";
XmlDocument doc = new XmlDocument();
doc.LoadXml(xml);
var mgr = new XmlNamespaceManager(doc.NameTable);
mgr.AddNamespace("se", "http://www.example.com/Schemas/SomeEntity/2023/01");
var nodes = doc.DocumentElement.SelectNodes(xpath, mgr);
Console.WriteLine(nodes.Count);
Console.WriteLine(nodes.Item(0).FirstChild.Value);
For XDocument
using System.Linq;
using System.Xml.XPath;
using System.Xml.Linq;
string xpath = #"//se:SomeEntity[namespace-uri()='http://www.example.com/Schemas/SomeEntity/2023/01']/se:Child/se:TextValue";
var xDoc = XDocument.Parse(xml);
var mgr = new XmlNamespaceManager(doc.NameTable);
mgr.AddNamespace("se", "http://www.example.com/Schemas/SomeEntity/2023/01");
var results = xDoc.XPathSelectElements(xpath, mgr);
Console.WriteLine(results.FirstOrDefault()?.Value);

Xml path that have multiple namespaces

I can't figure out what namespaces need to be used for following Xml (sample):
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<ResponseCharge xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<ResponseInfo xmlns="http://www.example.net">
<ResponseDetail>
<ResponseCode>00</ResponseCode>
<RequestIdentifier>1029034</RequestIdentifier>
<RetrievalReferenceNumber>634716660366</RetrievalReferenceNumber>
<ProcessingTime>00:03:314</ProcessingTime>
</ResponseDetail>
<ResponseTransactionDetail>
<AVSResponseCode />
<CVVResponseCode />
<AuthorizationSourceCode />
<AuthorizationNumber>004454</AuthorizationNumber>
</ResponseTransactionDetail>
<EMVResponseData />
</ResponseInfo>
</ResponseCharge>
</s:Body>
</s:Envelope>
My code looks like this atm:
XmlDocument doc = new XmlDocument();
doc.Load(responseXmlFile);
var nsmgr = new XmlNamespaceManager(doc.NameTable);
nsmgr.AddNamespace("s", "http://schemas.xmlsoap.org/soap/envelope/");
//nsmgr.AddNamespace("xsi", "http://www.w3.org/2001/XMLSchema-instance");
//nsmgr.AddNamespace("xsd", "http://www.w3.org/2001/XMLSchema");
//nsmgr.AddNamespace("", "http://www.example.net");
// getting NULL here
XmlNode node = doc.SelectSingleNode("/s:Envelope/s:Body/ResponseCharge/ResponseInfo/ResponseTransactionDetail/AuthorizationNumber", nsmgr);
I'm following this post: Namespace Manager or XsltContext needed
You need to include the namespace in your query for the elements in the http://www.example.net/ namespace.
var nsmgr = new XmlNamespaceManager(doc.NameTable);
nsmgr.AddNamespace("s", "http://schemas.xmlsoap.org/soap/envelope/");
nsmgr.AddNamespace("ex", "http://www.example.net");
XmlNode node = doc.SelectSingleNode(
"/s:Envelope/s:Body/ResponseCharge/ex:ResponseInfo/ex:ResponseTransactionDetail/ex:AuthorizationNumber",
nsmgr);
I've arbitrarily picked ex as the prefix here. What's defined in the XmlNamespaceManager only relates to your XPath query, the prefixes used in the document aren't relevant.
Alternatively, I'd suggest you use LINQ to XML:
XNamespace ns = "http://www.example.net"
var doc = XDocument.Load(responseXmlFile);
var authNo = (int)doc.Descendants(ns + "AuthorizationNumber").Single();

Access all nodes in xml using linq

I have xml:
<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
<UpdateMemberHireStatus xmlns="http://tempuri.org/">
<member>
<HireAvailability>
<code>1</code>
<name>פנוי</name>
</HireAvailability>
<HireRejectReason>
<code>2</code>
<name>wow</name>
</HireRejectReason>
<IdNumber>43504349</IdNumber>
<note> </note>
</member>
</UpdateMemberHireStatus>
and I want to use LINQ to access all the nodes in the xml.
Here's what I have tried:
XNamespace ns = "tempuri.org/";
IEnumerable<HireStatus> status = from r in doc.Descendants(ns + "UpdateMemberHireStatus")
.Descendants(ns + "member")
select new HireStatus() { };
return status.ToList();
Use Descendants
var xml = XDocument.Load(XMLStream);
var allEle = xml.Descendants("UpdateMemberHireStatus"); //you can do linq now.
You can use XDocument also in the following way:
string xmlPath = "D://member.xml";
XmlDocument doc = new XmlDocument();
xdoc = XDocument.Load(xmlPath);
doc.LoadXml(xdoc.ToString());
var memberStatus= (from mem in xdoc.Descendants("member")
select mem);
foreach (XElement element in memberStatuses.ToList())
IEnumerable<XNode> nodes = element.Nodes();
var x = XElement.Load(XMLStream);
var all = x.DescendantNodes();

Get data by XPath in C#

So I have this XML:
<?xml version="1.0" encoding="utf-8"?>
<M_ChucVu>
<ChucVu>
<MaChucVu>1
</MaChucVu>
<TenChucVu>
</TenChucVu>
</ChucVu>
<ChucVu>
<MaChucVu>2
</MaChucVu>
<TenChucVu>
</TenChucVu>
</ChucVu>
<ChucVu>
<MaChucVu>23</MaChucVu>
<TenChucVu>12</TenChucVu>
</ChucVu>
<ChucVu>
<MaChucVu>44</MaChucVu>
<TenChucVu>44</TenChucVu>
</ChucVu>
</M_ChucVu>
and I want to retrieve the ChucVu tags that contain an empty TenChucVu tag so the result is this:
<ChucVu>
<MaChucVu>1
</MaChucVu>
<TenChucVu>
</TenChucVu>
</ChucVu>
<ChucVu>
<MaChucVu>2
</MaChucVu>
<TenChucVu>
</TenChucVu>
</ChucVu>
XDocument doc = ...;
var query = doc.XPathSelectElements("//ChucVu[TenChucVu='']");
Another XPath that should work
/M_ChucVu[./ChucVu/TenChucVu='']
for example
var doc = new XmlDocument();
doc.LoadXml(yourXmlString);
var elem = doc.DocumentElement;
var sel = elem.SelectNodes("/M_ChucVu[./ChucVu/TenChucVu!='']");
// print or use sel.InnerXml
The XPath you need is:
/*/ChucVu[not(string(TenChucVu))]
or
/*/ChucVu[string-length(TenChucVu)=0]
You can as:
string xparth = String.Format("//ChucVu[TenChucVu='{0}']", '');
XmlDocument doc = new XmlDocument();
doc.Load("Xml");
XmlElement root = doc.DocumentElement;
XmlNode node = root.SelectSingleNode(xparth);
XmlNodeList list = root.SelectNodes(xparth);

issue to get specific XML element value using C#

Suppose I have the following XML document, how to get the element value for a:name (in my sample, the value is Saturday 100)? My confusion is how to deal with the name space. Thanks.
I am using C# and VSTS 2008.
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Body>
<PollResponse xmlns="http://tempuri.org/">
<PollResult xmlns:a="http://schemas.datacontract.org/2004/07/FOO.WCF" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<a:name>Saturday 100</a:name>
</PollResult>
</PollResponse>
</s:Body>
</s:Envelope>
Use System.Xml.XmlTextReader class,
System.Xml.XmlTextReader xr = new XmlTextReader(#"file.xml");
while (xr.Read())
{
if (xr.LocalName == "name" && xr.Prefix == "a")
{
xr.Read();
Console.WriteLine(xr.Value);
}
}
It's easier if you use the LINQ to XML classes. Otherwise namespaces really are annoying.
XNamespace ns = "http://schemas.datacontract.org/2004/07/FOO.WCF";
var doc = XDocument.Load("C:\\test.xml");
Console.Write(doc.Descendants(ns + "name").First().Value);
Edit. Using 2.0
XmlDocument doc = new XmlDocument();
doc.Load("C:\\test.xml");
XmlNamespaceManager ns = new XmlNamespaceManager(doc.NameTable);
ns.AddNamespace("a", "http://schemas.datacontract.org/2004/07/FOO.WCF");
Console.Write(doc.SelectSingleNode("//a:name", ns).InnerText);
XPath is the direct way to get at bits of an XML document in 2.0
XmlDocument xml = new XmlDocument();
xml.Load("file.xml")
XmlNamespaceManager manager = new XmlNamespaceManager(xml.NameTable);
manager.AddNamespace("a", "http://schemas.datacontract.org/2004/07/FOO.WCF");
string name = xml.SelectSingleNode("//a:name", manager).InnerText;

Categories

Resources