LINQ to XML问题,将树转换为列表

时间:2017-07-13 20:53:44

标签: c# linq

我需要以下帮助才能从xml树返回一组嵌套列表:

样本数据:

<step>
  <sequence>
   <step>
    <type></type>
    <position>0</position>
  </step>
  <step>
    <type></type>
    <position>0</position>
  </step>
  <step>
    <type></type>
    <position>0</position>
  </step>
  <step>
    <type></type>
    <position>1</position>
  </step>
  <step>
    <type></type>
    <position>0</position>
  </step>
  <step>
    <sequence>
      <step>
        <position>0</position>
      </step>
      <step>
        <position>0</position>
      </step>
      <step>
        <position>0</position>
      </step>
      <step>
        <position>0</position>
      </step>
      <step>
        <position>0</position>
      </step>
    </sequence>
  </step>
  <step>
    <sequence>
      <step>
        <position>0</position>
      </step>
      <step>
        <position>0</position>
      </step>
      <step>
        <position>0</position>
      </step>
      <step>
        <position>0</position>
      </step>
    </sequence>
   </step>
  </sequence>  
</step>

我的代码:

        public List<InstructionSequence> GetSequenceFromSource(XDocument UriSource)
    {
        List<InstructionSequence> StepCollection = new List<InstructionSequence>();

        var u = from v in UriSource.Descendants("step")
                select new InstructionSequence
                {
                    step = Convert.ToInt16(v.Element("position").Value),
                    sequence = this.GetChildSequence(v)
                };

        return u.ToList<InstructionSequence>();


    }

    private List<InstructionSequence> GetChildSequence(XElement parent)
    {
        var u = (from v in parent.Descendants("step")
                 select new InstructionSequence
                 {
                     step = Convert.ToInt16(v.Element("position").Value),
                     sequence = null

                 });

        return u.ToList<InstructionSequence>();
    }

在一个变体中,我可以正确解析顶级,但不返回子节点 - 哪里出错了?

2 个答案:

答案 0 :(得分:1)

根据您提供的文件(这有点奇怪),您需要将其转换为InstructionSequence

public InstructionSequence GetSequenceFromSource(XDocument UriSource)
{
    return this.GetSequenceFromSource(UriSource.Root);
}

public InstructionSequence GetSequenceFromSource(XElement step)
{
    return new InstructionSequence
    {
        step = step.Element("position") == null ? 0 : (int)step.Element("position"),
        sequence = step.Element("sequence")?.Elements("step").Select(s => this.GetSequenceFromSource(s)).ToList(),
    };
}

请注意,您要求提供一个列表,但XML的根节点是step,因此您实际上只需要返回一个InstructionSequence(内部包含一个列表)。

我的代码是递归的,并且只要堆栈允许就会下降。

根据你问题的源数据,我得到了这个结果:

result

答案 1 :(得分:0)

var val = doc.Root
             .Descendants("sequence")
             .Descendants("step")
             .Where(e => (e.FirstNode is XElement) && (((XElement)e.FirstNode).Name != "sequence"))
             .Select(l => new InstructionSequence()
             {
                 step = Convert.ToInt32(l.Element("position").Value)
             });

这个听起来就像你想要的那样,但我不确定。您能否提供更多细节,我们可以从上述基础开始工作?也许一些样本输出?你提供的信息非常少。

编辑,解决方案#2:

Func<XElement, InstructionSequence> GetChildContents = child => new InstructionSequence { step = Convert.ToInt32(child.Element("position").Value), sequence = null };

var matchItems = new List<InstructionSequence>();

var splitGroups = doc.Root
    .Descendants("step")
    .GroupBy(v => (v.FirstNode is XElement) && (((XElement)v.FirstNode).Name != "sequence"));

    var matchGroup = splitGroups.Single(e => e.Key == true);
    var remaining = splitGroups.Single(e => e.Key == false);

    matchItems.AddRange(matchGroup.Select(GetChildContents));

    matchItems.AddRange(remaining.Descendants("sequence").Descendants("step").Select(GetChildContents));

这是你在找什么?就像我之前说过的那样,不是很多。 如果你的节点进一步嵌套,我可以为你添加递归到上面的解决方案。