I've been reading through many tutorials and examples, but I'm lost. I have an XML file with this type of data:
<?xml version="1.0"?>
<properties>
<property>
<name>Client Property A</name>
<phone>Client Property A Phone Number</phone>
</property>
<property>
<name>Client Property B</name>
<phone>Client Property B Phone Number</phone>
</property>
<property>
<name>Client Property C</name>
<phone>Client Property C Phone Number</phone>
</property>
</properties>
I'm trying to parse through this data in C# but having no luck at all. I have this:
XmlTextReader xmldata = new XmlTextReader("http://url.to/xml");
XmlNodeList xmllist = doc.GetElementsByTagName("property");
processList( xmllist );
public void processList(XmlNodeList xmllist)
{
// Loop through each property node and list the information
foreach (XmlNode node in xmllist)
{
XmlElement nodeElement = (XmlElement)node;
txtBox.AppendText(nodeElement.GetElementsByTagName("name")[0].InnerText);
txtBox.AppendText(nodeElement.GetElementsByTagName("phone")[0].InnerText);
}
}
But nothing gets output in to my text box. :(
You can use Linq to Xml to get properties from your xml:
var xdoc = XDocument.Load("http://url.to/xml");
foreach(var p in xdoc.Root.Elements("property"))
{
txtBox.AppendText((string)p.Element("name"));
txtBox.AppendText((string)p.Element("phone"));
}
var m_strFilePath = "http://www.google.com/ig/api?weather=12414&hl=it";
string xmlStr;
using(var wc = new WebClient())
{
xmlStr = wc.DownloadString(m_strFilePath);
}
var doc= new XmlDocument();
doc.LoadXml(xmlStr);
XmlNodeList xmllist = doc.SelectNodes("//property");
processList( xmllist );
public void processList(XmlNodeList xmllist)
{
// Loop through each property node and list the information
foreach (XmlNode node in xmllist)
{
XmlElement nodeElement = (XmlElement)node;
txtBox.AppendText(nodeElement.SelectSingleNode("name").InnerText);
txtBox.AppendText(nodeElement.SelectSingleNode("phone").InnerText);
}
}
Related
I can succesfully load the XMl document and traverse the nodes. Once I get the node that I want, I start setting values. How do I deal with nested nodes?
Here is the xml:
<incident>
<id>1234</id>
<number>5678</number>
<name>This is a name</name>
<state>Awaiting Input</state>
<priority>Medium</priority>
<category>
<id>99999</id>
<name>Applications</name>
<default_tags>applications</default_tags>
<parent_id nil="true" />
<default_assignee_id nil="true" />
</category>
Here is some C#:
id = node.SelectSingleNode("id").InnerText; //works fine
number = node.SelectSingleNode("number").InnerText; //works fine
name = node.SelectSingleNode("name").InnerText; //works fine
descHTML = node.SelectSingleNode("description").InnerText; //works fine
desc = node.SelectSingleNode("description_no_html").InnerText; //works fine
state = node.SelectSingleNode("state").InnerText; //works fine
priority = node.SelectSingleNode("priority").InnerText; //works fine
catagoryID = node.SelectSingleNode("category/id").InnerText; // null reference error
catagoryName = node.SelectSingleNode("category/name").InnerText; // null reference error
catagoryTags = node.SelectSingleNode("category/default_tags").InnerText; // null reference error
If you are reading different elements that may or may not exist, use ?. after the SelectSingleNode method. This will ensure you dont get the error Object Reference Not Set to an Instance of an object.
?. in essence checks if there is a value before proceeding to evaluate the next method or proprety.
string xml = #"<incident>
<id>1234</id>
<number>5678</number>
<name>This is a name</name>
<state>Awaiting Input</state>
<priority>Medium</priority>
<category>
<id>99999</id>
<name>Applications</name>
<default_tags>applications</default_tags>
<parent_id nil=""true"" />
<default_assignee_id nil=""true"" />
</category>
</incident>";
XmlDocument doc = new XmlDocument();
doc.LoadXml(xml);
var node = doc.DocumentElement;
var id = node.SelectSingleNode("id")?.InnerText; //works fine
var number = node.SelectSingleNode("number")?.InnerText; //works fine
var name = node.SelectSingleNode("name")?.InnerText; //works fine
var descHTML = node.SelectSingleNode("description")?.InnerText; //ERRORS because there is no description.
var desc = node.SelectSingleNode("description_no_html")?.InnerText; //works fine
var state = node.SelectSingleNode("state")?.InnerText; //works fine
var priority = node.SelectSingleNode("priority")?.InnerText; //works fine
var catagoryID = node.SelectSingleNode("//category/id")?.InnerText; // null reference error
var catagoryName = node.SelectSingleNode("//category/name")?.InnerText; // null reference error
var catagoryTags = node.SelectSingleNode("//category/default_tags")?.InnerText; // null reference error
Console.WriteLine($"name: {name}");
Console.WriteLine($"descHTML: {descHTML}");
Console.WriteLine($"desc: {desc}");
Console.WriteLine($"state: {state}");
Console.WriteLine($"priority: {priority}");
Console.WriteLine($"catagoryID: {catagoryID}");
Console.WriteLine($"catagoryName: {catagoryName}");
Console.WriteLine($"catagoryTags: {catagoryTags}");
Output it prints out
name: This is a name
descHTML:
desc:
state: Awaiting Input
priority: Medium
catagoryID: 99999
catagoryName: Applications
catagoryTags: applications
Code on #dotnetfiddle
I suppose you use the XmlDocument class and CATEGORY NODE is the only item that will have childnodes, so I have this method to go through each element, including subnodes (I hope this helps someone).
string xml =
#"<incident>
<id>1234</id>
<number>5678</number>
<name>This is a name</name>
<state>Awaiting Input</state>
<priority>Medium</priority>
<category>
<id>99999</id>
<name>Applications</name>
<default_tags>applications</default_tags>
<parent_id nil=""true"" />
<default_assignee_id nil=""true"" />
</category>
</incident>";
List<String> innerTextNode = new List<string>();
XmlDocument XmlDoc= new XmlDocument();
XmlDoc.LoadXml(xml);
XmlElement root = XmlDoc.DocumentElement;
XmlNodeList nodes = root.ChildNodes;
XmlNodeList childs;
foreach (XmlNode anode in nodes)
{
// The next is for any NODE that will have childnodes
// bool havechilds = anode.ChildNodes.OfType<XmlNode>().Any(x => x.NodeType != XmlNodeType.Text)
if (!anode.LocalName.Equals("category", StringComparison.CurrentCulture))
{
// The node is only text, no has childnodes
// So capturing InnerText
innerTextNode.Add(anode.InnerText);
}
else
{
childs = nodo.ChildNodes;
foreach (XmlNode childone in childs)
{
// So capturing InnerText
innerTextNode.Add(childone.InnerText);
}
}
}
Here is my xml file
<?xml version="1.0" encoding="ASCII"?>
<Vitals>
<Vendor>General Electric Healthcare</Vendor>
<Model>Pro/Procare</Model>
<Result name="Mean_arterial_pressure">
<Value>86</Value>
<Units name="mmHg"></Units>
<Time_stamp year="2008" month="11" day="18" hour="12" minute="33" second="14"></Time_stamp>
</Result>
<Result name="Systolic_blood_pressure">
<Value>130</Value>
<Units name="mmHg"></Units>
<Time_stamp year="2008" month="11" day="18" hour="12" minute="33" second="14"></Time_stamp>
</Result>
<Result name="Diastolic_blood_pressure">
<Value>67</Value>
<Units name="mmHg"></Units>
<Time_stamp year="2008" month="11" day="18" hour="12" minute="33" second="14"></Time_stamp>
</Result>
<Result name="Pulse">
<Value>73</Value>
<Units name="BPM"></Units>
<Method>blood_pressure</Method>
<Time_stamp year="2008" month="11" day="18" hour="12" minute="33" second="14"></Time_stamp>
</Result>
</Vitals>
and Here is my sourcecode, I having the issue how to get the result name and the value?
private void btnReadXml_Click(object sender, EventArgs e)
{
Hashtable h = new Hashtable();
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load("C:\\dinamap.xml");
XmlNodeList doc_results = xmlDoc.GetElementsByTagName("Vitals/Vendor/Model/Result[#name='Systolic_blood_pressure']");
foreach (XmlNode pnode in doc_results)
{
foreach (XmlNode cnode in pnode.ChildNodes)
{
if (cnode.Name == "Value")
{
h.Add(pnode.Attributes["name"].InnerText + cnode.Name, cnode.Attributes["name"].InnerText);
}
else
{
h.Add(pnode.Attributes["name"].InnerText + "_" + cnode.Name, cnode.InnerText);
}
}
}
}
May I know what wrong of my code? always can't get the value.
I need to get the value from xml file.
On line 5, your xPath specify Model is a child of Vendor while Vendor contains only a string (<Vendor>General Electric Healthcare</Vendor>).
Moreover, to navigate with xPath i advice you to use SelectNodes function.
Try this instead :
XmlNodeList doc_results = xmlDoc.SelectNodes("/Vitals/Model/Result[#name='Systolic_blood_pressure']");
It'd be easier if you used LINQ to XML for this.
var doc = XDocument.Load("path/to/xml");
var results =
from result in doc.Descendants("Result")
select new
{
Name = (string) result.Attribute("name"),
Value = (string) result.Element("Value"),
Units = (string) result.Element("Units").Attribute("name")
};
You could then filter by Name if you needed:
var sysBp = results.Single(x => x.Name == "Systolic_blood_pressure");
See this fiddle for a working demo.
You're currently trying to retrieve the "name" attribute of the child node, which it does not actually have in the case of your value node. If you use cnode.Value you can get the contents of a text note.
Also, Result is not a child of Model, which is not a child of Vendor. You'll either want to properly make them children or change the path you're setting for doc_results
private void btnReadXml_Click(object sender, EventArgs e)
{
var doc = XDocument.Load("C:\\dinamap.xml");
var results = from result in doc.Descendants("Result")
select new
{
Name = (string)result.Attribute("name"),
Value = (string)result.Element("Value"),
Units = (string)result.Element("Units").Attribute("name")
};
foreach (var result in results)
{
MessageBox.Show("{result.Name}: {result.Value} {result.Units}");
}
}
I have the following XML type file
<root>
<info version_id=... product_id=... account_id=...>
<CRM>
<result key=... value=...>
<result key=... value=...>
....
</CRM>
<result key=... value=....>
</info>
<info version_id=... product_id=... account_id=...>
<CRM>
<result key=... value=...>
<result key=... value=...>
....
</CRM>
<result key=... value=....>
</info>
</root>
I need for each "info" nodes to create the following list:
list(account+product, key, value)
And I must take only "key" and "value" information that are part of the CRM node.
So the close I want was with this code
string[] directoryXml = Directory.GetFiles(directory);
var listxmlresult = new List<XmlResultNode>();
foreach (var xmlfile in directoryXml)
{
var docxml = new XmlDocument();
docxml.Load(xmlfile);
XmlNodeList nodesInfo = docxml.SelectNodes("//info");
XmlNodeList nodesResult = docxml.SelectNodes("//info/CRM/result");
foreach (XmlNode info in nodesInfo)
{
string VersionId = info.Attributes["version_id"].Value;
string ProductId = info.Attributes["product_id"].Value;
string AccountId = info.Attributes["account_id"].Value;
string AccountProductId = AccountId + " : " + ProductId;
// verify that CRM node exist
if (docxml.SelectSingleNode("//info/CRM") == null)
{
//To do log info that CRM node is not available for the specific file
}
foreach (XmlNode result in nodesResult)
{
//To do verfiy value is empty
string Key = result.Attributes["key"].Value;
string Value = result.Attributes["value"].Value;
if (Value.Length != 0)
{
var listXmlResultTemp = new XmlResultNode(AccountProductId, Key, Value);
listxmlresult.Add(listXmlResultTemp);
}
}
}
}
But this code return list with all "key" "value" for each "accountproduct".
I cannot manage in my second loop to just read the current node.
I tried several xpath possibility but I cannot manage to take the current position with XmlNodeList.
Tks
It isn't very clear what you're trying to achieve as posted. I think you want to change the inner loop this way :
foreach (XmlNode result in info.SelectNodes("./CRM/result"))
{
string Key = result.Attributes["key"].Value;
string Value = result.Attributes["value"].Value;
.....
.....
}
I would like to get XmlNodeList from a huge XML file.
Conditions:
I have a List of unique ID values, say IDList
Case I: Collect all the nodes where element called ID has value from IDList.
Case II: Collect all nodes where one of the attribute called idName of element ID has value from IDList.
In short, extract only the nodes which match with the values given in the IDList.
I did this using some loops like load this XML to XmlDocument to iterate over all nodes and ID value but what I am looking for is some sophisticated method to do it faster and in quick way.
Because looping isn't a solution for a large XML file.
My try:
try
{
using (XmlReader reader = XmlReader.Create(URL))
{
XmlDocument doc = new XmlDocument();
doc.Load(reader);
XmlNodeList nodeList = doc.GetElementsByTagName("idgroup");
foreach (XmlNode xn in nodeList)
{
string id = xn.Attributes["id"].Value;
string value = string.Empty;
if (IDList.Contains(id))
{
value = xn.ChildNodes[1].ChildNodes[1].InnerText; // <value>
if (!string.IsNullOrEmpty(value))
{
listValueCollection.Add(value);
}
}
}
}
}
catch
{}
XML (XLIFF) structure:
<XLIFF>
<xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.2">
<file date="2013-07-17">
<body>
<id idName="test_001" >
<desc-group name="test_001">
<desc type="text"/>
</desc-group>
<result-unit idName="test_001_text">
<source>abcd</source>
<result>xyz</result>
</result-unit>
</id>
</body>
</file>
</xliff>
Collect all the nodes like above where idName matches.
EDIT
This is a test that can parse the example you are giving. It attempts to reach the result node directly, so that it stays as efficient as possible.
[Test]
public void TestXPathExpression()
{
var idList = new List<string> { "test_001" };
var resultsList = new List<string>();
// Replace with appropriate method to open your URL.
using (var reader = new XmlTextReader(File.OpenRead("fixtures\\XLIFF_sample_01.xlf")))
{
var doc = new XmlDocument();
doc.Load(reader);
var root = doc.DocumentElement;
// This is necessary, since your example is namespaced.
var nsmgr = new XmlNamespaceManager(doc.NameTable);
nsmgr.AddNamespace("x", "urn:oasis:names:tc:xliff:document:1.2");
// Go directly to the node from which you want the result to come from.
foreach (var nodes in idList
.Select(id => root.SelectNodes("//x:file/x:body/x:id[#idName='" + id + "']/x:result-unit/x:result", nsmgr))
.Where(nodes => nodes != null && nodes.Count > 0))
resultsList.AddRange(nodes.Cast<XmlNode>().Select(node => node.InnerText));
}
// Print the resulting list.
resultsList.ForEach(Console.WriteLine);
}
You can extract only those nodes you need by using an XPath query. A brief example on how you 'd go about it:
using (XmlReader reader = XmlReader.Create(URL))
{
XmlDocument doc = new XmlDocument();
doc.Load(reader);
foreach(var id in IDList) {
var nodes = doc.SelectNodes("//xliff/file/body/id[#idName='" + id + "']");
foreach(var node in nodes.Where(x => !string.IsNullOrEmpty(x.ChildNodes[1].ChildNodes[1].InnerText)))
listValueCollection.Add(node.ChildNodes[1].ChildNodes[1].InnerText);
}
}
The xpath expression is of course an example. If you want, you can post an example of your XML so I can give you something more accurate.
I have been trying to read an xml file. I have to extract value of nodes "Date" and "Name", but the problem is, they might appear at any level in XML hierarchy.
So when I try with this code,
XmlDocument doc = new XmlDocument();
doc.Load("test1.xml");
XmlElement root = doc.DocumentElement;
XmlNodeList nodes = root.SelectNodes("//*");
string date;
string name;
foreach (XmlNode node in nodes)
{
date = node["date"].InnerText;
name = node["name"].InnerText;
}
and the XML file is ::
<?xml version="1.0" encoding="utf-8"?>
<root>
<child>
<name>Aravind</name>
<date>12/03/2000</date>
</child>
</root>
the above code errors out, as <name> and <date> are not immediate child Elements of root.
is it possible to assume that parent/root nodes are unknown and just with the name of the nodes, copy the values ??
Depending on the exception you are getting, this may or may not be the exact solution. However, I would definitely check that date and name exist before doing a .InnerText on them.
foreach (XmlNode node in nodes)
{
dateNode = node["date"];
if(dateNode != null)
date = dateNode.InnerText;
// etc.
}
I would read up on XPATH and XPATH for C# to do this more efficiently
http://support.microsoft.com/kb/308333
http://www.w3schools.com/XPath/xpath_syntax.asp
Here's a little method that should allow you to get the innerText easily.
function string GetElementText(string xml, string node)
{
XPathDocument doc = new XPathDocument(xml);
XPathNavigator nav = doc.CreateNavigator();
XPathExpression expr = nav.Compile("//" + node);
XPathNodeIterator iterator = nav.Select(expr);
while (iterator.MoveNext())
{
// return 1st but there could be more
return iterator.Current.Value;
}
}
Try to use LINQ:
string xml = #"<?xml version='1.0' encoding='utf-8'?>
<root>
<date>12/03/2001</date>
<child>
<name>Aravind</name>
<date>12/03/2000</date>
</child>
<name>AS-CII</name>
</root>";
XDocument doc = XDocument.Parse(xml);
foreach (var date in doc.Descendants("date"))
{
Console.WriteLine(date.Value);
}
foreach (var date in doc.Descendants("name"))
{
Console.WriteLine(date.Value);
}
Console.ReadLine();
The Descendants method allows you to get all the elements that have a specified name.