Using Xpath and reading values from same attribute name - c#

I am parsing a XML document using Xpath. The steps node have Attributes in the form of step. I am trying to get the value of each step. For example 0.03, 0.025,0.05.... But with my Code I only get the 1st value i.e 0.03 in the list of strings. Here is the Code that I tried:
XML file
private void btn_steps_Click(object sender, EventArgs e)
{
List<string> step = new List<string>();
XmlDocument doctst = new XmlDocument();
doctst.Load(#"C:\ehData\workData\mywork.xml");
XmlNodeList nodelistst = doctst.Selectnodes("//steps");
foreach (XmlNode node in nodelistst)
{
step.Add(node["step"].InnerText);
}
listBox2.DataSource = step;
}
Moreover, I am attaching the XML file image that I am trying to parse. What I am doing wrong in this Code?
Here are the few lines of the XML file
<devices orderNo="67354698">
<device serno="P1002001190">
<steps>
<step descriptor="160000556" element="1" usage="B">0.03</step>
<step descriptor="160000556" element="2" usage="B">0.025</step>
<step descriptor="160000556" element="3" usage="B">0.05</step>

1) By using XmlDocument.GetElementsByTagName() with xml tag name
...
XmlNodeList nodelistst1 = doctst.GetElementsByTagName("step");
foreach (XmlNode node in nodelistst1)
{
step.Add(node.InnerText);
}
2) By using XmlDocument.SelectNodes() with XPath
...
XmlNodeList nodelistst = doctst.SelectNodes(".//devices/device/steps/step/text()");
foreach (XmlNode node in nodelistst)
{
step.Add(node.Value);
}
So finally your result from both of the above option would be
foreach (var item in step)
{
Console.WriteLine(item);
}
Output: (For provided text XML from OP)

I am not sure whether you want attribute value or you want inner text.
Hence I am putting everything here.
Retrieving attributes:
For getting descriptor attribute from first step element - you can use below XPath:
/devices/device/steps/step[1]/#descriptor
This XPath will return - descriptor="160000556"
If you want only value then you can use:
string(/devices/device/steps/step[1]/#descriptor)
This would return only value i.e. 160000556
Same strategy you can apply for element or usage attributes.
Retrieving Inner Text:
And for getting inner text of second step element, you can use below XPath:
/devices/device/steps/step[2]/text()
Now these XPaths you can run through loop and change index inside square brackets to get all attributes and elements.
Hope this helps.

Related

C# XmlDocument select nodes returns empty

i am trying to work with http://api.met.no/weatherapi/locationforecast/1.9/?lat=49.8197202;lon=18.1673554 XML.
Lets say i want to select all value attribute of each temperature element.
i tried this.
const string url = "http://api.met.no/weatherapi/locationforecast/1.9/?lat=49.8197202;lon=18.1673554";
WebClient client = new WebClient();
string x = client.DownloadString(url);
XmlDocument xml = new XmlDocument();
xml.LoadXml(x);
XmlNodeList nodes = xml.SelectNodes("/weatherdata/product/time/location/temperature");
//XmlNodeList nodes = xml.SelectNodes("temperature");
foreach (XmlNode node in nodes)
{
Console.WriteLine(node.Attributes[0].Value);
}
But i get nothing all the time. What am i doing wrong?
The current single slash is targeting weatherdata under the root but the root is weatherdata.
Add a preceding slash to your xpath query to make it a double slash:
XmlNodeList nodes = xml.SelectNodes("//weatherdata/product/time/location/temperature");
Double slashes tells xpath to select nodes in the document from the current node that match the selection no matter where they are.
or remove the preceding slash:
XmlNodeList nodes = xml.SelectNodes("weatherdata/product/time/location/temperature");
which looks for the whole path including the root.
Also, since you apparently want the value called value add this:
Console.WriteLine(node.Attributes["value"].Value);
Since the value at of node.Attributes[0].Value may not be in the order you expect.
Are you attempting to loop through each attribute?
foreach (XmlNode node in nodes)
{
//You could grab just the value like below
Console.WriteLine(node.Attributes["value"].Value);
//or loop through each attribute
foreach (XmlAttribute f in node.Attributes)
{
Console.WriteLine(f.Value);
}
}

How do I read the value for and XML node and check if the value is correct

I am fairly new to programming and need to check a Single node in a XML file for a certain value and need to check if that value is correct.
I need to validate these 3 Nodes in 3 different classes:
<RunCodeAnalysis>true</RunCodeAnalysis>
I need to select this specific node from a xml file and need to check if the value of the node is true, i hope to get some help with the validation if the value is acutally true
private void CodeAnalysisEnabled(XDocument xmlDoc)
{
var codeAnalysis = from doc in xmlDoc.Root?.Descendants("RunCodeAnalysis") select doc;
foreach (var codeAnalysisNode in codeAnalysis)
{
codeAnalysisNode.Value = "true";
}
}
Load XML and use XPath to search for tags:
var document = new XmlDocument();
document.Load(fileName);
var root = document.DocumentElement
var nodes = root.SelectNodes("//RunCodeAnalysis");
This sample selects all RunCodeAnalysis nodes from XML. Using XPath you can select exactly what you want. Check this MSDN article.

How do I insert inner text into empty xml element?

I have an xmldocument that i'm loading xml in to.
The xml looks like this:
<Table1>
<buyer_id>0</buyer_id>
<buyername>CompanyA</buyername>
<address1>123 Simpsons Dr.</address1>
<address2/>
<city>Springfield</city>
<state>ST</state>
<postalcode>12345</postalcode>
<eaddress/>
<phone/>
<fax/>
</Table1>
I'm looping through looking at each CompanyA entry and setting innertext accordingly. I'm using the following code to insert inner text into elements that meet the criteria:
XmlDocument dom = new XmlDocument();
dom.LoadXml(xmlString);
XmlNodeList elemList = dom.GetElementByTagName("Table1");
for(int i = 0; i < elemList.Count; i++)
{
if(dom.GetElementsByTagName("buyername").Item(i).InnerText.Contains("CompanyA")
{
dom.GetElementsByTagName("address1").Item(i).InnerText = "SomeInfo";
}
}
Using the above code, the value of address1(123 Simpsons Dr.) would be replaced by "SomeInfo". I would like to instead insert "SomeInfo" into the address2 element but when I try using:
dom.GetElementsByTagName("address2").Item(i).InnerText = "SomeInfo";
I get an error. I'm able to insert innertext into any element that already has a value but I cannot when the element is empty (such as <address2/>). Thoughts?
Use LINQ2XML.It's a complete replacement to other XML api's like the dirty old idiot XmlDocument
XElement doc=XElement.Load("yourXml.xml");
foreach(var elm in doc.Descendants("Table1"))
{
if(elm.Element("buyername").Value=="CompanyA")
elm.Element("address2").Value="SomeInfo";
}
doc.Save("yourXml.xml");
Check if the address2 xml tag is empty.
If yes , go to its parent and remove the tag then again add the same tag with value.
If no , assign the inner text to address2.
let me know if you need the code.
Use the SetElementValue method in LINQ to XML:
XDocument doc = XDocument.Load(FilePath); //replace with xml file path
IEnumerable<XElement> buyersList = doc.Descendants("Table1"); //get the table node.
var ele = (from buyer in buyersList
where buyer.Element("buyername").Value == "CompanyA"
select buyer).SingleOrDefault();
ele.SetElementValue("address1", "SomeInfo");
ele.SetElementValue("address2", "SomeInfo");
doc.Save(FilePath);
DEMO: http://ideone.com/Cf7YI

Xdocument, get each element(s) value

I have xml as follows:
<Reports>
<report>
<name>By Book</name>
<report_type>book</report_type>
<Object>Count Change</Object>
<Slicers detail="detail">
<Namespace>EOD</Namespace>
<BookNode>HighLevel</BookNode>
<DateFrom>T-2</DateFrom>
<DateTo>T-1</DateTo>
<System>NewSystem</System>
</Slicers>
</report>
</Reports>
I simply want to loop through the value of each element of the Xdocument (pref would be any element under Slicers) but to start with just all elements.
When I run the following:
var slicers = from c in config.Elements("Reports")
select c.Value ;
foreach (var xe in slicers)
{
Console.WriteLine(xe);
}
The output is a single line concatenating all the values together.
"By BookbookCount ChangeEODHighLevelT-2T-1NewSystem"
I want to loop through them one at a time, 'By Book' first, run some code then book etc etc.
I am sure this is simple, but cant get round it. I have tried foreach(Xelement in query) but same resulst
i would do it something like this;
XmlDocument doc = new XmlDocument();
doc.LoadXml(xml);
//load in your xml here
XmlNodeList xnList = doc.SelectNodes("nodeYou'reLookingFor");
//for getting just the splicers you could do "Reports/report/Slicers"
foreach (XmlNode node in xnList)
string namespace = node["Namespace"].InnerText;
//go through all your nodes here
you're creating a xmldoc, loading your xml into it, creating a list which holds each node in the list (at a specified Xpath), and then looping through each. in the loop you can do whatever you want by referencing
node["nodenamehere"].InnerText

XPath and attributes

I'm trying to traverse an XML document and select certain node attributes. The XML is dynamically generated.
<?xml version="1.0" encoding="ISO-8859-1"?>
<streams>
<stream>
<title>+23 (Panama)</title>
<info resolution="768x420" bitrate="1000kbps"/> ----- Need These
<swfUrl>http://www.freeetv.com/script/mediaplayer/player.swf</swfUrl>
<link>rtmp://200.75.216.156/live/</link>
<pageUrl>http://www.freeetv.com/</pageUrl>
<playpath>livestream</playpath>
<language>Music</language>
<advanced></advanced>
</stream>
</streams>
The code that I'm trying to use with zero luck and Visual Studio saying "No you're wrong. Try 600 more times" is
xDoc.Load("http://127.0.0.1/www/xml.php");
XmlNodeList nodes = xDoc.SelectNodes("/streams/stream");
foreach (XmlNode xn in nodes)
{
ListViewItem lvi = listView1.Items.Add(xn["title"].InnerText);
lvi.SubItems.Add(xn["swfUrl"].InnerText);
lvi.SubItems.Add(xn["link"].InnerText);
lvi.SubItems.Add(xn["pageUrl"].InnerText);
lvi.SubItems.Add(xn["playpath"].InnerText);
lvi.SubItems.Add(xn["language"].InnerText);
lvi.SubItems.Add(xn["advanced"].InnerText);
lvi.SubItems.Add(xn["//info/#resolution"].Value);
}
Please tell me oh wise ones what am I doing wrong?
If you want to select node's attribute using XPath you should use SelectSingleNode method, e.g.:
xn.SelectSingleNode("info/#resolution").Value
To select resolution attribute of your last node you need to use:
xn["info"].Attributes["resolution"].Value
Alternatively, you can try LINQ to XML for the same results (I find its API easier to use):
var doc = XDocument.Parse("http://127.0.0.1/www/xml.php");
foreach (var d in doc.Descendants("stream"))
{
ListViewItem lvi = listView1.Items.Add(d.Element("title").Value);
lvi.SubItems.Add(d.Element("swfUrl").Value);
// ...
vi.SubItems.Add(d.Element("info").Attribute("resolution").Value);
}
Here is an example of LINQ to XML to extract attributes from the entire document of a particular attribute name OR list of attribute names.
var xml = XElement.Parse("http://127.0.0.1/www/xml.php");
// find all attributes of a given name
var attributes = xml
.Descendants()
.Attributes("AttributeName")
// find all attributes of multiple names
var attributes = xml
.Descendants()
.Attributes()
.Where(a => ListOfAttribNames.Contains(a.Name.LocalName))
Replace:
lvi.SubItems.Add(xn["//info/#resolution"].Value);
with:
lvi.SubItems.Add(xn.SelectSingleNode("info/#resolution").Value);

Categories