How to get value of child node from XDocument - c#

I need to get value of child node from XDocument using linq
<root>
<Cust>
<ACTNumber>1234</ACTNumber>
<Address>
<Street></Street>
<City>123 Main street</City>
<State>AL</State>
</Address>
</Cust>
</root>
I tried this: xDocTest.Root.Elements("Cust").Elements("ACTNumber")
If I try Address instead of ACTNumber then it works. But its not giving the child node value.

If there's only one Cust element and only one ACTNumber element, then it's easy:
string actNumber = doc.Root.Element("Cust").Element("ACTNumber").Value;
Or to get it as a long:
long actNumber = (long) doc.Root.Element("Cust").Element("ACTNumber");

Use this:
xDocTest.Root.Element("Cust").Element("Adress").Element("City").Value
If you use Elements (note the plural) it gives u an IEnumerable, this would be used like this:
XML
<Father>
<Child>Hello</Child>
<Child>World!</Child>
</Father>
C#
foreach(var childElement in Root.Elements("Child")) Console.WriteLine(childElement.Value);
Or to take your example:
foreach(var child in xdoc.Root.Element("Cust").Element("Address").Elements())
Console.WriteLine(string.Format("{0} : {1}", child.Name, child.Value);
Im not sure how Element behaves if you have multiple Elements of the same name. So you might want to use Elements and Inerate over all occurences.
And in Linq
If there is more than one Customer...
var result = from cust in xdoc.Root.Elements("Cust")
where cust.Elements("ACTNumber").Any() // This is to make sure there
// is an element called ACTNumber
// otherwise .Value would create
// Nullrefexception.
select child.Element("ACTNumber").Value;

Related

Using LINQ to exclude a Child Node from a collection of the same name

Per this XML, please note that BBB exists on two node levels.
<?xml version="1.0" encoding="utf-8"?>
<AAA>
<BBB>
<BBB>ONE</BBB>
<CCC>1</CCC>
<DDD>2</DDD>
<EEE>3</EEE>
</BBB>
<BBB>
<BBB>TWO</BBB>
<CCC>4</CCC>
<DDD>5</DDD>
<EEE>6</EEE>
</BBB>
<BBB>
<BBB>THREE</BBB>
<CCC>7</CCC>
<DDD>8</DDD>
<EEE>9</EEE>
</BBB>
</AAA>
I want to derive a collection of top level BBB's and extract them to their own file, with a file name based on the inner BBB.
My code is this:
XDocument xdoc = XDocument.Load(sourceFile);
var lv1s = from lv1 in xdoc.Descendants("AAA") select lv1;
var lv2s = from lv2 in xdoc.Descendants("BBB") select lv2;
foreach (var lv2 in lv2s)
{
var name = lv2.Element("BBB").Value;
lv2.Save(#"c:\temp\" + name + ".xml");
}
Problem is, LVL2 is picking up both the parent and descendants BBB.
Can't seem to find a method that effectively filters out descendants.
For example I thought this was the key, but it yielded no results:
var lv2s = from lv2 in xdoc.Elements("BBB") select lv2;
Hoping you can provide me a ways to deal with the problem.
-------------------- EDIT --------------------
Okay I see what I did wrong. A typo.
LVL2 should have leveraged LVL1, like this:
var lv2s = from lv2 in lv1s.Elements("BBB") select lv2;
That said, octavioccl's approach was much better than the bloated solution I came up with:
var parentBbbs =xdoc.Element("AAA").Elements("BBB");
You need to start getting the root element and then select the parent BBBs using Elements method:
var parentBbbs =xdoc.Element("AAA").Elements("BBB");
Just document.Root.Elements() should work.
Basically Descendants() recurses, whereas Elements() only gets direct children.

XML child values coming in strung together as on long string

I have the following XML:
<Items>
<textBoxCenterName>Denver Dispatch</textBoxCenterName>
<textBoxContactFirstName>Eric</textBoxContactFirstName>
<servicedUnits>
<unit>CO-ADX (Adams County)</unit>
<unit>CO-AFQ (Air Force Academy)</unit>
<unit>CO-ALDS (CSFS-Alamosa District)</unit>
<unit>CO-ALX (Alamosa County)</unit>
</servicedUnits>
</Items>
I am using the following code to pull in the servicedUnits as listBox items:
XElement element = XElement.Load("FCAT-Settings.xml");
foreach (XElement item in element.Elements("servicedUnits"))
listBoxServicedUnits.Items.Add(item.Value);
The items are coming in as one long string concatenated, like so:
CO-ADX (Adams County)CO-AFQ (Air Force Academy)CO-ALDS (CSFS-Alamosa District)CO-ALX (Alamosa County)
So I end up with one item in the listbox with all these servicedUnits strung together.
How can I solve this? Any ideas are welcome.
The problem is with the selection. element.Elements("servicedUnits") returns the list of servicedUnits elements (Only 1 in the XML), and what you wanted is the list of elements INSIDE that element, for example element.Elements("servicedUnits").Elements().
You might try getting child nodes:
foreach (XElement item in element.Elements("servicedUnits").Elements())
You are attempting to iterate over a single element (servicedUnits) instead of iterating over the collection of unit elements that you intend to. The output of your current implementation is simply giving you the total Value of your servicedUnits element, which is the value of each of its child elements.
To get what you seemingly intend to have, you need to iterate over your unit elements, like this:
foreach(XElement item in element.Element("servicedUnits").Elements("unit"))
{
//add to listbox, whatever
}
This sample implementation assumes you only have a single servicedUnits element, FYI.
An easy way to do this is by using the Descendents method on an XDocument:
var xdoc = XDocument.Load(#"FCAT-Settings.xml");
var units = xdoc
.Descendants("servicedUnits")
.SelectMany(u => u.Descendants("unit").Select(x => x.Value));
foreach (var unit in units)
listBoxServicedUnits.Items.Add(unit);
This also ensures you will only get the values for the "unit" nodes.

Can't loop children of returned XML Nodes in C#

I have a large, messy XML file and I want to retrieve ALL elements of the same name ("Item" for the sake of this post) from it, then be able to retrieve data from each element's children.
So far I have returned a list of every element called "Item" using this code, which just displays the namespace url and "Item" in p tags:
XDocument doc = XDocument.Load(#"C:\inetpub\wwwroot\mysite\myxml.xml");
XNamespace ns = "http://www.mynamespace.com";
var nodes = doc.Descendants().Elements(ns + "Item").Select(d => d.Name).ToList();
foreach(var x in nodes){
<p>#x</p>
}
However, by amending the code with the following, I can't retrieve any data of it's children and I get the error 'System.Xml.Linq.XName' does not contain a definition for 'Descendants':
foreach(var x in nodes){
<p>#x.Descendants().Element("Name")</p>
}
Here is a very basic version of my XML file:
<Item>
<Name>Item 1</Name>
<Type>Type 1</Type>
</Item>
I want to be able to search each 'Item' element for a 'Name' element and return the value. Can anyone see where I'm going wrong?
This is the problem:
.Select(d => d.Name)
You're explicitly selecting the names of the elements. If you want the actual elements (which I think you do), just get rid of that call:
var nodes = doc.Descendants().Elements(ns + "Item").ToList();
You could also get rid of the ToList() unless you need the query to be materialized eagerly.

Returning XML Data from Root on Window 7 Phone

I am having difficulty trying to return values from an XML file. Here is an example of the XML:
<xml>
<item1>Whatever</item1>
<video>
<caption>Video Title</caption>
<width>1280</width>
<height>720</height>
</video>
<element1>Results One</element1>
<element2>Results Two</element2>
</xml>
I am calling the data like this:
XElement xmlData = XElement.Parse(e.Result);
var list = new List<VideoUrl>();
foreach (XElement item in xmlData.Elements("xml"))
{
var element1 = item.Element("element1").Value;
var element2 = item.Element("element2").Value;
list.Add(new VideoUrl
{
etc...
});
and then assigning the data to a list box to return the values. Problem is I am trying to return XML items "element1" and "element2" but nothing is returned when i run the emulator. If I change the code to return Video > Caption it works fine. I feel like its something real simple I am missing. Any ideas or code samples to fix this would be much appreciated. Thanks in advanced.
xmlData is the <xml> element, so xmlData.Elements("xml") will return no values - there are no xml elements directly under xmlData. Given that it's the root, you know there's only one node, so you can just do:
var element1 = (string) xmlData.Element("element1");
var element2 = (string) xmlData.Element("element2");
Note that by casting to string instead of using the Value property, you end up with a null reference if the element doesn't exist, instead of an exception being thrown.

How do I get the value from a node using LINQ to XML?

I have this XML file:
<?xml version="1.0" encoding="utf-8"?>
<aBase xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<a>
<a>
<b>some data</b>
<c>other data</c>
</a>
<a>
<b>some data</b>
<c>other data</c>
</a>
</a>
</aBase>
I want to get all data from <b> nodes using LINQ to XML.
I have tried something like this:
var query = from c in xmlData.Descendants("b")
select c.Value;
but it doesn't work.
How can I do this?
Also, what is the difference between Descendents, Elements and Nodes?
You can write this query to get all information from inner a nodes:
var query = from e in doc.Root.Elements( "a" ).Elements( "a" )
select new { B = e.Element( "b" ).Value, C = e.Element( "c" ).Value };
But this is just a query. To execute it and work with results write this code:
foreach ( var e in query )
{
// Do something with results... For example, write to console:
Console.WriteLine( "B: " + e.B + ", C: " + e.C );
}
Node is the one element of the XML tree. aBase element, all the a, b and c elements - the nodes of the XML document.
Elements is just the child elements of selected node (in one level of hierarchy). For example for the aBase node the only child element is the outer a element, not the inner a, b or c element.
Descendants is all the elements that are child or descendants to the current node (in all levels of hierarchy). All elements are the descendants to the aBase element because it is the main element of the document.
xmlData.Descendants("b") will give you a collection of XElements with XName equal to "b". You can then iteration over this collection to get every value:
var data = xmlData.Descendants("b");
foreach (XElement b in data)
{
string value = b.Value;
// do something with value here
}
Descendants will give you any Element that is a descendant, not only the direct children, but also the children of them. So in your case xmlData.Root.Descendants("b") will return a collection over every B element in the file. Elements does the same thing but only for direct descendants and Nodes does the same thing but includes comments and textNodes.
Here you go:
XDocument doc = XDocument.Parse(xml);
XNamespace ns = doc.Root.Name.Namespace;
var query = doc.Root.Elements(ns + "a").Elements(ns + "a").Elements().Select(el => el.Value);
Please note that you don't even need neither the Descendants method nor iteration through descendants. Elements without parameters returns direct descendants, and Select method extracts values of descendants. And don't forget about xml namespace or elements names could not be found. Without namespace you're trying to extract different elements, not the elements in your xml.
As for difference between different methods:
Nodes() returns IEnumerable<XNode>
Elements() returns IEnumerable<XElement>
Descendants() returns all descendant elements (including all deeply nested elements in opposite to Nodes and Elements return only 1st level child elements of calling element.
var query = from c in xmlData.Descendants("b").First()
select c.Value;

Categories

Resources