如何使用Linq to XML从XML文档中删除重复的,无效的子节点?

时间:2014-12-10 16:32:33

标签: c# xml linq xelement

我正在使用JsonConvert从HttpWebRequest调用中检索的JSON创建XML。我回来的JSON有时会有重复的节点,在转换后在XML中创建重复的节点,然后我必须将其删除。

JSON到XML转换的处理是在通用服务调用包装器中完成的,它不了解底层数据结构,因此不能基于命名节点进行任何XPath查询。重复项可以在XML中的任何级别。

我已经进入了一个阶段,我在每个级别都有一个重复节点名称的列表,但我不确定Linq查询使用它来删除除该名称的第一个节点以外的所有节点。

我的代码:

protected virtual void RemoveDuplicateChildren(XmlNode node)
{
    if (node.NodeType != XmlNodeType.Element || !node.HasChildNodes)
    {
        return;
    }

    var xNode = XElement.Load(node.CreateNavigator().ReadSubtree());
    var duplicateNames = new List<string>();

    foreach (XmlNode child in node.ChildNodes)
    {
        var isBottom = this.IsBottomElement(child); // Has no XmlNodeType.Element type children

        if (!isBottom)
        {
            this.RemoveDuplicateChildren(child);
        }
        else
        {
            var count = xNode.Elements(child.Name).Count();

            if (count > 1 && !duplicateNames.Contains(child.Name))
            {
                duplicateNames.Add(child.Name);
            }
        }
    }

    if (duplicateNames.Count > 0)
    {
        foreach (var duplicate in duplicateNames)
        {
            xNode.Elements(duplicate).SelectMany(d => d.Skip(1)).Remove();

        }
    }
}

代码的最后一行显然不正确,但是我找不到一个如何重新编写它以检索然后删除除第一个匹配元素之外的所有元素的示例。

更新: 我现在找到了两种方法,一种使用XElement,一种使用XmlNode,但实际上都没有删除节点。

方法1: -

foreach (var duplicate in duplicateNames)
{
    xNode.Elements(duplicate).Skip(1).Remove();
}

方法2: -

foreach (var duplicate in duplicateNames)
{
    var nodeList =  node.SelectNodes(duplicate);

    if (nodeList.Count > 1)
    {
        for (int i=1; i<nodeList.Count; i++)
        {
            node.RemoveChild(nodeList[i]);
         }
     }
}

我错过了什么?

2 个答案:

答案 0 :(得分:2)

如果您不想要任何重复的名称:(假设没有名称空间)

XElement root = XElement.Load(file); // .Parse(string)
List<string> names = root.Descendants().Distinct(x => x.Name.LocalName).ToList();
names.ForEach(name => root.Descendants(name).Skip(1).Remove());
root.Save(file); // or root.ToString()

答案 1 :(得分:0)

您可能会尝试在错误的级别解决问题。在XML中,拥有多个具有相同名称的节点是完全有效的。具有重复属性名称的JSON结构应该无效。您应该尝试在JSON级别进行此环境卫生,而不是在它已经转换为XML之后。

对于xml清理,这可能是一个起点:

 foreach (XmlNode child 
   in node.ChildNodes.Distinct(custom comparer that looks on node names))
{
.....
}