XPath doesn't work as desired in C# - c#

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;

Related

Getting XML node using XPath returns null

I am trying to get a node in a simple XML, but no matter what I try I always get null.
I am guessing that the issue is the namespace.
I am simply trying to get the value of the ID element, 331377697.
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load("E:\\0323.xml");
XmlNamespaceManager manager = new XmlNamespaceManager(xmlDoc.NameTable);
manager.AddNamespace("cac", "http://xxxxxx Some URL XXXX");
manager.AddNamespace("cbc", "http://xxxxxx Some URL XXXX");
string query = "/StandardBusinessDocument/Invoice/cbc:ID";
XmlNode xmlNode = xmlDoc.SelectSingleNode(query, manager);
The XML:
<StandardBusinessDocument xmlns="http://www.unece.org/cefact/namespaces/StandardBusinessDocumentHeader">
<StandardBusinessDocumentHeader>
...
</StandardBusinessDocumentHeader>
<Invoice xmlns="urn:oasis:names:specification:ubl:schema:xsd:Invoice-2" xmlns:cac="urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2" xmlns:cbc="urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2" xmlns:ccts="urn:un:unece:uncefact:documentation:2"
...
</Invoice>
<cbc:UBLVersionID>2.1</cbc:UBLVersionID>
<cbc:CustomizationID>1234</cbc:CustomizationID>
<cbc:ProfileID>1234564</cbc:ProfileID>
<cbc:ID>331377697</cbc:ID>
<cbc:IssueDate>2017-03-23</cbc:IssueDate>
<cbc:InvoiceTypeCode listID="UNCL1001">380</cbc:InvoiceTypeCode>
<cbc:DocumentCurrencyCode listID="ISO4217">NOK</cbc:DocumentCurrencyCode>
<cac:OrderReference>
<cbc:ID>146136</cbc:ID>
</cac:OrderReference>
...
You must specify the exact namespaces.
Also you have to specify namespace prefixes for all elements in the XPath.
manager.AddNamespace("nsDoc", "http://www.unece.org/cefact/namespaces/StandardBusinessDocumentHeader");
manager.AddNamespace("nsInvoice", "urn:oasis:names:specification:ubl:schema:xsd:Invoice-2");
manager.AddNamespace("cbc", "urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2");
string query = "/nsDoc:StandardBusinessDocument/nsInvoice:Invoice/cbc:ID";
It's supposed to work.

How to use XmlNamespaceManager and SelectSingleNode correctly?

I need to get node value from xml. The xml has namespace.
I have the following code
string xml =
"<file xmlns=\"SFAKT\" xmlns:xs=\"http://www.w3.org/2001/XMLSchema\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">" +
"<document>test</document>" +
"</file>";
XmlDocument xmlDocument = new XmlDocument();
xmlDocument.LoadXml(xml);
XmlNamespaceManager ns = new XmlNamespaceManager(xmlDocument.NameTable);
ns.AddNamespace("sf", "SFAKT");
XmlNode node = xmlDocument.SelectSingleNode("sf:file/document");
But node = null
Can you tell me where is the error in my code?
You need to use the overloaded SelectSingleNode method and pass in the XmlNamespaceManager. Also, you need the sf prefix for the document node.
Pull the node out like this:
XmlNode node = xmlDocument.SelectSingleNode("sf:file/sf:document", ns);

Read first root node from XML

I work with three kinds of XML files :
Type A:
<?xml version="1.0" encoding="UTF-8"?>
<nfeProc versao="2.00" xmlns="http://www.portalfiscal.inf.br/nfe">
</nfeProc>
Tyepe B:
<?xml version="1.0" encoding="UTF-8"?>
<cancCTe xmlns="http://www.portalfiscal.inf.br/cte" versao="1.04">
</cancCTe>
Type C:]
<?xml version="1.0" encoding="UTF-8"?>
<cteProc xmlns="http://www.portalfiscal.inf.br/cte" versao="1.04">
</cteProc>
I have try with this code to read the first node :
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load(#"C:\crruopto\135120068964590_v01.04-procCTe.xml");
XmlNodeList ml = xmlDoc.GetElementsByTagName("*");
XmlElement root = xmlDoc.DocumentElement;
exti = root.ToString();
but dont return anything i want to read the first node , need to know if the file is nfeProc ,canCTE or cteProc
The second question is how i get the value from "value" in the same tag???
Thanks
From this post:
//Root node is the DocumentElement property of XmlDocument
XmlElement root = xmlDoc.DocumentElement
//If you only have the node, you can get the root node by
XmlElement root = xmlNode.OwnerDocument.DocumentElement
I would suggest using XPath. Here's an example where I read in the XML content from a locally stored string and select whatever the first node under the root is:
XmlDocument doc = new XmlDocument();
doc.Load(new StringReader(xml));
XmlNode node = doc.SelectSingleNode("(/*)");
If you aren't required to use the XmlDocument stuff, then Linq is your friend.
XDocument doc = XDocument.Load(#"C:\crruopto\135120068964590_v01.04-procCTe.xml");
XElement first = doc.GetDescendants().FirstOrDefault();
if(first != null)
{
//first.Name will be either nfeProc, canCTE or cteProc.
}
Working with Linq to XML is the newest and most powerful way of working with XML in .NET and offers you a lot more power and flexibility than things like XmlDocument and XmlNode.
Getting the root node is very simple:
XDocument doc = XDocument.Load(#"C:\crruopto\135120068964590_v01.04-procCTe.xml");
Console.WriteLine(doc.Root.Name.ToString());
Once you have constructed an XDocument you don't need to use any LINQ querying or special checking. You simply pull the Root property from the XDocument.
Thanks i have solved this way the first part
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load(nomear);
XmlNodeList ml = xmlDoc.GetElementsByTagName("*");
XmlNode primer = xmlDoc.DocumentElement;
exti = primer.Name;
First, to be clear, you're asking about the root element, not the root node.
You can use an XmlReader to avoid having to load large documents completely into memory. See my answer to a how to find the root element at https://stackoverflow.com/a/60642354/1307074.
Second, once the reader is referencing the element, you can use the reader's Name property to get the qualified tag name of the element. You can get the value as a string using the Value property.

C# Xml Value always getting null

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.

I need to convert an XML string into an XmlElement

I'm looking for the simplest way to convert a string containing valid XML into an XmlElement object in C#.
How can you turn this into an XmlElement?
<item><name>wrench</name></item>
Use this:
private static XmlElement GetElement(string xml)
{
XmlDocument doc = new XmlDocument();
doc.LoadXml(xml);
return doc.DocumentElement;
}
Beware!!
If you need to add this element to another document first you need to Import it using ImportNode.
Suppose you already had a XmlDocument with children nodes, And you need add more child element from string.
XmlDocument xmlDoc = new XmlDocument();
// Add some child nodes manipulation in earlier
// ..
// Add more child nodes to existing XmlDocument from xml string
string strXml =
#"<item><name>wrench</name></item>
<item><name>screwdriver</name></item>";
XmlDocumentFragment xmlDocFragment = xmlDoc.CreateDocumentFragment();
xmlDocFragment.InnerXml = strXml;
xmlDoc.SelectSingleNode("root").AppendChild(xmlDocFragment);
The Result:
<root>
<item><name>this is earlier manipulation</name>
<item><name>wrench</name></item>
<item><name>screwdriver</name>
</root>
Use XmlDocument.LoadXml:
XmlDocument doc = new XmlDocument();
doc.LoadXml("<item><name>wrench</name></item>");
XmlElement root = doc.DocumentElement;
(Or in case you're talking about XElement, use XDocument.Parse:)
XDocument doc = XDocument.Parse("<item><name>wrench</name></item>");
XElement root = doc.Root;
You can use XmlDocument.LoadXml() to do this.
Here is a simple examle:
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.LoadXml("YOUR XML STRING");
I tried with this snippet, Got the solution.
// Sample string in the XML format
String s = "<Result> No Records found !<Result/>";
// Create the instance of XmlDocument
XmlDocument doc = new XmlDocument();
// Loads the XML from the string
doc.LoadXml(s);
// Returns the XMLElement of the loaded XML String
XmlElement xe = doc.DocumentElement;
// Print the xe
Console.out.println("Result :" + xe);
If any other better/ efficient way to implement the same, please let us know.
Thanks & Cheers

Categories

Resources