简体   繁体   中英

Descendants within descendants in LINQ to XML

I'm struggling to navigate to my 'user' element in my XML; I want a set of users so I can then extract username details. My LINQ query is as follows and always returns 0 for the count (though is not null)

var xApprovers = from d in doc.Root.Descendants("document_version")
                               .Elements("stages")
                               .Elements("stage")
                               .Elements("user")
                               .Elements("approver_list")
                               .Elements("approver")
                               .Elements("user")
                 where d.Element("docVersionID").Value == vId
                 select d;

My XML source is:

<Root>
<document_version>
    <version_number>1</version_number>
    <version_comments></version_comments>
    <creation_date>2011-12-20 09:20:42.877</creation_date>
    <docVersionID>00002_0000000453</docVersionID>
    <pageno>-1</pageno>
    <author>
      <user>
        <userID>00002_0000000001</userID>
        <login>ACRE_ROBOT</login>
        <lastname>ROBOT</lastname>
        <firstname>ACRE</firstname>
        <email>richardtaylor@vcg-kestrel.com</email>
      </user>
    </author>
    <document_approval_cycle_code>0</document_approval_cycle_code>
    <document_approval_cycle_status>Not Started</document_approval_cycle_status>
    <stage_index>1</stage_index>
    <stages>
      <stage>
        <stage_id>00002_0000001017</stage_id>
        <name></name>
        <index>1</index>
        <conditional_approval>1</conditional_approval>
        <upon_rejection_code>0</upon_rejection_code>
        <stage_approval_cycle_code>0</stage_approval_cycle_code>
        <stage_approval_cycle_status>Not Started</stage_approval_cycle_status>
        <stage_approval_code>00001_0000000002</stage_approval_code>
        <stage_approval_status>Pending</stage_approval_status>
        <approver_list>
          <approver>
            <user>
              <userID>00002_0000000011</userID>
              <login>DEVAPP78@APPROVER.COM</login>
              <lastname>App 78</lastname>
              <firstname>Dev</firstname>
              <email>DevApp78@approver.com</email>
            </user>
            <approval_action />
          </approver>
          <approver>
            <user>
              <userID>00002_0000000010</userID>
              <login>DEVAPP77@APPROVER.COM</login>
              <lastname>App 77</lastname>
              <firstname>Dev</firstname>
              <email>DevApp77@approver.com</email>
            </user>
            <approval_action />
          </approver>
        </approver_list>
      </stage>
    </stages>
    <approvals></approvals>
</document_version>
</Root>

What am I doing wrong? Thanks in advance.

you have an extra user selection. Try

var xApprovers = from d in doc.Root
                              .Descendants("document_version")
                 where d.Element("docVersionID").Value == vId
                 select d.Elements("stages")
                              .Elements("stage")
                              .Elements("approver_list")
                              .Elements("approver")
                              .Elements("user");

You had two problems, you had an extra .Elements("user") which wasn't necessary

You also were trying to apply the where clause to the wrong element

Here's the corrected LINQ which returns the result in the same IEnumerable<XElement> as your original

  var xGood = from docVersion in doc.Root.Descendants( "document_version" )
              where docVersion.Element("docVersionID").Value == vId
              from d in docVersion.Elements( "stages" )
                                  .Elements( "stage" )
                                  .Elements( "approver_list" )
                                  .Elements( "approver" )
                                  .Elements( "user" )
              select d;

The notable difference between this LINQ and abatishchev's is that this would support multiple document_version nodes in a single xml document

Why don't just this:

from d in doc.Root.Descendants("document_version")
where d.Element("docVersionID").Value == vId
select d.Elements("stages")
        .Elements("stage")
        .Elements("approver_list")
        .Elements("approver")
        .Elements("user");

or

doc.Root
   .Descendants("document_version")
   .SingleOrDefault(d => d.Element("docVersionID").Value == vId).Elements("stages") // sic!
   .Elements("stage")
   .Elements("approver_list")
   .Elements("approver")
   .Elements("user");

Or run XPath:

(IEnumerable)doc.XPathEvaluate(String.Format("Root/document_version/docVersionID[text()='{0}']/../stages/stage/approver_list/approver/user", vId));

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM