使用linq查找嵌套列表中的最后一条记录

时间:2012-10-29 23:23:14

标签: linq

我有一个像这样的嵌套xml。

 < H>

   < FP >
       < Name="FP1"/>

       < R >
       < Name = "R1"/> 

            < O>
            < Name="O1"/>
            < /O>
            < O>
                < Name="O2"/>
            < /O>
     < /R>       
     < R>
     < Name = "R2"/>
         < O>
    < Name="O4"/>
          < /O>
     < /R>
< /FP>

< FP>
    < Name="FP2" />

    < R>
          < Name = "R3"/>

          < O>
             < Name="O5"/>
          < /O>
          < O>
             < Name="O6"/>
          < /O>
    < /R>
< /FP>

   < R> 
       < Name="R4"/>
       < O>
    < Name="O7"/>
   < /O>
        < O>
            < Name="O8"/>
        < /O>
     < /R>
 < R>
     < Name="R5"/>
     < O >
          < Name="O9"/>
     < /O>
  < /R>

< /H>

我正在使用反序列化来读取这个xml。

这是我的反序列化类:

[XmlRoot("H")]
public class ReplyH
{
    [XmlElement("FP")]
    public List<ReplyFP> FPs;

    [XmlElement("R")]
    public List<ReplyR> Rs;

}

public class ReplyFP
{
    [XmlElement("Name")]
    public string Name;

    [XmlElement("R")]
    public List<ReplyR> Rs = new List<ReplyR>();
}


public class ReplyR
{
    [XmlElement("Name")]
    public string Name;

    [XmlElement("O")]
    public List<ReplyO> Os = new List<ReplyO>();
}


public class ReplyO
{
    [XmlElement("Name")]
    public string Name;
}

我需要迭代O标签。

类似于foreach(H.FP.R.O中的var O)和foreach(H.R.O中的var O)

1)。我需要找到上面示例中的最后一个<O>标记 &LT; O&GT; &LT;名称=“O9”/&gt; &LT; / O&GT; . 2). I also need to get the parent环R Name and {FP {1}} O`

如何使用linq / lambda表达式获取此信息?

由于

2 个答案:

答案 0 :(得分:1)

以下是使用Xml.Linq:更新另请参阅competing answer for updated question

using System.Linq;
using System.Xml.Linq;
using System.Xml.XPath;
using System;

public class stuff
{
    public static void Main(string[] args)
    {
        var doc = XDocument.Parse(xml);

        var last = doc.Root
            .XPathSelectElements("//H/FP/R/O | //H/R/O")
            .Last();

        Console.WriteLine(last);
        Console.WriteLine("Parent R has name '{0}'", last.Parent.Attribute("Name").Value);

        var granddad = last.Parent.Parent;
        if (granddad.Name == "FP")
            Console.WriteLine("Parent FP has name '{0}'", granddad.Attribute("Name").Value);
    }

    const string xml = @"<H>
        <FP Name=""FP1"">
            <R Name=""R1""> 
                <O Name=""O1""/>
                <O Name=""O2""/>
            </R>       
            <R Name=""R2"">
                <O Name=""O4""/>
            </R>
        </FP>
        <FP Name=""FP2"">
            <R Name=""R3"">
                <O Name=""O5""/>
                <O Name=""O6""/>
            </R>
        </FP>
    <!--
        <R Name=""R4"">
            <O Name=""O7""/>
            <O Name=""O8""/>
        </R>
        <R Name=""R5"">
            <O Name=""O9""/>
        </R>
    -->
        </H>";
}

输出

<O Name="O6" />
Parent R has name 'R3'
Parent FP has name 'FP2'

如果取消注释XML的最后一部分:

<!--
    <R Name=""R4"">
        <O Name=""O7""/>
        <O Name=""O8""/>
    </R>
    <R Name=""R5"">
        <O Name=""O9""/>
    </R>
-->

输出变为:

<O Name="O9" />
Parent R has name 'R5'

答案 1 :(得分:1)

对于更新的问题,使用Linq-to-objects更新答案。

代码不如Linq-to-XML falvour优雅,但它可以工作。

  

备注

     
      
  1. 因为FPs和Rs位于顶层的不同集合中,所以没有办法知道他们的文档排序,就像在源XML中一样。我假设Rs遵循ReplyH内的FP,就像代码所示(并且样本XML似乎也暗示)。
  2.   
  3. 我必须修复序列化类才能使用

    [XmlAttribute("Name")] public string Name;
    
         

    在哪里(意外?)在您的问题中说XmlElement("Name")

  4.   
using System.Collections.Generic;
using System.Xml.Serialization;
using System.Linq;
using System.IO;
using System;

public class Program
{
    public static void Main(string[] args)
    {
        ReplyH doc;
        using (var reader = new StringReader(xml))
            doc = (ReplyH) new XmlSerializer(typeof(ReplyH)).Deserialize(reader);

        var Rs = doc.FPs
            .SelectMany(fp => fp.Rs.Select(r => new { Parent = fp            , R=r }))
            .Concat    (     doc.Rs.Select(r => new { Parent = (ReplyFP) null, R=r }));

        var Os = Rs.SelectMany(r => r.R.Os.Select(o => new { Parent = r, O=o }));

        var lastO = Os.Last();
        Console.WriteLine(lastO.O.Name);

        if (lastO != null)
        {
            Console.WriteLine("Parent R has name '{0}'", lastO.Parent.R.Name);

            ReplyFP granddad = lastO.Parent.Parent;
            if (granddad != null)
                Console.WriteLine("Parent FP has name '{0}'", granddad.Name);
        }
    }

    const string xml = @"<H>
        <FP Name=""FP1"">
            <R Name=""R1""> 
                <O Name=""O1""/>
                <O Name=""O2""/>
            </R>       
            <R Name=""R2"">
                <O Name=""O4""/>
            </R>
        </FP>
        <FP Name=""FP2"">
            <R Name=""R3"">
                <O Name=""O5""/>
                <O Name=""O6""/>
            </R>
        </FP>
    <!--
        <R Name=""R4"">
            <O Name=""O7""/>
            <O Name=""O8""/>
        </R>
        <R Name=""R5"">
            <O Name=""O9""/>
        </R>
    -->
        </H>";
}

[XmlRoot("H")] public class ReplyH {
    [XmlElement("FP")] public List<ReplyFP> FPs = new List<ReplyFP>();
    [XmlElement("R")] public List<ReplyR> Rs = new List<ReplyR>();
}

public class ReplyFP {
    [XmlAttribute("Name")] public string Name; 
    [XmlElement("R")] public List<ReplyR> Rs = new List<ReplyR>();
}

public class ReplyR {
    [XmlAttribute("Name")] public string Name; 
    [XmlElement("O")] public List<ReplyO> Os = new List<ReplyO>();
}

public class ReplyO {
    [XmlAttribute("Name")] public string Name;
}

输出:

O6
Parent R has name 'R3'
Parent FP has name 'FP2'

或者在取消评论最后一个XML块之后:

O9
Parent R has name 'R5'