XmlDocument - SelectSingleNode with namespace - c#

This is my code:
XmlTextReader reader = new XmlTextReader(xmlPath);
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load(reader);
XmlNode root = xmlDoc.DocumentElement;
XmlNode node = root.SelectSingleNode("marketingid");
XML that works:
<confirmsubmit>
<marketingid>-1</marketingid>
</confirmsubmit>
XML that doesn't work:
<confirmsubmit xmlns="http:....">
<marketingid>-1</marketingid>
</confirmsubmit>
What is the way to deal with the xmlns attribute and how can i parse it?
Is it has anything to do with namespace?
EDIT:
This is the code that works:
XmlTextReader reader = new XmlTextReader(xmlPath);
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load(reader);
XmlNamespaceManager nsmgr = new XmlNamespaceManager(xmlDoc.NameTable);
nsmgr.AddNamespace("ns", xmlDoc.DocumentElement.NamespaceURI);
XmlNode book = xmlDoc.SelectSingleNode("/ns:confirmsubmit/ns:marketingid", nsmgr);
This all XPath is more complicated than seems, I would recommand to begginers like my to read: http://www.w3schools.com/xpath/xpath_syntax.asp

You need to add a XmlNamespaceManager instance in the game, as shown in this example from the documentation:
public class Sample
{
public static void Main()
{
XmlDocument doc = new XmlDocument();
doc.Load("booksort.xml");
//Create an XmlNamespaceManager for resolving namespaces.
XmlNamespaceManager nsmgr = new XmlNamespaceManager(doc.NameTable);
nsmgr.AddNamespace("bk", "urn:samples");
//Select and display the value of all the ISBN attributes.
XmlNodeList nodeList;
XmlElement root = doc.DocumentElement;
nodeList = root.SelectNodes("/bookstore/book/#bk:ISBN", nsmgr);
foreach (XmlNode isbn in nodeList){
Console.WriteLine(isbn.Value);
}
}
}

Here is how to do it from LINQ to XML. Short and simple
const string xml = #"<confirmsubmit xmlns='http:....'>
<marketingid>-1</marketingid>
</confirmsubmit>";
XElement element = XElement.Parse(xml);
var requestedElement = element.Elements().FirstOrDefault(x => x.Name.LocalName.Equals("marketingid"));

xmlns attribute is used at XHTML and defines namespace for a document. You can parse it like:
XDocument xdoc = XDocument.Load(xmlPath);
var attrib = xdoc.Root.Attribute("xmlns").Value;

Related

iterating XmlDocument with xpath

How do we iterate an XmlDocument using an xpath?
I'm attempting to return a list of nodes by xpath:
public static List<string> Filter(string xpath, string input, string ns, string nsUrl)
{
var bytes = Encoding.UTF8.GetBytes(input); //i believe this unescapes the string
var stream = new MemoryStream(bytes);
var doc = new XmlDocument();
XmlNamespaceManager namespaceManager = new XmlNamespaceManager(doc.NameTable);
namespaceManager.AddNamespace(ns, nsUrl);
var links = new List<string>();
var nodes = doc.SelectNodes(xpath, namespaceManager);
using (var reader = new XmlTextReader(stream))
{
reader.Namespaces = false;
doc.Load(reader);
}
foreach (XmlNode node in nodes)
{
if (IsNullOrWhiteSpace(node.InnerText))
{
continue;
}
links.Add(node.InnerText);
}
return links;
}
however, the count is always 0 !
I'm using this xpath. notice how i am using only 1 namespace:
/ns0:Visit/ns0:DocumentInterface/ns0:Documents/ns0:Document/ns0:BinaryData
The header of the file looks like this:
<ns0:Visit xmlns:ns0="http://NameSpace.ExternalSchemas.Patient"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
I'm certain that I am using the right xpath because I tested it against my payload:
I'm calling the function this way:
var links = Filter(xpath, xml, "ns0", "http://NameSpace.ExternalSchemas.Patient");
How do we iterate an XmlDocument using an xpath? Perhaps the XmlDocument should be an XDocument instead?

'This document already has a 'DocumentElement' node.'

I am trying to create a xml document of following format
<TemplateID>xxxxx</TemplateID>
<CaptionOptions>
<CaptionField>
<Field>xxx</Field>
<Text>xxx</Text>
</CaptionField>
<CaptionField>
<Field>xxxx</Field>
<Text>""</Text>
</CaptionField>
</CaptionOptions>
Here is the code that I wrote
XmlDocument xml2 = new XmlDocument();
XmlElement e = xml2.CreateElement("TemplateID");
e.InnerText = "xxxx";
xml2.AppendChild(e);
XmlElement root2 = xml2.CreateElement("CaptionOptions");
xml2.AppendChild(root2); //error here
XmlElement child2a = xml2.CreateElement("CaptionField");
root2.AppendChild(child2a);
XmlElement child2aa = xml2.CreateElement("Field");
child2a.InnerText = "xxxx";
XmlElement child2ab = xml2.CreateElement("Text");
child2a.InnerText = "xxxx";
child2a.AppendChild(child2aa);
child2a.AppendChild(child2ab);
child2a.AppendChild(child2aa);
child2a.AppendChild(child2ab);
My real code was different from the one I was trying to ask earlier....
You could use
XmlElement child = xml.CreateElement("Players");
child.SetAttribute("Nationality", "England");
child.InnerText = "Rooney";
You need to create attributes and append them to the Player element. But your xml hierarchy doesn't look right.
As discussed, now edited.
XmlDocument doc = new XmlDocument();
XmlElement template = doc.CreateElement("Template");
XmlNode id = doc.CreateElement("TemplateID");
id.InnerText = "123456";
template.AppendChild(id);
doc.AppendChild(template);
XmlElement options = doc.CreateElement("CaptionOptions");
XmlElement captionField = doc.CreateElement("CaptionField");
XmlElement field1 = doc.CreateElement("Field");
field1.InnerText = "Field1Text";
XmlElement text1 = doc.CreateElement("Field");
text1.InnerText = "Text1Text";
captionField.AppendChild(field1);
captionField.AppendChild(text1);
options.AppendChild(captionField);
template.AppendChild(options);
string xml = doc.OuterXml;
Hope that helps.

Reading XML in Asp.net not getting any results

I am using following code to read an XML file from this address.
XmlDocument xdoc = new XmlDocument();
xdoc.Load("https://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml");
XmlNodeList nodeList = xdoc.DocumentElement.SelectNodes("//gesmes/Cube/Cube");
if (nodeList == null) lblOutput.Text = "node is null";
foreach (XmlNode node in nodeList)
{
XmlNode innerNode = node.SelectSingleNode(".//Cube");
lblOutput.Text = innerNode.Attributes["currency"].Value;
}
The problem is I don't get any thing. nodeList.Count always gives me 0.
You need to handle the namespaces correctly.
There are probably more then one way to handle them and this is one
XmlDocument xdoc = new XmlDocument();
xdoc.Load("https://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml");
XmlNamespaceManager xnm = new XmlNamespaceManager(xdoc.NameTable);
xnm.AddNamespace("gesmes", "http://www.gesmes.org/xml/2002-08-01");
xnm.AddNamespace("eurofxref", "http://www.ecb.int/vocabulary/2002-08-01/eurofxref");
XmlNodeList nodeList = xdoc.DocumentElement.SelectNodes("//gesmes:Envelope/eurofxref:Cube/eurofxref:Cube", xnm);
if (nodeList == null)
{
var text = "node is null";
}
foreach (XmlNode node in nodeList)
{
XmlNode innerNode = node.SelectSingleNode(".//eurofxref:Cube", xnm);
var text = innerNode.Attributes["currency"].Value;
}
I don't know why it has to be this complicated but....
XmlDocument xdoc = new XmlDocument();
xdoc.Load("https://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml");
XmlNamespaceManager xMan = new XmlNamespaceManager(xdoc.NameTable);
xMan.AddNamespace("def", "http://www.ecb.int/vocabulary/2002-08-01/eurofxref");
XmlNodeList nodeList = xdoc.DocumentElement.SelectNodes("//def:Cube", xMan);

Creating XML document with Two root nodes

I want to create XML with two root nodes, like this
<?xml version="1.0" encoding="IBM437"?>
<header1>
<header2>
<fracc>6004</fracc>
<txncode>HTH</txncode>
<reason>testing</reason>
<timeout>20</timeout>
<rdate>2/3/2015 12:00:00 AM</rdate>
<rtime>6/18/2015 1:20:00 PM</rtime>
<seqno>5</seqno>
<prefix>8</prefix>
<msgtype>trr</msgtype>
<sendto>trr</sendto>
<replyto>trr</replyto>
</header2>
</header1>
My code is like this, I'm unable to add two root elements with my code, it's a must to use XmlDocument class.
XmlDocument xmlDoc = new XmlDocument();
XmlNode rootNode = xmlDoc.CreateElement("header" );
xmlDoc.AppendChild(rootNode);
XmlNode accountNode = xmlDoc.CreateElement("fracc");
accountNode.InnerText = Infracc;
rootNode.AppendChild(accountNode);
XmlNode txnNode = xmlDoc.CreateElement("txncode");
txnNode.InnerText = Intxncode;
rootNode.AppendChild(txnNode);
XmlNode reasonNode = xmlDoc.CreateElement("reason");
reasonNode.InnerText = Inreason;
rootNode.AppendChild(reasonNode);
XmlNode timeoutNode = xmlDoc.CreateElement("timeout");
timeoutNode.InnerText = Intimeout.ToString();
rootNode.AppendChild(timeoutNode);
XmlNode rdateNode = xmlDoc.CreateElement("rdate");
rdateNode.InnerText = Indate.ToString();
rootNode.AppendChild(rdateNode);
XmlNode rtimeNode = xmlDoc.CreateElement("rtime");
rtimeNode.InnerText = Intime.ToString();
rootNode.AppendChild(rtimeNode);
XmlNode seqnoNode = xmlDoc.CreateElement("seqno");
seqnoNode.InnerText = Inseqno.ToString();
rootNode.AppendChild(seqnoNode);
XmlNode prefixNode = xmlDoc.CreateElement("prefix");
prefixNode.InnerText = Inprefix.ToString();
rootNode.AppendChild(prefixNode);
XmlNode msgtypeNode = xmlDoc.CreateElement("msgtype");
msgtypeNode.InnerText = Inmsgtype;
rootNode.AppendChild(msgtypeNode);
XmlNode sendtoNode = xmlDoc.CreateElement("sendto");
sendtoNode.InnerText = Insendto;
rootNode.AppendChild(sendtoNode);
XmlNode replytoNode = xmlDoc.CreateElement("replyto");
replytoNode.InnerText = Inreplyto;
rootNode.AppendChild(replytoNode);
xmlDoc.Save("boc.xml");
xmlDoc.Load("boc.xml");
xmlDoc.Save(Console.Out);
return xmlDoc;
and my output is this
<?xml version="1.0" encoding="IBM437"?>
<header>
<fracc>6004</fracc>
<txncode>ttt</txncode>
<reason>testing</reason>
<timeout>20</timeout>
<rdate>2/3/2015 12:00:00 AM</rdate>
<rtime>6/18/2015 1:20:00 PM</rtime>
<seqno>5</seqno>
<prefix>8</prefix>
<msgtype>tt</msgtype>
<sendto>t</sendto>
<replyto>t</replyto>
</header>
Please help me to add two root nodes.
You are not adding 2 root elements.
Change your lines of code
XmlDocument xmlDoc = new XmlDocument();
XmlNode rootNode = xmlDoc.CreateElement("header" );
xmlDoc.AppendChild(rootNode);
like below -
XmlDocument xmlDoc = new XmlDocument();
XmlNode rootNode1 = xmlDoc.CreateElement("header1");
xmlDoc.AppendChild(rootNode1);
XmlNode rootNode = xmlDoc.CreateElement("header2");
rootNode1.AppendChild(rootNode);
Based on your sample output, it's clear that <header1> is the root element and <header2> is inside <header1>, so all you need to do is append <header2> inside <header1> and append the rest of the elements inside <header2>. This code should work
XmlDocument xmlDoc = new XmlDocument();
XmlNode rootNode = xmlDoc.CreateElement("header1");
xmlDoc.AppendChild(rootNode);
XmlNode rootNode2 = xmlDoc.CreateElement("header2");
rootNode.AppendChild(rootNode2);
XmlNode accountNode = xmlDoc.CreateElement("fracc");
accountNode.InnerText = Infracc;
rootNode2.AppendChild(accountNode);
XmlNode txnNode = xmlDoc.CreateElement("txncode");
txnNode.InnerText = Intxncode;
rootNode2.AppendChild(txnNode);
XmlNode reasonNode = xmlDoc.CreateElement("reason");
reasonNode.InnerText = Inreason;
rootNode2.AppendChild(reasonNode);
XmlNode timeoutNode = xmlDoc.CreateElement("timeout");
timeoutNode.InnerText = Intimeout.ToString();
rootNode2.AppendChild(timeoutNode);
XmlNode rdateNode = xmlDoc.CreateElement("rdate");
rdateNode.InnerText = Indate.ToString();
rootNode2.AppendChild(rdateNode);
XmlNode rtimeNode = xmlDoc.CreateElement("rtime");
rtimeNode.InnerText = Intime.ToString();
rootNode2.AppendChild(rtimeNode);
XmlNode seqnoNode = xmlDoc.CreateElement("seqno");
seqnoNode.InnerText = Inseqno.ToString();
rootNode2.AppendChild(seqnoNode);
XmlNode prefixNode = xmlDoc.CreateElement("prefix");
prefixNode.InnerText = Inprefix.ToString();
rootNode2.AppendChild(prefixNode);
XmlNode msgtypeNode = xmlDoc.CreateElement("msgtype");
msgtypeNode.InnerText = Inmsgtype;
rootNode2.AppendChild(msgtypeNode);
XmlNode sendtoNode = xmlDoc.CreateElement("sendto");
sendtoNode.InnerText = Insendto;
rootNode2.AppendChild(sendtoNode);
XmlNode replytoNode = xmlDoc.CreateElement("replyto");
replytoNode.InnerText = Inreplyto;
rootNode2.AppendChild(replytoNode);
xmlDoc.Save("boc.xml");
xmlDoc.Load("boc.xml");
xmlDoc.Save(Console.Out);
return xmlDoc;
Working fiddle: https://dotnetfiddle.net/EevsJq

XDocument to XElement

How do you convert an XDocument to an XElement?
I found the following by searching, but it's for converting between XDocument and XmlDocument, not XDocument and XElement.
public static XElement ToXElement(this XmlElement xmlelement)
{
return XElement.Load(xmlelement.CreateNavigator().ReadSubtree());
}
public static XmlDocument ToXmlDocument(this XDocument xdoc)
{
var xmldoc = new XmlDocument();
xmldoc.Load(xdoc.CreateReader());
return xmldoc;
}
I couldn't find anything to convert an XDocument to an XElement. Any help would be appreciated.
Other people have said it, but here's explicitly a sample to convert XDocument to XElement:
XDocument doc = XDocument.Load(...);
return doc.Root;
XDocument to XmlDocument:
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load(xdoc.CreateReader());
XmlDocument to XDocument
XDocument xDoc = XDocument.Load(new XmlNodeReader(xmlDoc));
To get the root element from the XDocument you use xDoc.Root
Simple conversion from XDocument to XElement
XElement cvtXDocumentToXElement(XDocument xDoc)
{
XElement xmlOut = XElement.Parse(xDoc.ToString());
return xmlOut;
}

Categories