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
, andXNode
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.
- Call an axes method to obtain an
IEnumerable<T>
result. - 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
How to Implement Custom Jsonconverter in Json.Net
Why Not Inherit from List≪T≫
Converting a String to Datetime
C# Variance Problem: Assigning List≪Derived≫ as List≪Base≫
How to Convert a Unix Timestamp to Datetime and Vice Versa
Webbrowser Control in a New Thread
Mvvm: Tutorial from Start to Finish
Why Saving Changes to a Database Fails
How to Auto-Generate a C# Class File from a Json String
The Entity Cannot Be Constructed in a Linq to Entities Query
Casting VS Using the 'As' Keyword in the Clr
What's Wrong With Using Thread.Abort()
Decimal VS Double! - Which One Should I Use and When
Transactionscope Automatically Escalating to Msdtc on Some Machines