Linq XML - 使用父节点和组合的组合获得不同的值子节点

时间:2013-04-19 12:49:43

标签: xml linq distinct parent

我做了一个Linq语句,希望收到XML文件的所有节点。

foreach (var node in epaXmlLoad.Root.Descendants()
                                    .DescendantNodes()
                                    .OfType<XElement>()
                                    .Distinct())
{
    newEntity = true;
    xmlModel.Node = node.Name.ToString();
    xmlModel.ParentNode = node.Parent.Name.ToString();

    model.Save(xmlModel);
}

这会将节点和该节点的父节点保存在表中。

但是当我运行它时,表中会有重复的数据。 我无法区分节点值,因为有更多的子节点具有相同的名称,但上面有其他父节点。

<EPC>
<General>
    <Input>3</Invoer>
    <Amount>3</Amount>
    <Name>Bla</Name>
</General>
<Sectors>
    <Sector>
        <Name>Blalbla</Perc>
        <UsageID>0</UsageID>
        <Detection>0</Detection>
    <Sector>
    <Sector>
        <Name>Blalbla</Perc>
        <UsageID>0</UsageID>
        <Detection>0</Detection>
    <Sector>
<Sectors>
<Devices>
    <Device>
        <Name>Bladiebla</name>
        <Amount>5</Amount>
        <Detection>True</Detection>
    </Device>
    <Device>
        <Name>Bladiebla2</name>
        <Amount>5</Amount>
        <Detection>True</Detection>
    </Device>
<Devices>

^这个XML描述了我的问题。

1 个答案:

答案 0 :(得分:0)

虽然您的问题对预期结果不是很清楚,但您似乎正在尝试从XML中删除重复的节点。

XML:

<Parent>
  <Child>
    <Value>42</Value>
  </Child>
  <Child>
    <Value>stackoverflow</Value>
  </Child>
  <Child>
    <Value>stackoverflow</Value>
    <Grandchild>17</Grandchild>
  </Child>
  <Child>
    <Value>42</Value>
  </Child>
</Parent>

应转换为:

<Parent>
  <Child>
    <Value>42</Value>
  </Child>
  <Child>
    <Value>stackoverflow</Value>
  </Child>
  <Child>
    <Value>stackoverflow</Value>
    <Grandchild>17</Grandchild>
  </Child>
</Parent>

这需要对整棵树进行递归比较。在元素上使用Distinct将失败,因为它不会考虑孩子。

public static XElement Reduce(XElement root)
{
    XElement result = new XElement(root.Name);
    result.Add(root.Nodes().OfType<XText>());

    List<XElement> children = new List<XElement>();

    foreach (var child in root.Elements())
    {
        var reducedChild = Reduce(child);

        if (!children.Any(c => IsDuplicate(c, reducedChild)))
        {
            children.Add(reducedChild);
        }
    }

    result.Add(children);

    return result;
}

public static bool IsDuplicate(XElement element1, XElement element2)
{
    if (element1.Name != element2.Name || element1.Value != element2.Value)
    {
        return false;
    }

    var children1 = element1.Elements();
    var children2 = element2.Elements();

    if (children1.Count() != children2.Count())
    {
        return false;
    }

    return children1.Zip(children2, (c1, c2) => IsDuplicate(c1, c2)).All(isDup => isDup);
}

Reduce的根目录上调用XDocument将构建一个包含不同元素的新XElement。您现在可以将所有节点添加到模型中。

请注意,这不会考虑属性。还要注意,这可能不是最有效的算法。

BTW:您的示例XML充满了错误(标签未正确关闭)。