how to read value from XML? - c#

The data:
<sys>
<id>SCPUCLK</id>
<label>CPU Clock</label>
<value>2930</value>
</sys>
<sys>
<id>CPUTEMP</id>
<label>CPU Temp</label>
<value>39</value>
</sys>
This is the code that I'm using to read the data:
XmlDocument document = new XmlDocument();
document.LoadXml(data);
XmlElement node = document.SelectSingleNode("/sys/value") as XmlElement;
Console.WriteLine("node = " + node);
The issue: Console.WriteLine("node = " + node); doesn't give me any output besides node: but no actual value like 2930 from the sample above.
Thanks

use node.value ie., XmlElement.value

As an alternative to using XmlDocument, you can also use LINQ to XML (which is my preference):
using System.Xml.Linq;
XDocument xDoc = new XDocument();
// Parse loads the XDocument with XML from a string
xDoc = XDocument.Parse(data);
string node = (from x in xDoc.Root.Elements("value")
select x.Value).SingleOrDefault();
Console.WriteLine("node = " + node);
Nothing wrong with using XmlDocument, especially for what you're doing, but you might want to check out LINQ to XML when you get a chance, as I find it a lot easier to work with than XmlDocument.
If you want to get all the "value" elements, simply remove the SingleOrDefault() from the query, and then you can loop through the result, like this:
var nodes = from x in xDoc.Root.Elements("value")
select x.Value;
foreach (var node in nodes)
{
Console.WriteLine("node = " + node);
}
Here's a site worth checking out:
LINQ to XML - 5 Minute Overview

Related

Reading a XML file using C# not working for some xml files

I need to read following xml file. I've used XML and LINQ but neither of them show any values.I can't find any mistakes on the code.
I've followed This example it's working fine with XML that shown there.
<dataSet>
<transactions>
<trans>1</trans>
<Amount>1000</Amount>
<Name>1000</Name>
<Type>Income</Type>
<Date>2022-04-21T00:00:00+05:30</Date>
</transactions>
</dataSet>
I've use this code.
using System;
using System.Xml;
namespace ReadXMLInCsharp
{
class Program
{
static void Main(string[] args)
{
//create XMLDocument object
XmlDocument xmlDoc = new XmlDocument();
//returns url of main directory which contains "/bin/Debug"
var url = System.IO.Path.GetDirectoryName(
System.Reflection.Assembly.GetExecutingAssembly().GetName().CodeBase);
//correction in path to point it in Root directory
var mainpath = ("F:\\Education\\Test\\new.xml");
//load xml file
xmlDoc.Load(mainpath);
XmlNodeList nodeList = xmlDoc.DocumentElement.SelectNodes("/dataSet/transactions");
var NodeStr = "";
foreach (XmlNode node in nodeList)
{
NodeStr = NodeStr + "\nTransaction " + node.SelectSingleNode("trans").InnerText;
}
Console.WriteLine(NodeStr);
}
}
}
I'd note this sort of thing is generally much nicer in the more modern LINQ to XML API. It might look something like this (though there are many ways to skin a cat):
XNamespace ns = "tempuri.org/DataSet.xsd";
var doc = XDocument.Load(mainpath);
var lines =
from dataSet in doc.Elements(ns + "dataSet")
from transactions in dataSet.Elements(ns + "transactions")
from trans in transactions.Elements(ns + "trans")
select $"Transaction {trans.Value}";
var nodeStr = string.Join(Environment.NewLine, lines);
Console.WriteLine(nodeStr);
See this fiddle for a working demo.
Your xml DataSet node has a namespace attribute, so you'll either need to remove it or use XmlNamespaceManager to handle it. Here is a fiddle with both:
https://dotnetfiddle.net/EOXtBN
In the first, I load the xml into a string, then use .Replace:
xmlDoc.LoadXml(getXML().Replace(" xmlns='tempuri.org/DataSet.xsd'", ""));
Probably not optimal, because that namespace is probably there for a reason, but it's possible this could be an option for you. It's the one I got to work first.
Second, I use XmlNamespaceManager to handle the parsing. It doesn't add that much overhead:
xmlDoc.LoadXml(getXML());
XmlNamespaceManager nsmgr = new XmlNamespaceManager(xmlDoc.NameTable);
nsmgr.AddNamespace("ns", "tempuri.org/DataSet.xsd");
nodeList = xmlDoc.DocumentElement.SelectNodes("//ns:DataSet//ns:transactions", nsmgr);
foreach (XmlNode node in nodeList) {
NodeStr = NodeStr + "\nTransaction " + node.SelectSingleNode("ns:trans", nsmgr).InnerText;
}
Also, bear in mind that you can just include ns:trans in the xpath for the nodelist, like so:
nodeList = xmlDoc.DocumentElement.SelectNodes("//ns:DataSet//ns:transactions//ns:trans", nsmgr);
foreach (XmlNode node in nodeList) {
NodeStr = NodeStr + "\nTransaction " + node.InnerText;
}
Console.WriteLine(NodeStr);
And you can use += to clean it up a little more, too:
nodeList = xmlDoc.DocumentElement.SelectNodes("//ns:DataSet//ns:transactions//ns:trans", nsmgr);
foreach (XmlNode node in nodeList) {
NodeStr += "\nTransaction " + node.InnerText;
}
Console.WriteLine(NodeStr);
Let me know if this works for you.
Your XML file have and you are parsing it via dataset. "s" is in lowercasein your code. set it to
XmlNodeList nodeList = xmlDoc.DocumentElement.SelectNodes("/dataSet/transactions");
Also check the path to your XML is correct.

XmlDoc SelectNodes selecting entire document

I have a simple XML doc with no Namespace
Here is the code I wrote in C# to search for a particular element based on Name.
public XmlElement SearchXML(string name)
{
XmlDocument xDoc = new XmlDocument();
string filePath = ConfigurationManager.AppSettings["path"];
xDoc.Load(filePath);
string xQryStr = "//NewPatient[Name='" + name + "']";
xDoc.SelectNodes(xQryStr);
XmlElement xmlEle = xDoc.DocumentElement;
return xmlEle;
}
The XML document is as follows
When I try to call the method SearchXML and pass Dennis as the arguement, instead of returning the xml element containing only the specific elements, it returns the entire document.
Where am I possibly erring?
Any help appreciated.
xDoc.SelectNodes(xQryStr) does not mutate the original doc. You need to store the return value of this method call and return that instead.
ATM you're simply returning the root element of the original doc (i.e. the entire tree)
EDIT
In answer to your comment, you could fish the first matched XmlElement as follows:
xDoc.SelectNodes(xQryStr).OfType<XmlElement>().FirstOrDefault()
This will return either null or an XmlElement
If you want to select a list of nodes based on an XPath expression, you need to use .SelectNodes in this fashion:
public XmlElement SearchXML(string name)
{
XmlDocument xDoc = new XmlDocument();
string filePath = ConfigurationManager.AppSettings["path"];
xDoc.Load(filePath);
string xQryStr = "//NewPatient[Name='" + name + "']";
XmlNodeList listOfNodes = xDoc.SelectNodes(xQryStr);
foreach(XmlNode node in listOfNodes
{
// do something with that list of XML nodes you've selected....
// XmlElement xmlEle = node;
// return xmlEle;
}
}
The call to .SelectNodes(xpath) returns a list of matching XML nodes (see the MSDN documentation on XmlDocument.SelectNodes) - once you have that list, you can iterate over the matched nodes and do something with them....
Or if you're expecting only a single XML node to match your XPath expression, you can use .SelectSingleNode, too:
string xQryStr = "//NewPatient[Name='" + name + "']";
XmlNode matchedNode = xDoc.SelectSingleNode(xQryStr);
if(matchedNode != null)
{
// do something with that list of XML nodes you've selected....
return matchedNode;
}
can you change
string xQryStr = "//NewPatient[Name='" + name + "']";
to
xQryStr = "/NewPatient[Name='" + name + "']";
see the below link
http://www.csharp-examples.net/xml-nodes-by-name/

NodeList.SelectSingleNode() syntax

Having problems getting NodeList.SelectSingleNode() to work properly.
My XML looks like this:
<?xml version="1.0" encoding="ISO-8859-1" standalone="yes"?>
<inm:Results xmlns:inm="http://www.namespace.com/1.0">
<inm:Recordset setCount="18254">
<inm:Record setEntry="0">
<!-- snip -->
<inm:Image>fileName.jpg</inm:Image>
</inm:Record>
</inm:Recordset>
</inm:Results>
The data is a long series of <inm:Record> entries.
I open the doc and get create a NodeList object based on "inm:Record". This works great.
XmlDocument xdoc = new XmlDocument();
xdoc.Load(openFileDialog1.FileName);
XmlNodeList xRecord = xdoc.GetElementsByTagName("inm:Record");
I start looping through the NodeList using a for loop. Before I process a given entry, I want to check and see if the <inm:Image> is set. I thought it would be super easy just to do
string strImage = xRecord[i].SelectSingleNode("inm:Image").InnerText;
My thinking being, "For the XRecord that I'm on, go find the <inm:Image> value ...But this doesn't work as I get the exception saying that I need a XmlNameSpaceManager. So, I tried to set that up but could never get the syntax right.
Can someone show me how to use the correct XmlNameSpaceManager syntax in this case.
I've worked around the issue for now by looping through all of the childNodes for a given xRecord, and checking the tag once I loop around to it. I would like to check that value first to see if I need to loop over that <inm:Record> entry at all.
No need to loop through all the Record elements, just use XPath to specify the subset that you want:
XmlDocument xdoc = new XmlDocument();
xdoc.Load(openFileDialog1.FileName);
XmlNamespaceManager manager = new XmlNamespaceManager(xdoc.NameTable);
manager.AddNamespace("inm", "http://www.inmagic.com/webpublisher/query");
XmlNodeList nodes = xdoc.SelectNodes("/inm:Results/inm:Recordset/inm:Record[inm:Image != '']", manager);
Using the LINQ to XML libraries, here's an example for retrieving that said node's value:
XDocument doc = XDocument.Load(openFileDialog1.FileName);
List<XElement> docElements = doc.Elements().ToList();
XElement results = docElements.Elements().Where(
ele => ele.Name.LocalName == "Results").First();
XElement firstRecord = results.Elements().Where(
ele => ele.Name.LocalName == "Record").First();
XElement recordImage = firstRecord .Elements().Where(
ele => ele.Name.LocalName == "Image").First();
string imageName = recordImage.Value;
Also, by the way, using Hungarian notation for a type-checked language is overkill. You don't need to prepend string variables with str when it will always be a string.
XmlNamespaceManager nsMgr = new XmlNamespaceManager(xdoc.NameTable);
string strImage = xRecord[i].SelectSingleNode("inm:Image",nsMgr).InnerText;
Should do it.
Using this Xml library, you can get all the records that have an Image child element with this:
XElement root = XElement.Load(openFileDialog1.FileName);
XElement[] records = root.XPath("//Record[Image]").ToArray();
If you want to be sure that the Image child contains a value, it can be expressed like this:
XElement[] records = root.XPath("//Record[Image != '']").ToArray();

Read Child nodes including text and node using XPath from XElement ? LinQ

Using old way of doing via XmlDocument,
string xmlstring = "<root><profile><Name>John</Name><Age>23</Age></profile></root>";
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.LoadXml(xmlstring);
string childNodes = xmlDoc.SelectSingleNode("root/Profile").InnerXml;
// output of childNodes would be => "<Name>John</Name><Age>23</Age>";
what is the equivalent of doing the above execution in LinQ when you have XElement variable. I see XPathSelectElement method in XElement but it doesn't return the child nodes + Child nodes text. Any Ideas?
I wouldn't use XPath at all for this. I'd use:
XDocument doc = XDocument.Parse(xmlString);
var nodes = doc.Root
.Elements("profile")
.DescendantsAndSelf();
That give the profile nodes and all their descendants. It's not really clear what you're trying to do with the results, but if you can give more details I should be able to come up with the appropriate code.

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.

Categories

Resources