2014-09-12 28 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)) 

...它會給你所有具有獨特的區位屬性,獨特的「圖像」元素。