2010-02-12 143 views
3

我想使用XSLT将一组文档转换为一个结构。我有转换工作正确连接文档。不过,我不知道这些文件是否有重复的条目,我需要删除这些条目。基于属性的唯一xml节点

我需要知道如何通过id属性删除这些重复项(如果存在)。所有重复项都将具有相同的ID。我知道这将与按键和生成id功能有关。

<root> 
    <item id="1001">A</item> 
    <item id="1003">C</item> 
    <item id="1004">D</item> 
    <item id="1002">B</item> 
    <item id="1001">A</item> 
    <item id="1003">C</item> 
    <item id="1004">D</item> 
    <item id="1005">E</item> 
</root> 

我需要一个XSLT 1.0变换针对上述情况,基于以下...

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 

另外,有人能够解释它对我的作用吗?一个小白有点...

在此先感谢...

回答

3

常用的解决方案都带有使用generate-id(),但我个人更喜欢稍微不同的变化,不使用生成ID: -

<xsl:key name="items" match="item" use="@id" /> 

<xsl:template match="root"> 
    <root> 
     <xsl:copy-of select="item[count(key('items',@id)[1]|.)=1]" /> 
    </root> 
</xsl:template> 

首先创建持有使用id属性作为查找键的所有项元素的关键。 key生成可用于查找项目的高效索引。

该技术依赖于以下事实:当使用|运营商创建一个节点集你得到了一套独特的节点。换句话说,如果在|运算符的两侧找到相同的节点,它只会出现在结果集中一次。

的表达: -

key('items',@id) 

将返回一组具有特定ID的项目节点。所以: -

key('items',@id)[1] 

将只返回被发现的节点中的一个具有特定ID,是可重复的(即使用这种表达反复总是返回相同的节点)。

因此,表达式: -

count(key('items',@id)[1]|.)=1 

是只能用于与值的特定ID一个item节点真。因此

copy-of使得具有不同ID只有一个项目节点深层副本。

+0

@Anthony:我的$ 0.02 - 而'计数()'方法需要更少的空间,也很难理解。证明:长的解释。 :)'generate-id()'方法不太透明,这就是为什么我总是推荐使用后者。有*的*情况下'计数()'方法是唯一的选择,但他们是罕见的,相距甚远。 (编辑:静止,+1) – Tomalak 2010-02-12 13:04:52

3

这里提到的generate-id()方式@AnthonyWJones。我发现这个在人脑中更容易。结果没有区别,选择你最喜欢的。

<xsl:stylesheet 
    version="1.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
> 
    <xsl:key name="kItemById" match="item" use="@id" /> 

    <xsl:template match="root"> 
    <copy> 
     <xsl:copy-of select=" 
     item[generate-id() = generate-id(key('kItemById', @id)[1])] 
     " /> 
    </copy> 
    </xsl:template> 
</xsl:stylesheet> 

简而言之:

item[generate-id() = generate-id(key('kItemById', @id)[1])] 

意思是: “所有<item> S,其唯一ID等于第一物品的唯一ID具有相同@id值”。

+0

+1我同意使用产生-ID更容易理解。 – AnthonyWJones 2010-02-12 14:56:29