vendredi 18 mai 2012

xml file to a flatten list using Xlinq (Linq to xml) (+Namespace problem)

Here is once again a simple problem I faced recently.

I had this xml file and I'd like to flatten it to a list of actors in c#




<?xml version="1.0" encoding="utf-8" ?>
<MyDbCollection xmlns="http://www.Example.com">
  <Actors>
    <Actor FirstName="Will" LastName="Smith">
      <birthday date ="25.09.1968"/>
      <Movie name="Men in Black" Date="1999"/>
      <Movie name="Wild wild west" Date="1999"/>
      <Movie name="Ali" Date="2002"/>
    </Actor>
    <Actor FirstName="Jason" LastName="Statham">
      <Movie name="The Transporter" Date="2002"/>
      <Movie name="Revolver" Date="2005"/>
      <Movie name="The Bank Job" Date="2008"/>
      <Movie name="Transporter 3" Date="2008"/>
    </Actor>
    <Actor FirstName="Edward" LastName="Norton">
      <birthday date="18.08.1969"/>
      <Movie name="The Incredible Hulk" Date="2008"/>
      <Movie name="Fight Club" Date="1999"/>
      <Movie name="American History X" Date="1998"/>
    </Actor>
  </Actors>
</MyDbCollection>


There are many reason to flatten a list, so I won't enumerate any one of those.
So lets start:

As I want to use a list of "Actors", I create a class of actor:

 public class Actors
    {
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public string Name { get; set; }
        public string Date { get; set; }
    }

As you can see, I don't need the birthdate value (for the example purpose)

With a simple Xlinq request, it quite easy to cover the xml file... just make sure to understand between the Descandants() and the Elements() method.


class Program
    {
        static void Main(string[] args)
        {
            string file =
                @"G:\ConsoleApplication1\ConsoleApplication1\bin\Debug\Test.xml";
            ReadXmlFile(file);
        }

        private static void ReadXmlFile(string fileName)
        {
            XDocument indexDoc = XDocument.Load(fileName);
            var reader = from a in indexDoc.Root.Descendants().Descendants()
                         from b in a.Elements()
                         
                         select  new Actors
                                    {
                                        FirstName = a.Attribute("FirstName").Value,
                                        LastName = a.Attribute("LastName").Value,
                                        Name = b.Attribute("name").Value,
                                        Date = b.Attribute("Date").Value
                                    };
            var test = reader.ToList();
        }
    }

If you run this code, you'll get this result:



Actually this code should have been correct whether the node <birthday> was not present in the datasource (xml file)

So, let solve this problem... 
Having a look to the MSDN documentation, we see that by adding the name of the node, we can filter only the nodes that the code need.
But if you try, you'll see in this example that nothing will occur.
The reason is quite simple, the xml file contains a namespace so, an namespace should be added in the code in order to make it run correctly.

So an object XNamespace will help to add a namespace to the XML object. Just add the namespace object to the node to reach.

here is the finale code:



private static void ReadXmlFile(string fileName)
        {

            XNamespace ns = "http://www.Example.com";
            XDocument indexDoc = XDocument.Load(fileName);
            var reader = from a in indexDoc.Root.Descendants().Descendants()
                         from b in a.Elements(ns + "Movie")

                         select new Movie
                                    {
                                        FirstName = a.Attribute("FirstName").Value,
                                        LastName = a.Attribute("LastName").Value,
                                        Name = b.Attribute("name").Value,
                                        Date = b.Attribute("Date").Value
                                    };
            var test = reader.ToList();
        }

Good work ;-)

Aucun commentaire:

Publier un commentaire