Parsing XML Data with LINQ

c#, linq, parsing, xml

Solution

Here is one way of doing it:

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

class Program
{
    static void Main()
    {
        String xml = @"<Pricing>
            <MPrice>
                <Id>0079</Id>
                <Price>
                <Price>31.25</Price>
                <StartDt>2009-8-01</StartDt>
                <EndDt>2009-08-26</EndDt>
                </Price>
                <Price>
                <ListPrice>131.25</ListPrice>
                <StartDt>2009-08-26</StartDt>
                <EndDt>9999-12-31</EndDt>
                </Price>
            </MPrice>
           </Pricing>";

        var priceInfo = from e in XElement.Parse(xml).Elements("MPrice").Elements("Price")
                let start = DateTime.Parse(e.Descendants("StartDt").FirstOrDefault().Value)
                let end = DateTime.Parse(e.Descendants("EndDt").FirstOrDefault().Value)
                where start < DateTime.Now && end > DateTime.Now
                select new { Id = e.Parent.Element("Id").Value, ListPrice = e.Element("ListPrice").Value };

        Console.WriteLine(priceInfo.FirstOrDefault().Id);
        Console.WriteLine(priceInfo.FirstOrDefault().ListPrice);
    }
}

Output:

0079
131.25

Please note that there needs to be much more error checking than this example provides. I would specifically add checking around the parsing of the datetime (perhaps by using a function that wraps `DateTime.TryParseExact`).

Edit: If you want to use an `XDocument` instead of an `XElement` you will need to make a subtle change to the query (notice the usage of the `Descendants` method instead of the `Elements` method):

var priceInfo = from e in XDocument.Parse(xml).Descendants("MPrice").Elements("Price")
        let start = DateTime.Parse(e.Descendants("StartDt").FirstOrDefault().Value)
        let end = DateTime.Parse(e.Descendants("EndDt").FirstOrDefault().Value)
        where start < DateTime.Now && end > DateTime.Now
        select new { Id = e.Parent.Element("Id").Value, ListPrice = e.Element("ListPrice").Value };

Remember that you don't need to use an `XDocument` unless you are working with the XML as a true document. In most cases, the `XElement` type is sufficient.

Edit #2: If you want to load the `XDocument` from disk then use this approach:

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

class Program
{
    static void Main()
    {
        XDocument document = XDocument.Load(@"d:\test.xml");

        var priceInfo = from e in document.Descendants("MPrice").Elements("Price")
                let start = DateTime.Parse(e.Descendants("StartDt").FirstOrDefault().Value)
                let end = DateTime.Parse(e.Descendants("EndDt").FirstOrDefault().Value)
                where start < DateTime.Now && end > DateTime.Now
                select new { Id = e.Parent.Element("Id").Value, ListPrice = e.Element("ListPrice").Value };

        Console.WriteLine(priceInfo.FirstOrDefault().Id);
        Console.WriteLine(priceInfo.FirstOrDefault().ListPrice);
    }
}

Problem

I am new to LINQ. I need to return the id with the correct price information for today's date for each MPrice. Here is an example of the XML: ``` <Pricing> <MPrice> <Id>0079</Id> <Price> <Price>31.25</Price> <StartDt>2009-8-01</StartDt> <EndDt>2009-08-26</EndDt> </Price> <Price> <ListPrice>131.25</ListPrice> <StartDt>2009-08-26</StartDt> <EndDt>9999-12-31</EndDt> </Price> </MPrice> <MPrice> <Id>0081</Id> <Price> <Price>131.25</Price> <StartDt>2009-8-01</StartDt> <EndDt>2009-08-26</EndDt> </Price> <Price> <ListPrice>231.25</ListPrice> <StartDt>2009-08-26</StartDt> <EndDt>9999-12-31</EndDt> </Price> </MPrice> </Pricing> ```

Original source