2014-09-12 4 views
0

У меня есть несколько XML-файлов, содержащих много повторяющихся записей.Эффективное удаление повторяющихся элементов xml в C#

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()' –

ответ

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, я считаю, что на самом деле трудно следовать. Это критика Линка, а не ответ. – Flynn1179

+0

Не 'XDocument.parse()' принимает строку? или он работает, если я пройду по пути к моему документу ?. – cyberbemon

+0

для прохождения пути XML-документа используется «XDocument.Load» –

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)) 

... который даст вам все уникальные элементы «изображения», которые имеют уникальные атрибуты местоположение.

Смежные вопросы