Cannot select an XML node with XML namespace using SelectSingleNode method - c#

I have the following XML
<?xml version="1.0" encoding="UTF-8"?>
<form:Documents xmlns:form="http://www.example.com/file.xsd" xmlns:addData="http://www.example.com/file2.xsd">
<_colored:_colored addData:DocumentState="Correct" xmlns:_colored="http://www.example.com/colored.xsd">
<_colored>
<_Field1>PB8996MT</_Field1>
</_colored>
</_colored:_colored>
</form:Documents>
I try to get the inner text of the _Field1 tag by writing the following C# code:
XmlDocument xmlDocument = new XmlDocument();
xmlDocument.Load(filePath);
string fieldValue = xmlDocument.SelectSingleNode("/form:Documents/_colored:_colored/_colored/_Field1").InnerText;
And when I run the application I get the following exception:
Unhandled Exception: System.Xml.XPath.XPathException: Namespace Manager or XsltContext needed.
This query has a prefix, variable, or user-defined function.

You should declare the namespace prefix using an XmlNamespaceManager before you can use it in XPath expressions.
XmlDocument doc = new XmlDocument ();
doc.Load("/Users/buttercup/Projects/23564466/kram.xml");
XmlNamespaceManager nmspc = new XmlNamespaceManager(doc.NameTable);
nmspc.AddNamespace("form", "http://www.example.com/file.xsd");
nmspc.AddNamespace("addData", "http://www.example.com/file2.xsd");
nmspc.AddNamespace("_colored", "http://www.example.com/colored.xsd");
string fieldValue = doc.SelectSingleNode("/form:Documents/_colored:_colored/_colored/_Field1", nmspc).InnerText;
http://msdn.microsoft.com/en-us/library/system.xml.xmlnamespacemanager.aspx

LINQ to Xml can make things easier:
XDocument doc = XDocument.Load(filePath);
var value = doc.Descendants("_Field1").First().Value;

Related

get contents from inner xml with xml parsing in c#?

I have a service which returns the below xml as string.I am using Xdocument parse method and XmlDocument load methods to convert the string to xml. but i want to parse and get the status and i_numer which i need to use for further processing.can some one point me in right direction or give some hints.below is the xml i am using.
i tried the innerxml property from the Xdocument and XmlDocument which is returning the whole "" element and this is not what i needed.
<Report>
<Incidentreport Company="company1" ID="sample">
<status i_number="12345678" status="sucessful" />
</Incidentreport>
</Report>
The following should work:
string str = [string of xml goes here];
string i_number = string.Empty;
XmlDocument doc = new XmlDocument();
doc.Load(str);
XmlNode node = doc.SelectSingleNode("//status");
i_number = node.Attributes["i_number"].Value;
You can use SelectSingleNode() which accept XPath parameter to get the target attribute value in one go * :
var raw = #"<Report>
<Incidentreport Company='company1' ID='sample'>
<status i_number='12345678' status='sucessful' />
</Incidentreport>
</Report>";
var doc = new XmlDocument();
doc.LoadXml(raw);
var result = doc.SelectSingleNode("/Report/Incidentreport/status/#i_number");
Console.WriteLine(result.Value);
dotnetfiddle demo
*) notice how XML attribute can be referenced by using #attribute_name syntax in XPath

How to get innertext from xml node that has '\' along with other characters when fetched as string

Hi i am facing an issue extracting innertext from an xml script saved as varchar2 in my oracle database.
While fetching i am getting the xml in the following format:
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<SpecificAction xmlns=\"http://www.xyz.com/schemas/core/caut\">action to take</SpecificAction>"
the following xml is fetched using the code below:
instance.cautDescription = records.GetStringOrDefault("SPEC_ACTION");
the field SPEC_ACTION is of VARCHAR2(4000 BYTE) type.
due to the presence of \ character in the xml from database i am not able to extract the inner text withing the Tag. I tried the following code for fetching the inner text:
string s = instance.cautDescription;
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.LoadXml(s);
XmlNode specificAction = xmlDoc.DocumentElement.SelectSingleNode("/SpecificAction");
string specific = specificAction.InnerText;
xmlString = specificAction.InnerText;
return xmlString;
My code is returning null can this be avoided if so how , any support would be really helpful.
This is classic problem when working with XML having default namespace. In XML, when you have default namespace (namespace without prefix, like xmlns="...."), all elements without prefix considered in default namespace. But in XPath, all elements without prefix considered has no namespace. To bridge this different paradigm, you need to declare a prefix that point to default namespace URI and use it in XPath :
var nsManager = new XmlNamespaceManager(xmlDoc.NameTable);
nsManager.AddNamespace("ns", xmlDoc.DocumentElement.NamespaceURI);
XmlNode specificAction = xmlDoc.DocumentElement.SelectSingleNode("/ns:SpecificAction", nsManager);
string specific = specificAction.InnerText;
Since the "SpecificAction" node has a namespace, you will need to supply a namespace manager.
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.LoadXml(s);
XmlNamespaceManager ns = new XmlNamespaceManager(xmlDoc.NameTable);
ns.AddNamespace("xyz", "http://www.xyz.com/schemas/core/caut");
XmlNode specificAction = xmlDoc.SelectSingleNode("/xyz:SpecificAction", ns);
return specificAction.InnerText;

Reading attribute of an XML file

I have this XML file, I can read all the the nodes
<?xml version="1.0" encoding="UTF-8"?>
<cteProc xmlns="http://www.portalfiscal.inf.br/cte" versao="1.04">
<CTe xmlns="http://www.portalfiscal.inf.br/cte">
<infCte versao="1.04" ID="CTe3512110414557000014604"></infCte>
</CTe>
</cteProc>
I have tried reading this using C#
string chavecte;
string CaminhoDoArquivo = #"C:\Separados\13512004-procCTe.xml";
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load(CaminhoDoArquivo); //Carregando o arquivo
chavecte = xmlDoc.SelectSingleNode("infCTe")
.Attributes.GetNamedItem("Id").ToString();
but something is wrong with this code.
If you want to use Linq To Xml
var xDoc = XDocument.Load(CaminhoDoArquivo);
XNamespace ns = "http://www.portalfiscal.inf.br/cte";
var chavecte = xDoc.Descendants(ns+"infCte").First().Attribute("id").Value;
PS: I am assuming your xml's invalid line is as
<infCte versao="1.04" id="CTe3512110414557000014604"></infCte>
replace
chavecte = xmlDoc.SelectSingleNode("infCTe").Attributes.GetNamedItem("Id").Value;
with
XmlNamespaceManager nsmgr = new XmlNamespaceManager(xmlDoc.NameTable);
nsmgr.AddNamespace("ab", "http://www.portalfiscal.inf.br/cte");
chavecte = xmlDoc.SelectSingleNode("//ab:infCte", nsmgr)
.Attributes.GetNamedItem("Id").Value;
I've also noticed that infCte doesn't have the ID attribute properly defined in your xml
Another possible solution is:
string CaminhoDoArquivo = #"C:\Separados\13512004-procCTe.xml";
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load(CaminhoDoArquivo); //Carregando o arquivo
// Select the node you're interested in
XmlNode node = xmlDoc.SelectSingleNode("/cteProc/CTe/infCte");
// Read the value of the attribute "ID" of that node
string chavecte = node.Attributes["ID"].Value;

Get nodes from xml files

How to parse the xml file?
<?xml version="1.0" encoding="UTF-8"?>
<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<sitemap>
<loc>link</loc>
<lastmod>2011-08-17T08:23:17+00:00</lastmod>
</sitemap>
<sitemap>
<loc>link</loc>
<lastmod>2011-08-18T08:23:17+00:00</lastmod>
</sitemap>
</sitemapindex>
I am new to XML, I tried this, but it seems to be not working :
XmlDocument xml = new XmlDocument(); //* create an xml document object.
xml.Load("sitemap.xml");
XmlNodeList xnList = xml.SelectNodes("/sitemapindex/sitemap");
foreach (XmlNode xn in xnList)
{
String loc= xn["loc"].InnerText;
String lastmod= xn["lastmod"].InnerText;
}
The problem is that the sitemapindex element defines a default namespace. You need to specify the namespace when you select the nodes, otherwise it will not find them. For instance:
XmlDocument xml = new XmlDocument();
xml.Load("sitemap.xml");
XmlNamespaceManager manager = new XmlNamespaceManager(xml.NameTable);
manager.AddNamespace("s", "http://www.sitemaps.org/schemas/sitemap/0.9");
XmlNodeList xnList = xml.SelectNodes("/s:sitemapindex/s:sitemap", manager);
Normally speaking, when using the XmlNameSpaceManager, you could leave the prefix as an empty string to specify that you want that namespace to be the default namespace. So you would think you'd be able to do something like this:
// WON'T WORK
XmlDocument xml = new XmlDocument();
xml.Load("sitemap.xml");
XmlNamespaceManager manager = new XmlNamespaceManager(xml.NameTable);
manager.AddNamespace("", "http://www.sitemaps.org/schemas/sitemap/0.9"); //Empty prefix
XmlNodeList xnList = xml.SelectNodes("/sitemapindex/sitemap", manager); //No prefixes in XPath
However, if you try that code, you'll find that it won't find any matching nodes. The reason for this is that in XPath 1.0 (which is what XmlDocument implements), when no namespace is provided, it always uses the null namespace, not the default namespace. So, it doesn't matter if you specify a default namespace in the XmlNamespaceManager, it's not going to be used by XPath, anyway. To quote the relevant paragraph from the Official XPath Specification:
A QName in the node test is expanded into an expanded-name using the
namespace declarations from the expression context. This is the same
way expansion is done for element type names in start and end-tags
except that the default namespace declared with xmlns is not used: if
the QName does not have a prefix, then the namespace URI is null (this
is the same way attribute names are expanded). It is an error if the
QName has a prefix for which there is no namespace declaration in the
expression context.
Therefore, when the elements you are reading belong to a namespace, you can't avoid putting the namespace prefix in your XPath statements. However, if you don't want to bother putting the namespace URI in your code, you can just use the XmlDocument object to return the URI of the root element, which in this case, is what you want. For instance:
XmlDocument xml = new XmlDocument();
xml.Load("sitemap.xml");
XmlNamespaceManager manager = new XmlNamespaceManager(xml.NameTable);
manager.AddNamespace("s", xml.DocumentElement.NamespaceURI); //Using xml's properties instead of hard-coded URI
XmlNodeList xnList = xml.SelectNodes("/s:sitemapindex/s:sitemap", manager);
Sitemap has 2 sub nodes "loc" and "lastmod". The nodes that you are accessing are "name" and "url". that is why you are not getting any result. Also in your XML file the last sitemap tag is not closed properly with a corresponding Kindly try xn["loc"].InnerText and see if you get the desired result.
I would definitely use LINQ to XML instead of the older XmlDocument based XML API. You can accomplish what you are looking to do using the following code. Notice, I changed the name of the element that I am trying to get the value of to 'loc' and 'lastmod', because this is what is in your sample XML ('name' and 'url' did not exist):
XElement element = XElement.Parse(XMLFILE);
IEnumerable<XElement> list = element.Elements("sitemap");
foreach (XElement e in list)
{
String LOC= e.Element("loc").Value;
String LASTMOD = e.Element("lastmod").Value;
}

XML CDATA Encoding

I am trying to build an XML document in C# with CDATA to hold the text inside an element. For example..
<email>
<![CDATA[test#test.com]]>
</email>
However, when I get the InnerXml property of the document, the CDATA has been reformatted so the InnerXml string looks like the below which fails.
<email>
<![CDATA[test#test.com]]>
</email>
How can I keep the original format when accessing the string of the XML?
Cheers
Don't use InnerText: use XmlDocument.CreateCDataSection:
using System;
using System.Xml;
public class Test
{
static void Main()
{
XmlDocument doc = new XmlDocument();
XmlElement root = doc.CreateElement("root");
XmlElement email = doc.CreateElement("email");
XmlNode cdata = doc.CreateCDataSection("test#test.com");
doc.AppendChild(root);
root.AppendChild(email);
email.AppendChild(cdata);
Console.WriteLine(doc.InnerXml);
}
}
With XmlDocument:
XmlDocument doc = new XmlDocument();
XmlElement email = (XmlElement)doc.AppendChild(doc.CreateElement("email"));
email.AppendChild(doc.CreateCDataSection("test#test.com"));
string xml = doc.OuterXml;
or with XElement:
XElement email = new XElement("email", new XCData("test#test.com"));
string xml = email.ToString();
See XmlDocument::CreateCDataSection Method for information and examples how to create CDATA nodes in an XML Document

Categories