2014-09-12 53 views
0

我有几个XML文件包含大量重复的条目,如这些。高效地删除C#中的重复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(); 

但是,这并不工作,同样没有

+0

退房'GroupBy()' – 2014-09-12 16:18:34

回答

4
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(); 
+0

嘿,这就是为什么我不使用linq,我觉得很难遵循。这是对Linq的批评,而不是答案。 – Flynn1179 2014-09-12 16:39:49

+0

不''XDocument.parse()'接受一个字符串?或者如果我传递给我的文档的路径,它是否工作? – cyberbemon 2014-09-12 16:47:22

+0

用于传递XML文档路径使用'XDocument.Load' – 2014-09-12 17:34:59

0

如果重复总是以这种形式,那么你可以用一点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] 

,并从他们的父母将其删除。

0

有几件事你可以在这里做。除了迄今为止的其他答案,您可以注意到Distinct()具有一个需要IEqualityComparer的重载。你可以使用的东西like this ProjectionEqualityComparer做这样的事情:

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

...它会给你所有具有独特的区位属性,独特的“图像”元素。