有效地删除c中重复的xml元素

本文关键字:xml 元素 删除 有效地 | 更新日期: 2023-09-27 18:21:50

我有两个XML文件,其中包含许多重复条目,比如这些。

<annotations>
  <annotation value=",Clear,Outdoors" eventID="2">
    <image location="Location 1" />
    <image location="Location 2" />
    <image location="Location 2" />
  </annotation>
  <annotation value=",Not a problem,Gravel,Shopping" eventID="2">
    <image location="Location 3" />
    <image location="Location 4" />
    <image location="Location 5" />
    <image location="Location 5" />
    <image location="Location 5" />
  </annotation>
</annotations>

我想删除每个子项中的重复元素。我处理这个问题的方法是将所有元素复制到一个列表中,然后进行比较,

 foreach (var el in xdoc.Descendants("annotation").ToList())
   {
      foreach (var x in el.Elements("image").Attributes("location").ToList())
       {
           //add elements to a list
       }
   }

进行到一半时,我意识到这是非常低效和耗时的。我对XML还很陌生,我想知道C#中是否有任何内置方法可以用来删除重复项?。

我试过使用

if(!x.value.Distinct()) // can't convert collections to bool
    x.Remove();

但这不起作用,也不起作用

if(x.value.count() > 1) // value.count returns the number of elements.
   x.Remove()

有效地删除c中重复的xml元素

using System.Xml.Linq;
XDocument xDoc = XDocument.Parse(xmlString);
xDoc.Root.Elements("annotation")
         .SelectMany(s => s.Elements("image")
                           .GroupBy(g => g.Attribute("location").Value)
                           .SelectMany(m => m.Skip(1))).Remove();

如果重复项总是以这种形式存在,那么您可以使用一些XSLT来删除重复的节点。这方面的XSLT是:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:template match="node()|@*">
    <xsl:copy>
      <xsl:apply-templates select="node()|@*"/>
    </xsl:copy>
  </xsl:template>
  <xsl:template match="image[@location = preceding-sibling::image/@location]"/>
</xsl:stylesheet>

如果这是经常发生的事情,那么将样式表加载到XslCompiledTransform实例中可能是值得的。

或者,您可以使用XPath:简单地获得所有重复节点的列表

/annotations/annotation/image[@location = preceding-sibling::image/@location]

并将它们从父对象中移除。

这里可以做一些事情。除了到目前为止的其他答案外,您还可以注意到Distinct()有一个重载,它需要一个IEqualityComparer。你可以使用类似ProjectionEqualityComparer的东西来做这样的事情:

var images = xdoc.Descendants("image")
    .Distinct(ProjectionEqualityComparer<XElement>.Create(xe => xe.Attributes("location").First().Value))

这将为您提供所有具有独特位置属性的独特"图像"元素。