Loop through a specific node of XML with XmlNodeList - c#

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;
.....
.....
}

Related

C# - Can I select the value of an XML attribute by searching for a second attribute?

I want to select the value of the "data" attribute where the "key" attribute matches a specific search.
The XML file will look like this.
<connections>
<production>
<connection key="KEY1" data="value1" />
<connection key="KEY2" data="value2" />
<connection key="KEY3" data="value3" />
</production>
</connections>
So is there a way to return the value of the data attribute by searching for key = key1 for example?
You could do something like this if you wanted to avoid using XPath.
using System.Xml.Linq;
var xmlStr = File.ReadAllText("Testfile.xml");
XElement root = XElement.Parse(xmlStr);
var data = root.Element("production")
.Elements().Where(x => x.Attribute("key").Value == "KEY1")
.Select(x=>x.Attribute("data").Value)
.First();
Console.WriteLine(data);
Try this, using System.Xml you can read the xml file in question and iterate through the nodes to look for your value.
private void YOUR_METHOD_NAME()
{
// Call GetXml method which returns the result in the form of string
string result = GetXml("xmlfile.xml", "KEY2");
Debug.WriteLine(result);
}
private string GetXml(string filePath, string searchKey)
{
XmlDocument doc = new XmlDocument();
doc.Load(filePath);
XmlNodeList nodes = doc.SelectSingleNode("//connections/production").ChildNodes;
string output = string.Empty;
foreach (XmlNode node in nodes)
{
if (node.Attributes["key"].Value == searchKey)
{
output = node.Attributes["data"].Value;
}
else
{
continue;
}
}
return output;
}

How to loop through XML node and its child node to get the SQL and Mail Address

I am trying to read an xml with the following format given below in C# . I have to store each sql Text and mailbody content and each email address under customer tag into a string variable for further process. The XML format I have given below
<?xml version="1.0" encoding="utf-8" ?>
<Queries>
<Customer>
<SQL ID="GYSQL">
Select * from customer where code ='GYSQL'
</SQL>
<MailBody>
Please find the Report GY
</MailBody>
<Address>customer1#mail.com</Address>
<Address>customer2#mail.com</Address>
</Customer>
<Customer>
<SQL ID="TSSQL">
Select * from customer where code ='TSSQL'
</SQL>
<MailBody>
Please find the Report TS
</MailBody>
<Address>customer3#mail.com</Address>
<Address>customer4#mail.com</Address>
<Address>customer5#mail.com</Address>
</Customer>
</Queries>
I have to loop through Each Customer Tag
var xml = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetEntryAssembly().Location) + "\\xml\\sql.xml";
XmlDocument xml1 = new XmlDocument();
xml1.Load(xml);
XmlNodeList list = xml1.SelectNodes(#"//Customer");
foreach (XmlNode xn in list)
{
string Sql = Get the text from SQL tag under Customer
string mailbody = Get the text under tag Customer\Mailbody
//Here I have to get each email address in a loop in a string variable
}
To keep going with XPath expressions, you could do something like this:
foreach (XmlNode xn in list)
{
// Find the first child node of 'xn' with name "SQL"
var sqlForThisCustomer = xn.SelectSingleNode("SQL")?.InnerText;
// Same for "MailBody"
var mailBodyForThisCustomer = xn.SelectSingleNode("MailBody")?.InnerText;
var addressList = xn.SelectNodes("Address");
foreach(XmlNode adr in addressList) {
var currentAddress = adr.InnerText;
}
}
For this sort of work I usually prefer XDocument:
var doc = XDocument.Parse(xmlstring);
var customers = doc.Root
.Elements("Customer")
.Select(c => new {
SQL = c.Element("SQL")?.Value,
MailBody = c.Element("MailBody")?.Value,
Addresses = c.Elements("Address").Select(x => x.Value).ToList()
})
.ToList();

C# Trying to get XML inner text for nested node

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

Xml file with C# can't get the value

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

Parse through XML

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

Categories