C# select node from XML - c#

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

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

Can't find a certain node in XML

My problem is that I can't seem to get a list of nodes I need. I have tried multiple solutions and it doesn't seem to work. This is a part of my xml file:
<findItemsByCategoryResponse xmlns="http://www.ebay.com/marketplace/search/v1/services">
<ack>Success</ack>
<version>1.13.0</version>
<timestamp>2016-08-23T07:33:22.497Z</timestamp>
<searchResult count="100">
<item>
<itemId>152210133431</itemId>
<title>...</title>
<globalId>EBAY-GB</globalId>
<primaryCategory>
<categoryId>218</categoryId>
<categoryName>Magic the Gathering</categoryName>
</primaryCategory>
<galleryURL>
http://thumbs4.ebaystatic.com/m/meIDrVqhmbpQMYCxzeUvR9Q/140.jpg
</galleryURL>
<viewItemURL>
http://www.ebay.co.uk/itm/MTG-See-Unwritten-Khans-Tarkir-MYTHIC-MINT-/152210133431
</viewItemURL>
<paymentMethod>PayPal</paymentMethod>
<autoPay>false</autoPay>
<location>London,United Kingdom</location>
<country>GB</country>
<shippingInfo>
<shippingServiceCost currencyId="GBP">1.1</shippingServiceCost>
<shippingType>Flat</shippingType>
<shipToLocations>GB</shipToLocations>
</shippingInfo>
<sellingStatus>
<currentPrice currencyId="GBP">0.5</currentPrice>
<convertedCurrentPrice currencyId="GBP">0.5</convertedCurrentPrice>
<bidCount>0</bidCount>
<sellingState>Active</sellingState>
<timeLeft>P0DT0H19M12S</timeLeft>
</sellingStatus>
<listingInfo>
<bestOfferEnabled>false</bestOfferEnabled>
<buyItNowAvailable>false</buyItNowAvailable>
<startTime>2016-08-18T07:52:34.000Z</startTime>
<endTime>2016-08-23T07:52:34.000Z</endTime>
<listingType>Auction</listingType>
<gift>false</gift>
</listingInfo>
<condition>
<conditionId>1000</conditionId>
<conditionDisplayName>New</conditionDisplayName>
</condition>
<isMultiVariationListing>false</isMultiVariationListing>
<topRatedListing>false</topRatedListing>
</item>
</searchResult>
<paginationOutput>...</paginationOutput>
<itemSearchURL>...</itemSearchURL>
</findItemsByCategoryResponse>
Normally there are 100 item nodes in this xml file, I just shorted the file. I tried to get the ''item'' nodes and everything inside in a XmlNodeList, but when I debug it says it contains 0 items. After this I want to retrieve some data, as you can see in the code. Note: I tried a lot of xpath values!
Here is the code I used:
XmlDocument xmlText = new XmlDocument();
xmlText.Load(basicUrl);
XmlElement root = xmlText.DocumentElement;
XmlNodeList xnList = root.SelectNodes("//item");
foreach(XmlNode item in xnList)
{
string title = item["title"].InnerText;
Console.WriteLine(title);
}
XPath Expressions are always namespace aware (if the Element has a Namespace then the XPath must reference it by namespace). Also, in XPath expressions, the 'default' namespace is always in the URI "". In your case you should do something like this :
XmlDocument xmlText = new XmlDocument();
xmlText.Load(yourXml);
XmlElement root = xmlText.DocumentElement;
XmlNamespaceManager nsmgr = new XmlNamespaceManager(xmlText.NameTable);
nsmgr.AddNamespace("t", "http://www.ebay.com/marketplace/search/v1/services");
XmlNodeList xnList = xmlText.SelectNodes("//t:item", nsmgr);
foreach (XmlNode item in xnList)
{
string title = item["title"].InnerText;
Console.WriteLine(title);
}
SelectNodes with namespace :
https://msdn.microsoft.com/en-US/library/4bektfx9(v=vs.110).aspx

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

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