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;
Related
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);
I have this XML
<?xml version="1.0" encoding="utf-8" standalone="no"?>
<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
<S:Header>
<wss:Security xmlns:wss="http://schemas.xmlsoap.org/ws/2002/12/secext">
<wss:UsernameToken>
<wss:Username>username</wss:Username>
<wss:Password>password</wss:Password>
<wss:Nonce></wss:Nonce>
<wss:Created></wss:Created>
</wss:UsernameToken>
</wss:Security>
</S:Header>
<S:Body>
<TaxRegistrationNumber>213213123</TaxRegistrationNumber>
<CompanyName>sadsadasd</CompanyName>
</S:Body>
</S:Envelope>
I want to accesses to the value of <wss:Username> and set a value in <wss:Nonce> node.
I already try 3 ways to get value of <wss:Username> on C# project:
First:
XDocument xmlFile = XDocument.Load(xmlpathfile);
XmlNamespaceManager ns = new XmlNamespaceManager(new NameTable());
ns.AddNamespace("wss", "http://schemas.xmlsoap.org/ws/2002/12/secext/");
XElement UserFinanc = xmlFile.XPathSelectElement("wss:Security/wss:UsernameToken/wss:Username", ns);
Second:
XDocument xmlFile = XDocument.Load(xmlpathfile);
XmlNamespaceManager ns = new XmlNamespaceManager(new NameTable());
var element = xmlFile.Descendants(wss + "Security").Descendants(wss + "UsernameToken").Where(x => x.Descendants(wss + "Username").Any(y => y.Value != "")).First().Element(wss + "UsernameToken");
if (element != null)
MessageBox.Show(element.Element(wss + "Username").Value).Value);
Third:
string grandChild = (string) (from el in xmlFile.Descendants(wss + "Username") select el).First();
MsgBox.Show(grandChild);
I always have similar errors like 'The sequence contains no elements'
Your first attempt is almost right. There are a couple things missing:
The namespace defined in code must be an exact match to the one in the xml. In your case the namespace in code has an extra trailing slash. It should be http://schemas.xmlsoap.org/ws/2002/12/secext.
The XPath expression should be //wss:Security/wss:UsernameToken/wss:Username. The leading slashes basically mean "look for this node anywhere". Alternatively, you could write out the whole path begining with <S:Envelope>. You would need to add the soap envelope namespace to your code as well.
The problem is the ServiceDocument as the xmlns attribute on it.
---Preassigned XML
System.Xml.XmlDocument xmlDoc = new XmlDocument();
xmlDoc.LoadXml("<?xml version=\"1.0\" encoding=\"utf-8\"?>
<ServiceDocument
xmlns:i=\"http://www.w3.org/2001/XMLSchema-instance\"
xmlns=\"http://schemas.microsoft.com/ado/2007/08/dataservices\"
>
<BaseUri>
http://xxxx.xxxxx.net/xxx.1/
</BaseUri>
<ProfilesLink>
http://adf.apis.dds.net/af.1/
</ProfilesLink>
<SignedInUser>
<Cid>
4433sfsdfgd
</Cid>
<Uri>
http://fd.apis.afdafd.net/V4.1/cid-xxxxx/adad
</Uri>
</SignedInUser>
<StatusMessageLink>
http://psm.adfa.afd.net/dfa.1/
</StatusMessageLink>
</ServiceDocument>"
);
// Response.Write(xmlDoc.InnerXml);
--//PARSE XML problem is below**
Response.Write(xmlDoc.SelectSingleNode("/ServiceDocument/BaseUri").InnerXml);
You need to assign short aliases to the namespaces using the XMLNamespaceManager.
See this page for an example.
So, to solve your problem:
var xmlNamespaceManager = new XmlNamespaceManager(xmlDoc.NameTable);
xmlNamespaceManager.AddNamespace("ds", "http://schemas.microsoft.com/ado/2007/08/dataservices");
var result = xmlDoc.SelectNodes("/ds:ServiceDocument/ds:BaseUri", xmlNamespaceManager);
I have the following Xml in my Resources.xmltest:
<?xml version="1.0" encoding="utf-8" ?>
<Response xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://DFISofft.com/SmartPayments/">
<Result>0</Result>
<Message>Pending</Message>
<PNRef>222131</PNRef>
<ExtData>InvNum=123</ExtData>
</Response>
I've tried several ways to get the values, Result,Message,PNRef,ExtData, out of it and I've had no luck. I always get a null value for the NodePath so it never goes into the loop:
var XmlDoc = new XmlDocument();
XmlDoc.LoadXml(Resources.xmltest);
XmlElement NodePath = (XmlElement) XmlDoc.SelectSingleNode("/Response");
while (NodePath != null)
{
foreach (XmlNode Xml_Node in NodePath)
{
Console.WriteLine(Xml_Node.Name + " " + Xml_Node.InnerText);
}
}
I've tried this:
XmlNode node3 = XmlDoc.SelectSingleNode("PNRef");
Console.WriteLine(node3.Value);
Console.WriteLine(XmlDoc.InnerXml);
var tst = XmlDoc.GetElementsByTagName("PNRef");
Console.WriteLine(tst);
And this:
NodePath = (XmlElement) XmlDoc.SelectSingleNode("/Response");
if (NodePath != null)
{
foreach (XmlNode node in NodePath)
{
Console.WriteLine("NodeName: " + Xml_NodeX.Name);
Console.WriteLine("NodeValue: " + node.InnerText);
}
}
Apparently, I'm not getting the xml read/write. I've done it with DataSets but they do all the work for you.
Can someone point me in the right direction? I've been at this for longer than I should have been already.
Thank you!
Your XML has a XML namespace and you're not paying any attention to it:
<Response xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns="http://DFISofft.com/SmartPayments/">
******************************************
When selecting from this XML, you need to use that XML namespace!
You're not taking into account the XML namespace (xmlns="http://nts-de-osm1-pxc/webservices/") on the document!
Try this:
var XmlDoc = new XmlDocument();
// setup the XML namespace manager
XmlNamespaceManager mgr = new XmlNamespaceManager(XmlDoc.NameTable);
// add the relevant namespaces to the XML namespace manager
mgr.AddNamespace("ns", "http://DFISofft.com/SmartPayments/");
XmlDoc.LoadXml(Resources.xmltest);
// **USE** the XML anemspace in your XPath !!
XmlElement NodePath = (XmlElement) XmlDoc.SelectSingleNode("/ns:Response");
while (NodePath != null)
{
foreach (XmlNode Xml_Node in NodePath)
{
Console.WriteLine(Xml_Node.Name + " " + Xml_Node.InnerText);
}
}
The problem is your XPath query, which doesn't specify a namespace - despite the fact that your document only has a Response element in the "http://DFISofft.com/SmartPayments/" namespace. Ditto the PNRef elements.
Personally I'd use LINQ to XML if I actually wanted to use namespaces if at all possible. For example:
XNamespace ns = "http://DFISofft.com/SmartPayments/";
XDocument doc = XDocument.Load(filename);
foreach (var element in doc.Descendants(ns + "PNRef"))
{
// Use element here
}
As you can see, LINQ to XML makes it really easy to use namespaces - but of course it requires .NET 3.5 or higher. If I had to use .NET 2.0, I'd either use XmlNamespaceManager or iterate manually and check local names instead of using XPath.
That is because the node isn't called response; you need to take the namespace into account:
var XmlDoc = new XmlDocument();
var nsmgr = new XmlNamespaceManager(XmlDoc.NameTable);
nsmgr.AddNamespace("x", "http://DFISofft.com/SmartPayments/");
XmlDoc.LoadXml(yourXml);
XmlElement NodePath = (XmlElement)XmlDoc.SelectSingleNode("/x:Response", nsmgr);
For future reference...
Bubba Soft
This site has a great free tool for building XPath Expressions (XPath Builder).
It's because you are using the overload of SelectSingleNode that assumes an empty namespace. Since you have a default namespace you will need to use the version that takes an XmlNamespaceManager. See this article for more info.
from the docs:
If the XPath expression does not include a prefix, it is assumed that the namespace URI is the empty namespace. If your XML includes a default namespace, you must still add a prefix and namespace URI to the XmlNamespaceManager; otherwise, you will not get a node selected. For more information, see Select Nodes Using XPath Navigation.
My code doesn't return the node
XmlDocument xml = new XmlDocument();
xml.InnerXml = text;
XmlNode node_ = xml.SelectSingleNode(node);
return node_.InnerText; // node_ = null !
I'm pretty sure my XML and Xpath are correct.
My Xpath : /ItemLookupResponse/OperationRequest/RequestId
My XML :
<?xml version="1.0"?>
<ItemLookupResponse xmlns="http://webservices.amazon.com/AWSECommerceService/2005-10-05">
<OperationRequest>
<RequestId>xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxxx</RequestId>
<!-- the rest of the xml is irrelevant -->
</OperationRequest>
</ItemLookupResponse>
The node my XPath returns is always null for some reason. Can someone help?
Your XPath is almost correct - it just doesn't take into account the default XML namespace on the root node!
<ItemLookupResponse
xmlns="http://webservices.amazon.com/AWSECommerceService/2005-10-05">
*** you need to respect this namespace ***
You need to take that into account and change your code like this:
XmlDocument xml = new XmlDocument();
xml.InnerXml = text;
XmlNamespaceManager nsmgr = new XmlNamespaceManager(xml.NameTable);
nsmgr.AddNamespace("x", "http://webservices.amazon.com/AWSECommerceService/2005-10-05");
XmlNode node_ = xml.SelectSingleNode(node, nsmgr);
And then your XPath ought to be:
/x:ItemLookupResponse/x:OperationRequest/x:RequestId
Now, your node_.InnerText should definitely not be NULL anymore!
Sorry for the late reply but I had a similar problem just a moment ago.
if you REALLY want to ignore that namespace then just delete it from the string you use to initialise the XmlDocument
text=text.Replace(
"<ItemLookupResponse xmlns=\"http://webservices.amazon.com/AWSECommerceService/2005-10-05\">",
"<ItemLookupResponse>");
XmlDocument xml = new XmlDocument();
xml.InnerXml = text;
XmlNode node_ = xml.SelectSingleNode(node);
return node_.InnerText;