How to use XmlNamespaceManager and SelectSingleNode correctly? - c#

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);

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.

XmlDocument XPath expression failing

I am using C# XmlDocument API.
I have the following XML:
<Node1>
<Node2>
<Node3>
</Node3>
</Node2>
</Node1>
I want to get Node3 as an XmlNode. But my code is returning null:
XmlDocument doc = new XmlDocument();
doc.Load(reader);
XmlNode root_node = doc.DocumentElement.SelectSingleNode("/Node1");
Log(root_node.OuterXml);
XmlNode test_node = root_node.SelectSingleNode("/Node2/Node3");
if (test_node == null)
Logger.Log.Error(" --- TEST NODE IS NULL --- ");
The log for root_node.OuterXml logs
<Node1><Node2><Node3>.....
But test_node returns null.
What is going wrong here?
Use the path "Node2/Node3" instead of "/Node2/Node3":
XmlNode test_node = root_node.SelectSingleNode("Node2/Node3");
In an XPath expression, a leading forward slash / represents the root of the document. The expression "/Node2/Node3" doesn't work because <Node2> isn't at the root of the document.
Use // instead of /, when you are selecting from the root node
XmlDocument doc = new XmlDocument();
doc.Load(reader);
XmlNode root_node = doc.DocumentElement.SelectSingleNode("/Node1");
XmlNode test_node = root_node.SelectSingleNode("//Node2/Node3");
Another option is to use full path to the node 3
XmlNode test_node = doc.DocumentElement.SelectSingleNode("/Node1/Node2/Node3");
You can simple call Descendants()
var xml= #"<Node1><Node2><Node3></Node3></Node2></Node1>";
XDocument doc = XDocument.Parse(xml);
var node = doc.Descendants("Node3");
or use Element() starting from Root
var node2= doc.Root.Element("Node2").Element("Node3");
or use XPathSelectElement()
var node3= doc.XPathSelectElement("/Node1/Node2/Node3");

C# select node from XML

I have this code in C#, I need to get a Cube nodes, but my list of nodes is empty..
string url = #"http://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml";
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load(url);
XmlNamespaceManager manager = new XmlNamespaceManager(xmlDoc.NameTable);
manager.AddNamespace("gesmes", "http://www.gesmes.org/xml/2002-08-01");
XmlNodeList nodes = xmlDoc.SelectNodes("/gesmes:Envelope/Cube", manager);
What am I doing wrong?
There is a default namespace http://www.ecb.int/vocabulary/2002-08-01/eurofxref which you will need to register, to access the Cube element.
Otherwise, the XPath expression tries to find an un-namespaced Cube element, which doesn't exist in the document. XPath has no concept of a default namespace.
string url = #"http://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml";
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load(url);
XmlNamespaceManager manager = new XmlNamespaceManager(xmlDoc.NameTable);
manager.AddNamespace("gesmes", "http://www.gesmes.org/xml/2002-08-01");
manager.AddNamespace("default", "http://www.ecb.int/vocabulary/2002-08-01/eurofxref");
XmlNodeList nodes = xmlDoc.SelectNodes("/gesmes:Envelope/default:Cube", manager);
this will access the Cube child directly under the gesmes:Envelope. Depending what you want to achieve, you may want to use one of the following XPath expressions instead:
/gesmes:Envelope/default:Cube/default:Cube/default:Cube
/gesmes:Envelope//default:Cube[#currency]
/gesmes:Envelope//default:Cube[#time]/default:Cube

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

Change XML root element name

I have XML stored in string variable:
<ItemMasterList><ItemMaster><fpartno>xxx</fpartno><frev>000</frev><fac>Default</fac></ItemMaster></ItemMasterList>
Here I want to change XML tag <ItemMasterList> to <Masterlist>. How can I do this?
System.Xml.XmlDocument and the associated classes in that same namespace will prove invaluable to you here.
XmlDocument doc = new XmlDocument();
doc.LoadXml(yourString);
XmlDocument docNew = new XmlDocument();
XmlElement newRoot = docNew.CreateElement("MasterList");
docNew.AppendChild(newRoot);
newRoot.InnerXml = doc.DocumentElement.InnerXml;
String xml = docNew.OuterXml;
I know i am a bit late, but just have to add this answer as no one seems to know about this.
XDocument doc = XDocument.Parse("<ItemMasterList><ItemMaster><fpartno>xxx</fpartno><frev>000</frev><fac>Default</fac></ItemMaster></ItemMasterList>");
doc.Root.Name = "MasterList";
Which returns the following:
<MasterList>
<ItemMaster>
<fpartno>xxx</fpartno>
<frev>000</frev>
<fac>Default</fac>
</ItemMaster>
</MasterList>
You can use LINQ to XML to parse the XML string, create a new root and add the child elements and attributes of the original root to the new root:
XDocument doc = XDocument.Parse("<ItemMasterList>...</ItemMasterList>");
XDocument result = new XDocument(
new XElement("Masterlist", doc.Root.Attributes(), doc.Root.Nodes()));
Using the XmlDocument way, you can do this as follows (and keep the tree intact):
XmlDocument oldDoc = new XmlDocument();
oldDoc.LoadXml("<ItemMasterList><ItemMaster><fpartno>xxx</fpartno><frev>000</frev><fac>Default</fac></ItemMaster></ItemMasterList>");
XmlNode node = oldDoc.SelectSingleNode("ItemMasterList");
XmlDocument newDoc = new XmlDocument();
XmlElement ele = newDoc.CreateElement("MasterList");
ele.InnerXml = node.InnerXml;
If you now use ele.OuterXml is will return: (you you just need the string, otherwise use XmlDocument.AppendChild(ele) and you will be able to use the XmlDocument object some more)
<MasterList>
<ItemMaster>
<fpartno>xxx</fpartno>
<frev>000</frev>
<fac>Default</fac>
</ItemMaster>
</MasterList>
As pointed by Will A, we can do it that way but for case where InnerXml equals the OuterXml the following solution will work out:
// Create a new Xml doc object with root node as "NewRootNode" and
// copy the inner content from old doc object using the LastChild.
XmlDocument docNew = new XmlDocument();
XmlElement newRoot = docNew.CreateElement("NewRootNode");
docNew.AppendChild(newRoot);
// The below line solves the InnerXml equals the OuterXml Problem
newRoot.InnerXml = oldDoc.LastChild.InnerXml;
string xmlText = docNew.OuterXml;

Categories

Resources