1

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

1)。我需要找到<O>上面示例中的最后一个标签 < O> < Name = "O9" /> < /O> . 2). I also need to get the parentR Name andFP Name if exists for a particularO`

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

谢谢

4

2 回答 2

1

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

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

笔记

  1. 因为 FP 和 Rs 位于顶层的不同集合中,所以无法像在源 XML 中那样知道它们的文档顺序。我假设 Rs 跟随 FPs inside ReplyH,就像代码显示的那样(示例 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'
于 2012-10-30T00:15:59.883 回答
1

这里使用 Xml.Linq:更新另请参阅更新问题的竞争答案

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'
于 2012-10-29T23:38:32.630 回答