mhn
mhn

Reputation: 2750

Select Nodes with specific attribute using Linq

I want my Linq statement to fetch only customfield with name="Required" in the below example

   <root>
    <appinfo>
        <application app_id=1234 app_name="SomeName">
        <customfield name="Required" value="123" />
        <customfield name="Not Required" value="234" />
        <customfield name="Not Required" value="345" />
        <customfield name="Not Required" value="456" />
        <customfield name="Not Required" value="678" />
        </application>
    </appinfo>
    ...
    </root>

1234,SomeName,123 needs to be picked in this case

Below is the statement I tried. The commented Where does not work

 var appAI =
        from appinfo in doc.Root.Elements()

        let application = appinfo.Elements().First()
        let custom_field = application.Descendants()

        //.Where(x => (string)x.Attribute("name") == "Required" && (string)x.Attribute("value").Value !="" )
        select new
        {
            app_id = (string)application.Attribute("app_id"),
            app_name = (string)application.Attribute("app_name"),
            app_AI = custom_field

        };

Upvotes: 2

Views: 1171

Answers (2)

Andrew Whitaker
Andrew Whitaker

Reputation: 126072

This seemed to work for me:

var results = 
    from appInfo in d.Elements()
    let application = appInfo.Elements().First()
    let custom_field = application.Descendants()
        .Where(x => x.Attribute("name").Value == "Required" && x.Attribute("value").Value != "")
        .SingleOrDefault()
    select new
    {
        app_id = application.Attribute("app_id").Value,
        app_name = application.Attribute("app_name").Value,
        app_AI = custom_field.Attribute("value").Value
    };

I think your main problem was looking at d.Root.Elements instead of just d.Elements.

Example: https://dotnetfiddle.net/XVM1qz

Upvotes: 1

Cory Nelson
Cory Nelson

Reputation: 30031

See if this will work. Note that you can chain "Elements" and some of the other extension methods directly off of IEnumerable<T> to make it a bit simpler.

from app in doc.Elements("appinfo").Elements("application")
from cf in app.Elements("customfield")
where (string)cf.Attribute("name") == "Required"
select new
{
    app_id = (string)app.Attribute("app_id"),
    app_name = (string)app.Attribute("app_name"),
    app_AI = (string)cf.Attribute("value")
};

Descendants is very rarely a useful method because it can hide potential structural issues in your document. I wouldn't use it unless I was performing validation elsewhere (like with a XSD).

Upvotes: 0

Related Questions