Connect with Expertise | Find Experts, Get Answers, Share Insights

Readng XML via LINQ

Samishii23's Avatar
C
 
Join Date: Sep 2009
Location: Usa, Michigan, Westland
Posts: 146
#1: Feb 3 '10
Due to a recent suggestion...

And after failing to make a simple program to play with the code and see what it does... I come bearing questions, and seeking help...

Console App
Expand|Select|Wrap|Line Numbers
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Xml;
  5. using System.Xml.Linq;
  6. using System.Text;
  7.  
  8. namespace ConsoleApplication1
  9. {
  10.         class Program
  11.         {
  12.                 static void Main(string[] args)
  13.                 {
  14.                         var xdata = from d in XElement.Load("dk.xml").Elements("Talent")
  15.                                                 select d;
  16.  
  17.                         foreach (var data in xdata)
  18.                         {
  19.                                 Console.WriteLine(data);
  20.                         }
  21.                         Console.ReadLine();
  22.                 }
  23.         }
  24. }
Program compiles. All the console window does is the ReadLine() method, it doesn't show any data at all. can anyone tell me why I'm not getting any output?

tlhintoq's Avatar
E
C
 
Join Date: Mar 2008
Location: Arizona, USA
Posts: 3,476
#2: Feb 3 '10

re: Readng XML via LINQ


Just guessing that the path "dk.xml" does not lead to a file.
I think the default search is to check in the same folder as the executable.
Perhaps testing with the file a known valid location like "C:\\dk.xml"
Samishii23's Avatar
C
 
Join Date: Sep 2009
Location: Usa, Michigan, Westland
Posts: 146
#3: Feb 3 '10

re: Readng XML via LINQ


Thanks for the quick response.

I tried putting the XML file in the C:/ . Same result.
I tried using Console.Write instead.
I tried using data.ToString().

All the "Talent" tags in my XML file with don't have a closing tag (The syntax is w3 compliant though). So I tried to read a tag with a closing tag... Still no go...

Just figured I would try and see if it did anything. Though it didn't seem to work. =\
insertAlias's Avatar
E
M
C
 
Join Date: Apr 2008
Location: San Antonio, TX (USA)
Posts: 2,839
#4: Feb 3 '10

re: Readng XML via LINQ


I've been meaning to do a writeup of this eventually, but I haven't had time. I'll do a quick condensed version here for you to get started. I really love LINQ and want everyone to start using it =D

First, make sure to add a reference to System.Xml.Linq if you haven't, and make sure it's in your using statements. (I see that you already have, but I'm putting this here for other people's benefit).

The first part of the following code gets all the descendant nodes of the root element in the XML document, then loops through them and prints their values. I used the standard long notation for this.

The second part shows a query to find a specific string in the xml, namely the value of the first descendant node called "body". I used shorthand and a lambda expression for this example.

Here's a sample that can get you started.
C# Program
Expand|Select|Wrap|Line Numbers
  1. using System;
  2. using System.Linq;
  3. using System.Xml.Linq;
  4.  
  5. namespace TermsHelper
  6. {
  7.     class Program
  8.     {
  9.         static void Main(string[] args)
  10.         {
  11.             XDocument doc = XDocument.Load(@"c:\dev\temp.xml");
  12.  
  13.             //standard notation
  14.             var data = from x in doc.Root.Descendants()
  15.                        select x;
  16.             foreach (XElement e in data)
  17.                 Console.WriteLine(e.Value);
  18.  
  19.             //alternate notation
  20.             string body = doc.Root.Descendants().Where(x => x.Name == "body").First().Value;
  21.  
  22.             Console.WriteLine("\nBody: {0}", body);
  23.  
  24.             //attribute example
  25.             string attribute = doc.Root.Descendants().Where(x => x.Name == "body").First().Attribute("type").Value;
  26.             Console.WriteLine("\nAttribute: {0}", attribute);
  27.             Console.Read();
  28.         }
  29.     }
  30. }
temp.xml
Expand|Select|Wrap|Line Numbers
  1. <?xml version="1.0"?>
  2. <note>
  3.     <to>Tove</to>
  4.     <from>Jani</from>
  5.     <heading>Reminder</heading>
  6.     <body type="text">Don't forget me this weekend!</body>
  7. </note>
Expected output when executed
Expand|Select|Wrap|Line Numbers
  1. Tove
  2. Jani
  3. Reminder
  4. Don't forget me this weekend!
  5.  
  6. Body: Don't forget me this weekend!
  7.  
  8. Attribute: text
Good luck.
Samishii23's Avatar
C
 
Join Date: Sep 2009
Location: Usa, Michigan, Westland
Posts: 146
#5: Feb 3 '10

re: Readng XML via LINQ


Don't suppose I could get a quickie example pertaining to attributes?
insertAlias's Avatar
E
M
C
 
Join Date: Apr 2008
Location: San Antonio, TX (USA)
Posts: 2,839
#6: Feb 3 '10

re: Readng XML via LINQ


Sure, I'll edit my original post to include an attribute example.

Attribute("name") is a method of XElement that returns the first XAttribute of the XElement that matches the name. Attributes() will return a list.
Samishii23's Avatar
C
 
Join Date: Sep 2009
Location: Usa, Michigan, Westland
Posts: 146
#7: Feb 3 '10

re: Readng XML via LINQ


Awesome. I believe I've got the hang of singular Linq'n here. lol
This is a quickie layout of my current XML file.
Expand|Select|Wrap|Line Numbers
  1. <base>
  2.   <tree1>
  3.     <tag1 />
  4.     ...
  5.     <tag44 />
  6.   </tree1>
  7.   ...
  8.   <tree3 />
  9. </base>
  10.  
So far I've wrote this:
Expand|Select|Wrap|Line Numbers
  1. var query = from x in xmldoc.Root.Descendants()
  2.     select (XElement)x.Element("Talent");
And when I console it. I get Tag1 from each of the 3 trees and then a $hit ton of White Space. And thats it... lol

What I want to do is basicly read each Tag into a List or Array. All the examples I can find half the time either just give me a single item return, or they create an XML which I will not be doing at all.
insertAlias's Avatar
E
M
C
 
Join Date: Apr 2008
Location: San Antonio, TX (USA)
Posts: 2,839
#8: Feb 3 '10

re: Readng XML via LINQ


This would work better:
Expand|Select|Wrap|Line Numbers
  1. var query = from x in xmldoc.Root.Descendants().Elements("Talent")
  2.     select x;
Here's an example that uses your sample XML and does what you want in two different ways. The first way just gets all the elements who's name contains the string "tag". The second uses a custom data type and nested LINQ queries to give you a list of trees, with each tree containing a list of tags.

Expand|Select|Wrap|Line Numbers
  1. using System;
  2. using System.Linq;
  3. using System.Xml.Linq;
  4. using System.Collections.Generic;
  5.  
  6. namespace TermsHelper
  7. {
  8.     class Program
  9.     {
  10.         static void Main(string[] args)
  11.         {
  12.             XDocument doc = XDocument.Load(@"c:\dev\temp.xml");
  13.  
  14.             //just tags
  15.             List<XElement> elements = (from x in doc.Root.Descendants()
  16.                                       where x.Name.LocalName.Contains("tag")
  17.                                       select x).ToList();
  18.  
  19.             foreach (XElement e in elements)
  20.                 Console.WriteLine(e.Name);
  21.  
  22.             Console.WriteLine();
  23.  
  24.             //custom data type, hierarchical
  25.  
  26.             List<Tree> trees = (from x in doc.Root.Descendants()
  27.                                 where x.Name.LocalName.Contains("tree")
  28.                                 select new Tree
  29.                                 {
  30.                                     TreeName = x.Name.ToString(),
  31.                                     Tags = (from y in x.Elements()
  32.                                             where y.Name.LocalName.Contains("tag")
  33.                                             select y).ToList()
  34.                                 }).ToList();
  35.  
  36.             foreach (Tree t in trees)
  37.             {
  38.                 Console.WriteLine("Tree Name: {0}", t.TreeName);
  39.                 Console.WriteLine("Tags:");
  40.                 foreach (XElement e in t.Tags)
  41.                     Console.WriteLine(e.Name);
  42.                 Console.WriteLine();
  43.             }
  44.  
  45.             Console.Read();
  46.         }
  47.     }
  48.     public class Tree
  49.     {
  50.         public string TreeName { get; set; }
  51.         public List<XElement> Tags { get; set; }
  52.     }
  53. }
Contents of temp.xml
Expand|Select|Wrap|Line Numbers
  1. <?xml version="1.0"?>
  2.  <base>
  3.    <tree1>
  4.      <tag1 />
  5.      <tag2 />
  6.      <tag44 />
  7.    </tree1>
  8.    <tree2>
  9.     <tag1 />
  10.    </tree2>
  11.    <tree3 />
  12. </base>
Expected Output
Expand|Select|Wrap|Line Numbers
  1. tag1
  2. tag2
  3. tag44
  4. tag1
  5.  
  6. Tree Name: tree1
  7. Tags:
  8. tag1
  9. tag2
  10. tag44
  11.  
  12. Tree Name: tree2
  13. Tags:
  14. tag1
  15.  
  16. Tree Name: tree3
  17. Tags:
  18.  
Samishii23's Avatar
C
 
Join Date: Sep 2009
Location: Usa, Michigan, Westland
Posts: 146
#9: Feb 12 '10

re: Readng XML via LINQ


Well. Thanks for all the help! Though this LINQ stuff is a headache, and I doubt I'll be learning much more since just trying to figure out your examples, I couldn't really figure it out. Most tutorials out there do more XML generation rather then reading. Especially the MSDN examples... Ugh.

This is what I came up with...
Expand|Select|Wrap|Line Numbers
  1. XDocument xmldoc = XDocument.Load("dk.xml");
  2.     var query = from x in xmldoc.Root.Descendants()
  3.             where x.Name == "Talent"
  4.             select x;
  5.     foreach (XElement q in query)
  6.     {
  7.         Console.Write(q.Name + ": ");
  8.         Console.Write(q.Attribute("id").Value + ",");
  9.         if (Int32.Parse(q.Attribute("pts").Value) > 0)
  10.         {
  11.             Console.Write(q.Attribute("pts").Value + ",");
  12.             Console.Write(q.Attribute("title").Value + ",");
  13.             Console.Write(q.Attribute("icon").Value);
  14.             if (q.LastAttribute.Name == "req")
  15.                 Console.Write("," + q.Attribute("req").Value);
  16.         }
  17.         else
  18.         {
  19.             Console.Write(q.Attribute("pts"));
  20.         }
  21.     Console.WriteLine("--");
Output is:
Expand|Select|Wrap|Line Numbers
  1. Tag: 1,5,title,icon
  2. Tag: 2,0
  3. ... (132 total)
Each "Tag" output will be listed in its own List.
Samishii23's Avatar
C
 
Join Date: Sep 2009
Location: Usa, Michigan, Westland
Posts: 146
#10: Feb 12 '10

re: Readng XML via LINQ


So ok. Now my next question... Using the above code... How would I get a sibling node ( if thats what its called? ) through the same loop?

Would I use another Decendant() call?
Expand|Select|Wrap|Line Numbers
  1. <talent>
  2.   <disc>
  3.     Some stuff here
  4.   </disc>
  5. </talent>
insertAlias's Avatar
E
M
C
 
Join Date: Apr 2008
Location: San Antonio, TX (USA)
Posts: 2,839
#11: Feb 12 '10

re: Readng XML via LINQ


Expand|Select|Wrap|Line Numbers
  1. q.Element["whatever"].Value
Should give you the value of the first child node named "whatever"
Samishii23's Avatar
C
 
Join Date: Sep 2009
Location: Usa, Michigan, Westland
Posts: 146
#12: Feb 12 '10

re: Readng XML via LINQ


The " [] " brackets didn't work, but the " () " did. Thanks!
insertAlias's Avatar
E
M
C
 
Join Date: Apr 2008
Location: San Antonio, TX (USA)
Posts: 2,839
#13: Feb 13 '10

re: Readng XML via LINQ


Oops, sorry, forgot it was a method and not an index.
Reply

Tags
c sharp, linq, xml