Xml 转换以删除重复项并复制其余项
我希望输出xml已根据属性“f”为元素“c”分组。这是我的输入xml和xslt。我希望组只出现一次,其他节点应按原样复制到输出。我尝试的xslt复制了整个输入xml。因此,如果有两个或多个元素具有c元素,并且“f”的属性值相同,则希望该组的第一个出现出现在输出中。我想要的结果也被复制了 输入xmlXml 转换以删除重复项并复制其余项,xml,xslt,xslt-1.0,Xml,Xslt,Xslt 1.0,我希望输出xml已根据属性“f”为元素“c”分组。这是我的输入xml和xslt。我希望组只出现一次,其他节点应按原样复制到输出。我尝试的xslt复制了整个输入xml。因此,如果有两个或多个元素具有c元素,并且“f”的属性值相同,则希望该组的第一个出现出现在输出中。我想要的结果也被复制了 输入xml <M> <a> <b> <c f="123"> <d>Al</d>
<M>
<a>
<b>
<c f="123">
<d>Al</d>
<e NO="678">
<f>Y</f>
<g>
<h>FTO</h>
</g>
</e>
</c>
</b>
</a>
<a>
<b>
<c f="123">
<d>Al</d>
<e NO="678">
<f>Y</f>
<g>
<h>FTO</h>
</g>
</e>
</c>
</b>
</a>
<a>
<b>
<c f="567">
<d>Al</d>
<e NO="678">
<f>Y</f>
<g>
<h>FTO</h>
</g>
</e>
</c>
</b>
</a>
<a>
<b>
<somethingelse></somethingelse>
</b>
</a>
</M>
艾尔
Y
FTO
艾尔
Y
FTO
艾尔
Y
FTO
想要输出xml
<M>
<a>
<b>
<c f="123">
<d>Al</d>
<e NO="678">
<f>Y</f>
<g>
<h>FTO</h>
</g>
</e>
</c>
</b>
</a>
<a>
<b>
<c f="567">
<d>Al</d>
<e NO="678">
<f>Y</f>
<g>
<h>FTO</h>
</g>
</e>
</c>
</b>
</a>
<a>
<b>
<somethingelse></somethingelse>
</b>
</a>
</M>
艾尔
Y
FTO
艾尔
Y
FTO
我试过的xslt
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:key name="mykey" match="c"
use="@f"/>
<xsl:template match=
"c[generate-id()
=
generate-id(key('mykey',@f)[1])
]
">
<xsl:text/>
<xsl:copy-of select="key('mykey',@f)[1]"/>
</xsl:template>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
一个想法可能是将c的所有值保存在一个变量中,保存格式允许您将它们彼此区分开来,然后每次遇到c时,您都会检查该值是否包含在该变量中。如果是,请跳到下一个节点。如果不是,请继续处理当前节点 如果您需要更具体的信息,请告诉我
编辑:作为一种替代方法,并且可能是一种更简单的方法(我最近一直在使用NAnt,所以我可能会给你一个NAnt策略),就是根据节点的s值对所有节点进行排序。然后用一个变量存储c的当前值,并进行比较,直到看到的值不等于存储的值。然后重新分配该值并再次执行 一个简单的解决方案是只为以下所有
c
节点添加一个空模板:
<xsl:template match="c[generate-id() = generate-id(key('mykey',@f)[position() > 1])]" />
您可以匹配
元素,并检查它们的
子元素中是否有任何前面的同级元素具有相同的f
属性。如果存在,您已找到给定f
值的副本(给定f
值的出现不是该值的第一次出现),您可以覆盖标识模板以跳过元素:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/M/a[b/c/@f = preceding-sibling::a/b/c/@f]"/>
</xsl:stylesheet>
此解决方案的一个优点是,它不需要任何关于密钥或ID生成的知识;它只适用于基本的XPath轴功能。但是,当要比较的元素不都在相同的嵌套深度/相同的相对元素层次结构中时,可能会变得稍微复杂一些
备注:我删除了
元素,因为我无法测试它(我的Xml处理器声称我只能在传递可读流而不是文件时使用它),但如果它对您有效,请随时重新插入它。此转换:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:key name="kAByC-F" match="a" use="*/c/@f"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match=
"a[*/c
and
not(generate-id()
=
generate-id(key('kAByC-F', */c/@f)[1])
)
]"/>
</xsl:stylesheet>
<M>
<a>
<b>
<c f="123">
<d>Al</d>
<e NO="678">
<f>Y</f>
<g>
<h>FTO</h>
</g>
</e>
</c>
</b>
</a>
<a>
<b>
<c f="123">
<d>Al</d>
<e NO="678">
<f>Y</f>
<g>
<h>FTO</h>
</g>
</e>
</c>
</b>
</a>
<a>
<b>
<c f="567">
<d>Al</d>
<e NO="678">
<f>Y</f>
<g>
<h>FTO</h>
</g>
</e>
</c>
</b>
</a>
<a>
<b>
<somethingelse></somethingelse>
</b>
</a>
</M>
<M>
<a>
<b>
<c f="123">
<d>Al</d>
<e NO="678">
<f>Y</f>
<g>
<h>FTO</h>
</g>
</e>
</c>
</b>
</a>
<a>
<b>
<c f="567">
<d>Al</d>
<e NO="678">
<f>Y</f>
<g>
<h>FTO</h>
</g>
</e>
</c>
</b>
</a>
<a>
<b>
<somethingelse/>
</b>
</a>
</M>
应用于提供的XML文档时:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:key name="kAByC-F" match="a" use="*/c/@f"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match=
"a[*/c
and
not(generate-id()
=
generate-id(key('kAByC-F', */c/@f)[1])
)
]"/>
</xsl:stylesheet>
<M>
<a>
<b>
<c f="123">
<d>Al</d>
<e NO="678">
<f>Y</f>
<g>
<h>FTO</h>
</g>
</e>
</c>
</b>
</a>
<a>
<b>
<c f="123">
<d>Al</d>
<e NO="678">
<f>Y</f>
<g>
<h>FTO</h>
</g>
</e>
</c>
</b>
</a>
<a>
<b>
<c f="567">
<d>Al</d>
<e NO="678">
<f>Y</f>
<g>
<h>FTO</h>
</g>
</e>
</c>
</b>
</a>
<a>
<b>
<somethingelse></somethingelse>
</b>
</a>
</M>
<M>
<a>
<b>
<c f="123">
<d>Al</d>
<e NO="678">
<f>Y</f>
<g>
<h>FTO</h>
</g>
</e>
</c>
</b>
</a>
<a>
<b>
<c f="567">
<d>Al</d>
<e NO="678">
<f>Y</f>
<g>
<h>FTO</h>
</g>
</e>
</c>
</b>
</a>
<a>
<b>
<somethingelse/>
</b>
</a>
</M>
你不能用
替换整个第二个模板吗?@DevNull:可能吧。不过,我想我已经遇到并阅读了一些关于模板match
属性中不支持某些约束的XPath表达式的内容。现在我再也找不到它了,但它让我当时很头痛:-/@DevNull:你说得对;我所记得的只是使用参数值。我在回答中简化了代码。谢谢。只有这样才能删除重复的c
元素——但是,任务是删除每个重复元素的a
祖先中的完整子树。这就是我在回答中提供的解决方案所做的。嗯。。。我必须再仔细考虑一下(我仍然面临着明钦族的挑战,但渴望学习)。有趣的是,它似乎产生了期望的输出。顺便说一句:您(显示)的输出遗漏了包含
的部分(尚未尝试xslt)。