Linq to Read Xml

LINQ to read XML

Try this.

using System.Xml.Linq;

void Main()
{
StringBuilder result = new StringBuilder();

//Load xml
XDocument xdoc = XDocument.Load("data.xml");

//Run query
var lv1s = from lv1 in xdoc.Descendants("level1")
select new {
Header = lv1.Attribute("name").Value,
Children = lv1.Descendants("level2")
};

//Loop through results
foreach (var lv1 in lv1s){
result.AppendLine(lv1.Header);
foreach(var lv2 in lv1.Children)
result.AppendLine(" " + lv2.Attribute("name").Value);
}

Console.WriteLine(result);
}

Reading XML nodes with LINQ

The problem is that the x.Element("Name") call will return the first Name element. You actually need to query all the Name elements and filter for the one with the Last attribute value.

Try this instead:

var query = from x in doc.Elements("Employee").Elements("Name")
where x.Attribute("Type").Value == "Last"
select x;

foreach (XElement item in query)
{
Console.WriteLine(item.Value);
}

Parse XML with LINQ to get child elements

var employees = (from e in xml.Root.Elements("Employee")
let r = e.Element("Region")
where (string)r.Attribute("name") == "West"
select new Employee
{
EmployeeName = (string)e.Attribute("employee"),
EmployeeDeptId = (string)e.Attribute("deptId"),
RegionName = (string)r.Attribute("name"),
AreaCode = (string)r.Element("Area").Attribute("code"),
}).ToList();

But it will still require query revision when XML file structure changes.

Edit

Query for multiple regions per employee:

var employees = (from e in xml.Root.Elements("Employee")
select new Employee
{
EmployeeName = (string)e.Attribute("employee"),
DeptId = (string)e.Attribute("deptId"),
RegionList = e.Elements("Region")
.Select(r => new Region {
RegionName = (string)r.Attribute("name"),
AreaCode = (string)r.Element("Area").Attribute("code")
}).ToList()
}).ToList();

You can then filter the list for employees from given region only:

var westEmployees = employees.Where(x => x.RegionList.Any(r => r.RegionName == "West")).ToList();

LINQ to XML query does not read my XML file

Important

When You use LastOrDefault() method You must understood the method can return default value of object (default(XElement)) and can by null and You will need to chceck if value is null. For example for Your code:

if (discountElement != null)
{
string discounCategory = discountElement.Element("GenreName").Value;
}

Exept this Your code is good. Problem is the XML file and value of StartDate an EndDate. Change that value of tags as You have the where condition like StartDat < DateTime.Now and EndDate >= DateTime.Now, for example like this (for today)

    <StartDate>2016-05-01</StartDate>
<EndDate>2017-05-31</EndDate>

When

filteredDiscounts.LastOrDefault(); will not return null and all will by good.

Parsing XML using LINQ in c#

I recommend you do as you would when reading XML naturally.

In your code, try to find all the fields with the name attribute set to "name".

This process cannot be used to associate a name with an age. It is more natural to read the XML and check all resource elements. Then add to this element some information described in the field elements.

// Using LINQ to SQL
XDocument document = XDocument.Load("http://www.studiovincent.net/list.xml"); // Loads the XML document.
XElement resourcesElement = document.Root.Element("resources"); // Gets the "resources" element that is in the root "list" of the document.

XElement resourceElementVincent = (from resourceElement in resourcesElement.Elements("resource")// Gets all the "resource" elements in the "resources" element
let fieldNameElement = resourceElement.Elements("field").Single(fieldElement => fieldElement.Attribute("name").Value == "name") // Gets the field that contains the name (there one and only one "name" field in the "resource" element -> use of Single())
where fieldNameElement.Value == "Vincent" // To get only resources called "Vincent"
select resourceElement).Single(); // We suppose there is one and only 1 resource called "Vincent" -> Use of Single()
XElement fieldAgeElement = resourceElementVincent.Elements("field").Single(fieldElement => fieldElement.Attribute("name").Value == "age"); // Gets the corresponding "age" field
int age = int.Parse(fieldAgeElement.Value, CultureInfo.InvariantCulture); // Gets the age by Parse it as an integer
Console.WriteLine(age);

Does it do what you want?

How to read xml file using linq

You can take the list of its elements

EDITED

var items = from item in xdoc.Descendants("item")
select new
{
Title = item.Element("title").Value,
Year = item.Element("year").Value,
Categories = item.Descendants("categories").Descendants().Select(x=>x.Value).ToList(),
Count = item.Element("count").Value
};

c# Linq to read xml string

Because the source XML contains a namespace (xmlns) declaration, you also need to use that namespace when querying any element underneath it, like this:

XDocument xmlDoc = XDocument.Parse(s1);
XNamespace ns = "urn:psialliance-org";

XElement peopleCounting = xmlDoc.Root.Element(ns + "peopleCounting");

string enter = peopleCounting.Element(ns + "enter").Value.Trim(); // Remove spaces from the value
string exit = peopleCounting.Element(ns + "exit").Value.Trim();
string pass = peopleCounting.Element(ns + "pass").Value.Trim();

Console.WriteLine(enter + " | " + exit + " | " + pass);

Or if you need to keep using the loop because there could be multiple peopleCounting nodes:

IEnumerable<XElement> allPeopleCounting = xmlDoc.Root.Elements(ns + "peopleCounting");

var result = from a in allPeopleCounting
select new
{
_enter = a.Element(ns + "enter").Value.Trim(),
_exit = a.Element(ns + "exit").Value.Trim(),
_pass = a.Element(ns + "pass").Value.Trim()
};

foreach (var item in result)
{
Console.WriteLine(item._enter + " | " + item._exit + " | " + item._pass);
}

Extract data from a XML string using linq vs xmlDocument

Retrieve an Element's Value

var status = xDoc
.Descendants("optinStatus") // get the optinStatus element
.Single() // we're expecting a single result
.Value; // get the XElement's value

Example

Here is a working Fiddle for you. You can see it running live here. The output is 3.

using System;
using System.Linq;
using System.Xml;
using System.Xml.Linq;

public class Program
{
public static void Main()
{
var xDoc = XDocument.Parse(xmlString);
var status = xDoc.Descendants("optinStatus").Single();
Console.WriteLine(status.Value);
}

private static string xmlString = @"

<response op=""getcustomerinfo"" status=""200"" message=""ok"" version=""1.0"">
<customer>
<totalMsg>3</totalMsg>
<custId>9008281</custId>
<custName></custName>
<timestamp>2015-04-30 16:17:19</timestamp>
<optinStatus>3</optinStatus>
<custMobile>6185312349</custMobile>
<subacct>1st Choice Courier</subacct>
</customer>
</response>

";
}

Explanation

Descendents() is an instance axes method (or just axes in shorthand). It returns an IEnumerable<XElement> of all matching descendents. On its results, we call Single(). It is a Linq method that returns the only element of a sequence. If there is more than one element, it throws an error. We're left with a single XElement. This represent an entire XML element. Since we only want its value not the entire element, we call the Value property. Bingo, we're done.

A Bit More Detail

Axes come in two kinds:

  • Instance axes methods, which MSDN lists here, are invokable members of the XElement, XDocument, and XNode classes.
  • Extension axes methods, which MSDN lists here, are invokable on collections.

With one exception, an axes method returns a collection of type IEnumerable<T>. The exception is Element(), which returns the first matching child object. That what AmatuerDev used and, as in your question, if you are only expecting a single result, it is a just as good if not better approach that is Descendants().

Retrieve an Attribute Value

Once we have an XElement, we can retrieve one of its attributes instead of its value. We do that by calling the Attributes() method. It returns the matching XAttribute. Since we only want the attribute value, we call the Value property. Voila.

// for attribute
var response = xDoc.Descendants("response").Single();
var attr = response.Attribute("status");

General Approach

Using Linq to XML is a two step process.

  1. Call an axes method to obtain an IEnumerable<T> result.
  2. Use Linq to query that.

See Also

Here is some relevant MSDN documentation:

  • How to: Retrieve the Value of an Element (LINQ to XML)
  • LINQ to XML Axes


Related Topics



Leave a reply



Submit