I need assistance in retrieving the element Country and Its value 1 in the below code. Thanks in advance.
<?xml version="1.0" encoding="utf-8"?>
<env:Contentname xmlns:env="http://data.schemas" xmlns="http://2013-02-01/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<env:Body>
<env:Content action="Hello">
<env:Data xsi:type="Yellow">
</env:Data>
</env:Content>
<env:Content action="Hello">
<env:Data xsi:type="Red">
<Status xmlns="http://2010-10-10/">
<Id >39681</Id>
<Name>Published</Name>
</Status>
</env:Data>
</env:Content>
<env:Content action="Hello">
<env:Data xsi:type="green">
<Document>
<Country>1</Country>
</Document>
</env:Data>
</env:Content>
</env:Body>
</env:Contentname>
I tried this,
var result = from x in root.Descendants(aw + "Data")
where (string)x.Attribute(kw + "type") == "green"
select x;
foreach (var item in result)
{
var str = item.Element("Document").Element("Country");
Console.WriteLine(str.Value);
}
But i am getting error.(Object reference not set to an instance of an object.) kindly help me with this.
This is the problem, for two reasons:
var str = item.Element("Document").Element("country");
Firstly, XML is case-sensitive - you want Country
, not country
.
Secondly, those elements inherit the namespace declared with xmlns=...
in the root element. You need:
XNamespace ns = "http://2013-02-01/";
...
var element = item.Element(ns + "Document").Element(ns + "Country");
I'd also encourage you to avoid query expressions where they don't actually buy you much. In this case, you could perform the whole query in one go using the Elements
extension method which works on sequences of input elements, assuming you don't mind finding every Document -> Country
element rather than just one per Data
:
var query = root.Descendants(aw + "Data")
.Where(x => (string)x.Attribute(kw + "type") == "green")
.Elements(ns + "Document")
.Elements(ns + "Country")
.Select(x => x.Value);
foreach (var item in query)
{
Console.WriteLine(item);
}
One significant difference - this won't fall over with an exception if there is a Data
element with xsi:type='green'
which doesn't have a Document -> Country
element. If you want it to (to find bad data) you could use:
var query = root.Descendants(aw + "Data")
.Where(x => (string)x.Attribute(kw + "type") == "green")
.Select(x => x.Element(ns + "Document")
.Element(ns + "Country")
.Value);
To show a short but complete example, this code (with your XML as test.xml
) gives an output of "1":
using System;
using System.Linq;
using System.Xml.Linq;
public class Program
{
static void Main(string[] args)
{
var doc = XDocument.Load("test.xml");
XNamespace ns = "http://2013-02-01/";
XNamespace kw = "http://www.w3.org/2001/XMLSchema-instance";
XNamespace aw = "http://data.schemas";
var query = doc.Descendants(aw + "Data")
.Where(x => (string)x.Attribute(kw + "type") == "green")
.Elements(ns + "Document")
.Elements(ns + "Country")
.Select(x => x.Value);
foreach (var item in query)
{
Console.WriteLine(item);
}
}
}
See more on this question at Stackoverflow