我有几个包含大量重复条目的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()
答案 0 :(得分:6)
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();
答案 1 :(得分: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]
并将其从父母身上删除。
答案 2 :(得分:0)
你可以在这里做几件事。除了到目前为止的其他答案,你可以注意到Distinct()有一个带有IEqualityComparer的重载。您可以使用like this ProjectionEqualityComparer来执行以下操作:
var images = xdoc.Descendants("image")
.Distinct(ProjectionEqualityComparer<XElement>.Create(xe => xe.Attributes("location").First().Value))
...它将为您提供具有唯一位置属性的所有独特“图像”元素。