Linq to XML simple get attribute from node statement

12,653

Solution 1

I think you want something closer to this:

XDocument themes = XDocument.Load(HttpContext.Current.Server.MapPath("~/Models/Themes.xml"));
string result = "";
var childType = from t in themes.Descendants("theme")
                where t.Attribute("name").Value.Equals(theme)
                select new { value = t.Descendants().Attribute("type").Value };

foreach (var t in childType) {
    result += t.value;
}
return result;

EDIT: Based on your additional info, perhaps this is even closer:

XDocument themes = XDocument.Load(HttpContext.Current.Server.MapPath("~/Models/Themes.xml"));
string result = "";
var childType = from t in themes.Descendants("theme")
                where t.Attribute("name").Value.Equals(theme)
                where t.Element("node").Attribute("type").Value == parent
                select new { value = t.Descendants().Attribute("type").Value };

foreach (var t in childType) {
    result += t.value;
}
return result;

EDIT 2: This is working for me:

XDocument themes = XDocument.Load(HttpContext.Current.Server.MapPath("~/Models/Themes.xml"));
string result = "";
var theme = "Agile";
var parent = "Project";
var childType = from t in themes.Descendants("theme")
            where t.Attribute("name").Value.Equals(theme)
            where t.Element("root").Attribute("type").Value == parent
            from children in t.Element("root").Descendants()
            select new { value = children.Attribute("type").Value };
foreach (var t in childType) {
    result += t.value;
}
return result;

EDIT 3: Here's the complete working program, just throw it in a class in a console application.

static void Main(string[] args)
        {
            var xml = "<themes><theme name='Agile'><root type='Project'><node type='Iteration' ><node type='Story'><node type='Task'/></node></node></root></theme><theme name='Release' ><root type='Project'><node type='Release'><node type='Task' /><node type='Defect' /></node></root></theme></themes>";
            XDocument themes = XDocument.Parse(xml);
            string result = "";
            var theme = "Agile";
            var parent = "Project";
            var childType = from t in themes.Descendants("theme")
                            where t.Attribute("name").Value.Equals(theme)
                            where t.Element("root").Attribute("type").Value == parent
                            from children in t.Element("root").Descendants()
                            select new { value = children.Attribute("type").Value };

            foreach (var t in childType)
            {
                Console.WriteLine(t.value);
            }

            Console.Read();

        }

Solution 2

Ok here's what I did in the end, it's not very pretty but it works. Its based on the answer by Pramodh with a few tweeks.

string result = "";
                var childType = themes.Descendants("theme")
                                               .Where(x => x.Attribute("name").Value == theme)
                                               .Where(x => x.Descendants("node").First().Attribute("type").Value == parentType)
                                               .Select(x => x.Descendants("node").First().Descendants().First().Attribute("type").Value);

                foreach (var t in childType) {
                    result += t;
                }
                return result;

now if I pass in theme "Agile" and parent "Iteration" it returns story.

Like I said not very pretty but it works.

Thank you to everyone who posted answers.

Share:
12,653
Morgeh
Author by

Morgeh

Web developer for Next-Plc currently working on Lipsy.co.uk. I graduate from Staffordshire University with a 2.1 in Computing Science. In my spare time I work on www.thedevgame.com and enjoy gaming and creating mods for games.

Updated on June 15, 2022

Comments

  • Morgeh
    Morgeh about 2 years

    Here's the code snippet:

    XDocument themes = XDocument.Load(HttpContext.Current.Server.MapPath("~/Models/Themes.xml"));
    string result = "";
    var childType = from t in themes.Descendants()
        where t.Attribute("name").Value.Equals(theme)
        select new { value = t.Attribute("type").Value };
    
    foreach (var t in childType) {
        result += t.value;
    }
    return result;
    

    and here's the XML:

    <?xml version="1.0" encoding="utf-8" ?>
    <themes>
      <theme name="Agile">
        <root type="Project">
          <node type="Iteration" >
            <node type="Story">
              <node type="Task"/>
            </node>
          </node>
        </root>
      </theme>
      <theme name="Release" >
        <root type="Project">
          <node type="Release">
            <node type="Task" />
            <node type="Defect" />
          </node>
        </root>
      </theme>
    </themes>
    

    What am I doing wrong? I keep getting an "object not set to an instance of an object" exception.

    What I'm trying to return is the type of the selected node based on the type of a parent node, i.e., if the theme is "Agile" and the parent node is "Project" then the return value should be "Iteration". That's the final outcome but I never got that far because I got stuck with what you see above.

  • Morgeh
    Morgeh over 13 years
    there isn't a method version of FirstNode its a property that doesn't have an attribute method.
  • Morgeh
    Morgeh over 13 years
    I had to add .First() to t.Descendants() within the select statement to get it to compile, however I'm still getting object not set to an instance of an object exceptions
  • Morgeh
    Morgeh over 13 years
    your 2nd edit is returning blank values for me. I couldn't be to do with the layout of my xml could it?
  • Chris Conway
    Chris Conway over 13 years
    I've updated again showing the complete working example based on what you've given. If it's still not working, take a look at your xml and make sure it's the same format as what I have. It should be working for you unless there's something else in the xml.