【问题标题】:Find last record in nested list using linq使用 linq 查找嵌套列表中的最后一条记录
【发布时间】:2012-10-30 15:38:17
【问题描述】:

我有一个类似这样的嵌套 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(var O in H.FP.R.O) 和 foreach(var O in H.R.O)

1)。我需要找到上面示例中的最后一个 &lt;O&gt; 标记 . 2). I also need to get the parentRName andFPName if exists for a particularO`

我怎样才能使用 linq / lambda 表达式得到这个?

谢谢

【问题讨论】:

  • 我可以看看你的反序列化代码吗?我想知道数据反序列化后采用什么形式。

标签: linq


【解决方案1】:

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

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

备注

  1. 因为 FP 和 Rs 位于顶层的不同集合中,所以 无法 知道它们在源 XML 中的文档顺序。我假设 Rs 跟随 ReplyH 内的 FP,就像代码显示的那样(示例 XML 似乎也暗示了)。
  2. 我必须修复序列化类才能使用

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

    它在哪里(不小心?)在你的问题中说 XmlElement("Name")

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'

【讨论】:

  • @user1186390 这完全回答了您的问题。如果您意识到应该保持顺序,那么无论如何您的 XSD/序列化类都存在问题。我认为这个答案解决了所提出的问题(示例清楚地证明了这一点)。
  • 感谢您的所有帮助。如果没有 R,我将添加一个虚拟 FP,这样我仍然可以使用上面的解决方案来获取父母和祖父母。
【解决方案2】:

这里使用 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'

【讨论】:

  • 我用类更新了问题以进行反序列化。这只是一个巨大的 xml 和一个巨大的反序列化类的一部分。所以我现在不能改变使用 linq to xml :( 希望有出路
  • @user1186390 我已经为您更新的问题提供了another answer
  • 非常感谢您的回复。至于您在上面发布的 linq to object 答案,我确实有 和 的随机顺序,因此 不一定遵循 标签。所以这里的解决方案可能行不通。对于 linq to xml,我在 Win 8 Metro 风格的应用程序中实现它,看起来没有 System.xml.xpath。杀死它。
  • 如果排序有问题,请更改您的序列化类,这是没有办法
  • @user1186390 关于“谢谢” - 在Stack Overflow 上,如果您觉得答案有帮助,请点赞;如果它解决了你的问题,接受它:meta.stackexchange.com/questions/5234/…
猜你喜欢
  • 1970-01-01
  • 2022-01-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-11-29
  • 2016-03-27
  • 1970-01-01
相关资源
最近更新 更多