Readng XML via LINQ

Collapse
X
 
  • Time
  • Show
Clear All
new posts
  • Samishii23
    New Member
    • Sep 2009
    • 246

    Readng XML via LINQ

    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
    Code:
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Xml;
    using System.Xml.Linq;
    using System.Text;
    
    namespace ConsoleApplication1
    {
    		class Program
    		{
    				static void Main(string[] args)
    				{
    						var xdata = from d in XElement.Load("dk.xml").Elements("Talent")
    												select d;
    
    						foreach (var data in xdata)
    						{
    								Console.WriteLine(data);
    						}
    						Console.ReadLine();
    				}
    		}
    }
    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
    Recognized Expert Specialist
    • Mar 2008
    • 3532

    #2
    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 "

    Comment

    • Samishii23
      New Member
      • Sep 2009
      • 246

      #3
      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. =\

      Comment

      • Curtis Rutland
        Recognized Expert Specialist
        • Apr 2008
        • 3264

        #4
        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
        Code:
        using System;
        using System.Linq;
        using System.Xml.Linq;
        
        namespace TermsHelper
        {
            class Program
            {
                static void Main(string[] args)
                {
                    XDocument doc = XDocument.Load(@"c:\dev\temp.xml");
        
                    //standard notation
                    var data = from x in doc.Root.Descendants()
                               select x;
                    foreach (XElement e in data)
                        Console.WriteLine(e.Value);
        
                    //alternate notation
                    string body = doc.Root.Descendants().Where(x => x.Name == "body").First().Value;
        
                    Console.WriteLine("\nBody: {0}", body);
        
                    //attribute example
                    string attribute = doc.Root.Descendants().Where(x => x.Name == "body").First().Attribute("type").Value;
                    Console.WriteLine("\nAttribute: {0}", attribute);
                    Console.Read();
                }
            }
        }
        temp.xml
        Code:
        <?xml version="1.0"?>
        <note>
            <to>Tove</to>
            <from>Jani</from>
            <heading>Reminder</heading>
            <body type="text">Don't forget me this weekend!</body>
        </note>
        Expected output when executed
        Code:
        Tove
        Jani
        Reminder
        Don't forget me this weekend!
        
        Body: Don't forget me this weekend!
        
        Attribute: text
        Good luck.

        Comment

        • Samishii23
          New Member
          • Sep 2009
          • 246

          #5
          Don't suppose I could get a quickie example pertaining to attributes?

          Comment

          • Curtis Rutland
            Recognized Expert Specialist
            • Apr 2008
            • 3264

            #6
            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.

            Comment

            • Samishii23
              New Member
              • Sep 2009
              • 246

              #7
              Awesome. I believe I've got the hang of singular Linq'n here. lol
              This is a quickie layout of my current XML file.
              Code:
              <base>
                <tree1>
                  <tag1 />
                  ...
                  <tag44 />
                </tree1>
                ...
                <tree3 />
              </base>
              So far I've wrote this:
              Code:
              var query = from x in xmldoc.Root.Descendants()
                  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.

              Comment

              • Curtis Rutland
                Recognized Expert Specialist
                • Apr 2008
                • 3264

                #8
                This would work better:
                Code:
                var query = from x in xmldoc.Root.Descendants().Elements("Talent")
                    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.

                Code:
                using System;
                using System.Linq;
                using System.Xml.Linq;
                using System.Collections.Generic;
                
                namespace TermsHelper
                {
                    class Program
                    {
                        static void Main(string[] args)
                        {
                            XDocument doc = XDocument.Load(@"c:\dev\temp.xml");
                
                            //just tags
                            List<XElement> elements = (from x in doc.Root.Descendants()
                                                      where x.Name.LocalName.Contains("tag")
                                                      select x).ToList();
                
                            foreach (XElement e in elements)
                                Console.WriteLine(e.Name);
                
                            Console.WriteLine();
                
                            //custom data type, hierarchical
                
                            List<Tree> trees = (from x in doc.Root.Descendants()
                                                where x.Name.LocalName.Contains("tree")
                                                select new Tree
                                                {
                                                    TreeName = x.Name.ToString(),
                                                    Tags = (from y in x.Elements()
                                                            where y.Name.LocalName.Contains("tag")
                                                            select y).ToList()
                                                }).ToList();
                
                            foreach (Tree t in trees)
                            {
                                Console.WriteLine("Tree Name: {0}", t.TreeName);
                                Console.WriteLine("Tags:");
                                foreach (XElement e in t.Tags)
                                    Console.WriteLine(e.Name);
                                Console.WriteLine();
                            }
                
                            Console.Read();
                        }
                    }
                    public class Tree
                    {
                        public string TreeName { get; set; }
                        public List<XElement> Tags { get; set; }
                    }
                }
                Contents of temp.xml
                Code:
                <?xml version="1.0"?>
                 <base>
                   <tree1>
                     <tag1 />
                	 <tag2 />
                     <tag44 />
                   </tree1>
                   <tree2>
                	<tag1 />
                   </tree2>
                   <tree3 />
                </base>
                Expected Output
                Code:
                tag1
                tag2
                tag44
                tag1
                
                Tree Name: tree1
                Tags:
                tag1
                tag2
                tag44
                
                Tree Name: tree2
                Tags:
                tag1
                
                Tree Name: tree3
                Tags:

                Comment

                • Samishii23
                  New Member
                  • Sep 2009
                  • 246

                  #9
                  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...
                  Code:
                  XDocument xmldoc = XDocument.Load("dk.xml");
                  	var query = from x in xmldoc.Root.Descendants()
                  			where x.Name == "Talent"
                  			select x;
                  	foreach (XElement q in query)
                  	{
                  		Console.Write(q.Name + ": ");
                  		Console.Write(q.Attribute("id").Value + ",");
                  		if (Int32.Parse(q.Attribute("pts").Value) > 0)
                  		{
                  			Console.Write(q.Attribute("pts").Value + ",");
                  			Console.Write(q.Attribute("title").Value + ",");
                  			Console.Write(q.Attribute("icon").Value);
                  			if (q.LastAttribute.Name == "req")
                  				Console.Write("," + q.Attribute("req").Value);
                  		}
                  		else
                  		{
                      		Console.Write(q.Attribute("pts"));
                  		}
                  	Console.WriteLine("--");
                  Output is:
                  Code:
                  Tag: 1,5,title,icon
                  Tag: 2,0
                  ... (132 total)
                  Each "Tag" output will be listed in its own List.
                  Last edited by Samishii23; Feb 12 '10, 01:57 AM. Reason: Removed Some Tabs

                  Comment

                  • Samishii23
                    New Member
                    • Sep 2009
                    • 246

                    #10
                    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?
                    Code:
                    <talent>
                      <disc>
                        Some stuff here
                      </disc>
                    </talent>

                    Comment

                    • Curtis Rutland
                      Recognized Expert Specialist
                      • Apr 2008
                      • 3264

                      #11
                      Code:
                      q.Element["whatever"].Value
                      Should give you the value of the first child node named "whatever"

                      Comment

                      • Samishii23
                        New Member
                        • Sep 2009
                        • 246

                        #12
                        The " [] " brackets didn't work, but the " () " did. Thanks!

                        Comment

                        • Curtis Rutland
                          Recognized Expert Specialist
                          • Apr 2008
                          • 3264

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

                          Comment

                          Working...