Skip to content

LINQ, XML and XDocument fun.

July 9, 2008

I’ve had the chance to play with LINQ targeting XML recently in playing with some of the more (and less) popular webservices that provide metadata for MP3s.  I found that the documentation for creating and querying XML under the 3.5 framework a little sparse so I thought I’d share some code I just slapped together to illustrate some of the finer points for my colleagues.

 private void XmlExample()
     {
         XDocument rosterDoc = new XDocument();
         // We can setup namespaces if we need them.
       
XNamespace usr = @"http://www.xxxxx.com/schemas/hUsers";
         XNamespace ucls = @"http://www.xxxxx.com/schemas/hClasses";
         // Attach the declaration and setup default web settings
       
rosterDoc.Declaration = newXDeclaration("1.0", "utf-8", "yes");
         // You can add comments like so:
       
rosterDoc.Add(newXComment("Hogwarts Magic Computer User List:"));
         XElement rosterRoot = new XElement("Users");
         // We need to declare the namespaces so we’re not spelling them out on each line
        
rosterRoot.Add(new XAttribute(XNamespace.Xmlns + "usr", usr));
         rosterRoot.Add(new XAttribute(XNamespace.Xmlns + "ucls", ucls));
         foreach (ActiveDirData user in testData)
         {
             XElement newUser = new XElement(usr + "User");
             // Sometimes it makes more sense to make something an attribute than an element
            
newUser.Add(new XAttribute("IsActive", user.IsActive));
             newUser.Add(new XElement(usr + "UserID", user.UserID));
             newUser.Add(new XElement(usr + "FirstName", user.FirstName));
             newUser.Add(new XElement(usr + "LastName", user.LastName));
             newUser.Add(new XElement(usr + "Company", user.Company));
             newUser.Add(new XElement(usr + "Title", user.Title));
             newUser.Add(new XElement(usr + "Email", user.Email));
             // We can have conditional elements with their own children
            
if (user.Title == "student" && user.IsActive)
             {
                 XElement classRoot = new XElement(usr + "Classes");
                 foreach (string myClass in user.Classes)
                 {// Note the classes use a different namespace to prevent name confusion
                    
classRoot.Add(new XElement(ucls + "Class",
                         new XElement(ucls + "Title", myClass),
                         new XElement(ucls + "WeeklyMeetings", "5")));
                     // The weekly meetings thing is just a static example to add bulk
                
}
                 newUser.Add(classRoot);
             }
             rosterRoot.Add(newUser);// Add the user element to the root element
        
}
         rosterDoc.Add(rosterRoot);// Add the whole bundle to the document
        
rosterDoc.Save(@"c:\temp\example.xml");

         // So we could do a fun query to return active students like so
        
var results = from hogUsers in rosterDoc.Descendants(usr + "User")
                       where bool.Parse(hogUsers.Attribute("IsActive").Value) == true
                       select
hogUsers.Element(usr + "UserID");

         new XDocument(new XDeclaration("1.0", "utf-8", "yes"),
             new XElement("UserResults", results)).Save(@"c:\temp\exampleQuery.xml");
     }

     it will generate something like this:

 
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<!–

Hogwarts Magic Computer User List:

  –>

<usr:User IsActive="true">
  <usr:UserID>hpotter</usr:UserID>

  <usr:FirstName>harry</usr:FirstName>

  <usr:LastName>potter</usr:LastName>

  <usr:Company>hogwarts</usr:Company>

  <usr:Title>student</usr:Title>

  <usr:Email>hpotter@hogwarts.edu</usr:Email>

<usr:Classes>
<ucls:Class>
  <ucls:Title>Potions</ucls:Title>

  <ucls:WeeklyMeetings>5</ucls:WeeklyMeetings>

  </ucls:Class>

<ucls:Class>
  <ucls:Title>Charms</ucls:Title>

  <ucls:WeeklyMeetings>5</ucls:WeeklyMeetings>

  </ucls:Class>

<ucls:Class>
  <ucls:Title>Defense Against The Dark Arts</ucls:Title>

  <ucls:WeeklyMeetings>5</ucls:WeeklyMeetings>

  </ucls:Class>

<ucls:Class>
  <ucls:Title>Flying</ucls:Title>

  <ucls:WeeklyMeetings>5</ucls:WeeklyMeetings>

  </ucls:Class>

  </usr:Classes>

  </usr:User>

<usr:User IsActive="false">

  <usr:UserID>adumbledore</usr:UserID>

  <usr:FirstName>albus</usr:FirstName>

  <usr:LastName>dumbledore</usr:LastName>

  <usr:Company>hogwarts</usr:Company>

  <usr:Title>headmaster</usr:Title>

  <usr:Email>adumbledore@hogwarts.edu</usr:Email>

  </usr:User>

<usr:User IsActive="true">
  <usr:UserID>ssnape</usr:UserID>

  <usr:FirstName>severas</usr:FirstName>

  <usr:LastName>snape</usr:LastName>

  <usr:Company>hogwarts</usr:Company>

  <usr:Title>teacher</usr:Title>

  <usr:Email>ssnape@hogwarts.edu</usr:Email>

  </usr:User>

  </Users>
And the query would return this:

  <?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<UserResults>
</UserID>

  </UserResults>

For production I’d probably do the output differently but it makes a good example to do it this way.  Sorry about the XML pastes BTW.  Live Writer still has some problems with getting rich text from the clipboard though there are some good plugins to dump code snippets from visual studio.
I’ll leave you with another snippet from a query I was mucking around with to pull data out of the musicbrainz webservice.
var results = from b in doc.Descendants(XName.Get("track", "http://musicbrainz.org/ns/mmd-1.0#"))
select new
{
Score = b.Attribute(XName.Get("score", "http://musicbrainz.org/ns/ext-1.0#")).Value,
Title = b.Element(XName.Get("title", "http://musicbrainz.org/ns/mmd-1.0#")).Value,
Name = b.Element(XName.Get("artist", http://musicbrainz.org/ns/mmd-1.0#))
.Element(XName.Get("name", "http://musicbrainz.org/ns/mmd-1.0#")).Value,
Album = b.Element(XName.Get("release-list", http://musicbrainz.org/ns/mmd-1.0#))
.Element(XName.Get("release", http://musicbrainz.org/ns/mmd-1.0#))
.Element(XName.Get("title", "http://musicbrainz.org/ns/mmd-1.0#")).Value,
AlbumID = b.Element(XName.Get("release-list", http://musicbrainz.org/ns/mmd-1.0#))
.Element(XName.Get("release", http://musicbrainz.org/ns/mmd-1.0#))
.Attribute(XName.Get("id")).Value
};

 

Advertisements
One Comment leave one →
  1. anon permalink
    September 1, 2009 6:50 pm

    googled this because i was having trouble saving xml files and i got the answer.
    ( rosterDoc.Save(@”c:\temp\example.xml”); )

    Thanks alot.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: