How do I get the values for parameters in a XmlNode tag. For example:
<weather time-layout="k-p24h-n7-1">
<name>Weather Type, Coverage, and Intensity</name>
<weather-conditions weather-summary="Mostly Sunny"/>
</weather>
I want to get the value for the parameter 'weather-summary' in the node 'weather-conditions'.
var node = xmldoc.SelectSingleNode("weather/weather-conditions");
var attr = node.Attributes["weather-summary"];
In the interest of completeness, the .Net 3.5 way should be given as well:
Assuming
XDocument doc = XDocument.Parse(#"<weather time-layout='k-p24h-n7-1'>
<name>Weather Type, Coverage, and Intensity</name>
<weather-conditions weather-summary='Mostly Sunny'/></weather>");
Then either
return doc.Element("weather").Element("weather-conditions").Attribute("weather-summary").Value;
Or
return doc.Descendants("weather-conditions").First().Attribute("weather-summary").Value;
Will give you the same answer.
Related
I'd like to retrieve information from an XML file, however the way it's formatted is pretty strange. Here it is...
<?xml version="1.0"?>
<Careers>
<CareerList>
<CareerName></CareerName>
<CareerDescription></CareerDescription>
</CareerList>
<CareerList>
<CareerName>Cook</CareerName>
<CareerDescription>Cooks food for people</CareerDescription>
</CareerList>
</Careers>
I'd like to get the 2nd value, which would be Cook and the description which is Cooks food for people, but instead I'm getting only the empty node. For example...
public string CareerDescription(string CareerFile)
{
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load(CareerFile);
string Description = xmlDoc.SelectSingleNode("Careers/CareerList/CareerDescription").InnerText;
return Description;
}
How would I select the second node instead of the first?
You can use an index in your XPath expression:
xmlDoc.SelectSingleNode("Careers/CareerList[2]/CareerDescription").InnerText
Personally I'd use LINQ to XML instead, mind you:
var doc = XDocument.Load(CareerFile);
return doc.Root
.Elements("CareerList")
.ElementAt(1) // 0-based
.Element("CareerDescription")
.Value;
Instead of SelectSingleNode you should use SelectNodes: it will return XmlNodeList nodeList. Then you should take the InnerText of the element from that node list with index [1];
public string CareerDescription(string CareerFile)
{
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load(CareerFile);
string Description = xmlDoc.SelectNodes("Careers/CareerList/CareerDescription")[1].InnerText;
return Description;
}
Refer to the documentation on this method on MSDN for more details: http://msdn.microsoft.com/en-us/library/system.xml.xmlnode.selectnodes%28v=vs.71%29.aspx
Just a straight way of LINQ to XML routine (and because it is LINQ, I prefer this way much more than the "standard" usage of XmlDocument with the support of XPath):
return XDocument.Load(CareerFile)
.Descendants("CareerDescription").Skip(1).First().Value;
Given this XML:
<InitResponse>
<LottoToken>908ec70b308adf10d04db1478ef9b01b</LottoToken>
<GameInfoList>
<GameInfo>
<Draw>
<gameId>L649</gameId>
<draw>3035</draw>
</Draw>
</GameInfo>
<GameInfo>
<Draw>
<gameId>BC49</gameId>
<draw>2199</draw>
</Draw>
</GameInfo>
</GameInfoList>
</InitResponse>
I need to get the draw number based on a specific gameId. For example if I specify gameID L649 I need to get 3035.
The following works in several online evaluators, but not in C#. It says it cannot find it. Suggestions?
/InitResponse/GameInfoList/GameInfo/Draw/draw[preceding-sibling::gameId='L649']
C# Code I've tried:
XmlNode node = xmlDoc.SelectSingleNode("/InitResponse/GameInfoList/GameInfo/Draw/draw[preceding-sibling::gameId='L649']");
... where xmlDoc is an xmlDocument object loaded with the xml. the node variable ends up with a null value which seems to indicate there was no match found.
Here is xpath (with Linq)
var xdoc = XDocument.Load(path_to_xml);
string xpath = "/InitResponse/GameInfoList/GameInfo/Draw[gameId='L649']/draw";
var draw = xdoc.XPathSelectElement(xpath);
if (draw != null) // check if draw with gameId found in xml
value = (int)draw;
Also you can use pure Linq to Xml (but in this case xpath looks more compact):
var draw = xdoc.Descendants("GameInfo")
.SelectMany(g => g.Elements("Draw"))
.SingleOrDefault(d => (string)d.Element("gameId") == "L649");
if (draw != null)
value = (int)draw.Element("draw");
Using XmlDocument
I didn't saw something wrong in your XPath statement, look on the following:
(So i guess there is something else that is wrong)
XmlDocument myDoc = new XmlDocument();
String str = #"<InitResponse>
<LottoToken>908ec70b308adf10d04db1478ef9b01b</LottoToken>
<GameInfoList>
<GameInfo>
<Draw>
<gameId>L649</gameId>
<draw>3035</draw>
/Draw>
</GameInfo>
<GameInfo>
<Draw>
<gameId>BC49</gameId>
<draw>2199</draw>
</Draw>
</GameInfo>
</GameInfoList>
</InitResponse>";
myDoc.LoadXml(str);
XmlNode node =
myDoc.SelectSingleNode("/InitResponse/GameInfoList/GameInfo/Draw/draw[preceding-sibling::gameId='L649']");
The node which returns from the result is: 3035
Note: your first note have to be <InitResponse> otherwise it will returns null
According to MSDN there's an "Item" property associated with the XmlDocument class:
http://msdn.microsoft.com/en-us/library/system.xml.xmldocument.aspx
I can't seem to get it to work though.
XmlDocument doc = new XmlDocument();
doc.LoadXml("<item><name>wrench</name></item>");
string myItem = doc.Item["item/name"].InnerText;
...fails to compile for example. What's the correct way to use this property if it does exist?
An indexer in C# is exposed as a parametrized property called Item to other languages.
In C#, just use indexer syntax:
var result = someObject["something"];
An alternate approach, using LINQtoXML
Assuming your XML is going to be always in that structure.
string thatXml="<item><name>wrench</name></item>";
XElement elm =XElement.Parse(thatXml);
string thatValue = elm.Element("name").Value;
I have some code that is returning a XNode to me which looks like this:
<File>
<Component>Main</Component>
<Path>C:\Main\</Path>
<FileName>main.txt</FileName>
</File>
I need to have some C# code that will be able to pull out the value of Path for example (C:\Main). I know that if I was using an XML node I could do it like this:
String filePath = xmlNode["Path"].InnerText;
Does anybody know what the equivalent would be for an XNode? Any help is much appreciated!
Do you have to have it returning an XNode rather than an XElement? With an XElement it's simpler than with an XNode:
string filePath = fileElement.Element("Path").Value;
That will find the first Path element, and will throw a NullReferenceException if there aren't any. An alternative if you're happy to get null if there aren't any would be:
string filePath = (string) fileElement.Element("Path");
If you're really stuck with XNode, you'll either have to cast to XElement or possibly XContainer.
You can convert your XNode into XElement to access to its properties, my example:
XNode lastNode = myXElement.LastNode;
//if I want to get the 'ID' attribute
string id = (lastNode as XElement).Attribute("ID").Value;
Casting XNode to XElement works for the individual element to retrieve its value or attributes. But you won't be able to use myXelement.Elements("XXX") to get nested elements. For that you can use xmlNode.Nodes().
This should work:
var nodes = xmlNode.Nodes();//Get all nodes under 'File'
var fileNameNode = nodes.Where(el => ((XElement)el).Name.LocalName == "FileName")
.FirstOrDefault();
string filePath = ((XElement)fileNameNode).Value;
You may use this:
XElement xtr = XElement.Load("path/to/your/xml/file");
String filePath = xtr.Descendants("Path").Single().Value;
If you import System.Xml.XPath you can use XPathSelectElement like this on the XNode object:
String component = xmlNode.XPathSelectElement("Component");
String path = xmlNode.XPathSelectElement("Path");
String fileName = xmlNode.XPathSelectElement("FileName");
It depends on what convcrete objets is the abstract XNode. From XNode Class:
XNode is an abstract common base class for the following types:
XComment
XContainer: can be XDocument or XElement
XDocumentType
XProcessingInstruction
XText
So you need to check if you can cast it to an XDocument or an XElement, and use their methods, or use LINQ to XML:
For example:
Best way to query XDocument with LINQ?
Querying an XDocument vs. Querying an XElement (C#)
XNode xnode
string value = (xnode as XElement).Value;
we can get the value form XElement object so we need to cast XNode to XElement first
should work
Lately I've been using XPathDocument and XNavigator to parse an XML file for a given XPath and attribute. It's been working very well, when I know in advance what the XPath is.
Sometimes though, the XPath will be one of several possible XPath values, and I'd like to be able to test whether or not a given XPath exists.
In case I'm getting the nomenclature wrong, here's what I'm calling an XPath - given this XML blob:
<foo>
<bar baz="This is the value of the attribute named baz">
</foo>
I might be looking for what I'm calling an XPath of "//foo/bar" and then reading the attribute "baz" to get the value.
Example of the code that I use to do this:
XPathDocument document = new XPathDocument(filename);
XPathNavigator navigator = document.CreateNavigator();
XPathNavigator node = navigator.SelectSingleNode("//foo/bar");
if(node.HasAttributes)
{
Console.WriteLine(node.GetAttribute("baz", string.Empty));
}
Now, if the call to navigator.SelectSingleNode fails, it will return a NullReferenceException or an XPathException. I can catch both of those and refactor the above into a test to see whether or not a given XPath returns an exception, but I was wondering whether there was a better way?
I didn't see anything obvious in the Intellisense. XPathNavigator has .HasAttributes and .HasChildren but short of iterating through the path one node at a time, I don't see anything nicer to use.
If you've given valid XPath but it doesn't match anything, SelectSingleNode won't throw a NullReferenceException - it will just return null.
If you pass SelectSingleNode some syntactically invalid XPath, that's when it will throw an XPathException.
So normally, you'd just need to test whether the returned value was null or not.
var baz = navigator.SelectSingleNode("//foo/bar/#baz");
if (baz != null) Console.WriteLine(baz);
I think it is not good to create an XMLNode object by executing navigator.SelectSingleNode(...).
You have to use navigator.Evaluate() instead:
if (Convert.ToBoolean(navigator.Evaluate(#"boolean(//foo/bar)"))) {...}
From memory, may contain errors.
XDocument doc = XDocument.Load("foo.xml");
var att = from a in doc.Descendants("bar")
select a.Attribute("baz")
foreach (var item in att) {
if (item != null) { ... }
}
If node == null then node.HasAttributes will throw a NullReferenceException. This situation will occur when //foo/bar does not match any elements in the XML document.
var node = XDocument.Load(filename)
.Descendants("bar")
.SingleOrDefault(e=>e.Attribute("baz") != null);
if (node != null) Console.WriteLine(node.Attribute("baz").Value);
I would probably be more specific in my xpath.
var doc = XDocument.Load(fileName);
var results = from r in doc.XPathSelectElements("/foo/bar[count(#baz) > 0]")
select r.Attribute("baz");
foreach (String s in results)
Console.WriteLine(s);