Xslt 如何根据多个属性的值消除重复节点?
如何基于多个(1个以上)属性的值消除重复节点?属性名也作为参数传递给样式表。现在我知道了使用Xslt 如何根据多个属性的值消除重复节点?,xslt,xslt-1.0,Xslt,Xslt 1.0,如何基于多个(1个以上)属性的值消除重复节点?属性名也作为参数传递给样式表。现在我知道了使用元素的Muenchian分组方法。但是我知道XSLT1.0不允许中的参数/变量 是否有其他方法实现重复节点的删除?如果它没有穆尼钦方法那么有效,那就好了 从previus更新: XML: <data id = "root"> <record id="1" operator1='xxx' operator2='yyy' operator3='zzz'/> <record
元素的Muenchian分组方法。但是我知道XSLT1.0不允许
中的参数/变量
是否有其他方法实现重复节点的删除?如果它没有穆尼钦方法那么有效,那就好了
从previus更新:
XML:
<data id = "root">
<record id="1" operator1='xxx' operator2='yyy' operator3='zzz'/>
<record id="2" operator1='abc' operator2='yyy' operator3='zzz'/>
<record id="3" operator1='abc' operator2='yyy' operator3='zzz'/>
<record id="4" operator1='xxx' operator2='yyy' operator3='zzz'/>
<record id="5" operator1='xxx' operator2='lkj' operator3='tyu'/>
<record id="6" operator1='xxx' operator2='yyy' operator3='zzz'/>
<record id="7" operator1='abc' operator2='yyy' operator3='zzz'/>
<record id="8" operator1='abc' operator2='yyy' operator3='zzz'/>
<record id="9" operator1='xxx' operator2='yyy' operator3='zzz'/>
<record id="10" operator1='rrr' operator2='yyy' operator3='zzz'/>
</data>
如果您想将属性名作为参数传入,那么一种方法可以是两步转换,第一步接受任何XML输入,只需将属性名和元素名作为参数来生成第二个样式表,然后消除重复项。 以下是第一个样式表示例:
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:exsl="http://exslt.org/common"
xmlns:axsl="http://www.w3.org/1999/XSL/TransformAlias"
exclude-result-prefixes="axsl exsl"
version="1.0">
<xsl:param name="parent-name" select="'items'"/>
<xsl:param name="element-name" select="'item'"/>
<xsl:param name="att-names" select="'att1,att2'"/>
<xsl:param name="sep" select="'|'"/>
<xsl:namespace-alias stylesheet-prefix="axsl" result-prefix="xsl"/>
<xsl:output method="xml" indent="yes"/>
<xsl:variable name="key-value">
<xsl:text>concat(</xsl:text>
<xsl:call-template name="define-values">
<xsl:with-param name="att-names" select="$att-names"/>
</xsl:call-template>
<xsl:text>)</xsl:text>
</xsl:variable>
<xsl:template name="define-values">
<xsl:param name="att-names"/>
<xsl:choose>
<xsl:when test="contains($att-names, ',')">
<xsl:value-of select="concat('@', substring-before($att-names, ','), ',"', $sep, '",')"/>
<xsl:call-template name="define-values">
<xsl:with-param name="att-names" select="substring-after($att-names, ',')"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="concat('@', $att-names)"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="/">
<axsl:stylesheet version="1.0">
<axsl:output indent="yes"/>
<axsl:key name="k1" match="{$parent-name}/{$element-name}" use="{$key-value}"/>
<axsl:template match="@* | node()">
<axsl:copy>
<axsl:apply-templates select="@* | node()"/>
</axsl:copy>
</axsl:template>
<axsl:template match="{$parent-name}">
<axsl:copy>
<axsl:apply-templates select="@*"/>
<axsl:apply-templates select="{$element-name}[generate-id() = generate-id(key('k1', {$key-value})[1])]"/>
</axsl:copy>
</axsl:template>
</axsl:stylesheet>
</xsl:template>
</xsl:stylesheet>
<axsl:stylesheet xmlns:axsl="http://www.w3.org/1999/XSL/Transform" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<axsl:output indent="yes"/>
<axsl:key name="k1" match="items/item" use="concat(@att1,"|",@att2)"/>
<axsl:template match="@* | node()">
<axsl:copy>
<axsl:apply-templates select="@* | node()"/>
</axsl:copy>
</axsl:template>
<axsl:template match="items">
<axsl:copy>
<axsl:apply-templates select="@*"/>
<axsl:apply-templates select="item[generate-id() = generate-id(key('k1', concat(@att1,"|",@att2))[1])]"/>
</axsl:copy>
</axsl:template>
</axsl:stylesheet>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ext="http://exslt.org/common">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:param name="pAttribs">
<name>operator1</name>
<name>operator2</name>
<name>operator3</name>
</xsl:param>
<xsl:variable name="vAttribs" select=
"document('')/*/xsl:param[@name='pAttribs']"/>
<xsl:key name="kRecByAtts" match="record"
use="@___g_key"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/">
<xsl:variable name="vrtdPass1">
<xsl:apply-templates/>
</xsl:variable>
<xsl:variable name="vPass1" select=
"ext:node-set($vrtdPass1)/*"/>
<xsl:apply-templates select="$vPass1"/>
</xsl:template>
<xsl:template match="record[not(@___g_key)]">
<xsl:copy>
<xsl:copy-of select="@*"/>
<xsl:attribute name="___g_key">
<xsl:for-each select="@*[name()=$vAttribs/name]">
<xsl:sort select="name()"/>
<xsl:value-of select=
"concat('___Attrib___',name(),'___Value___',.,'+++')"/>
</xsl:for-each>
</xsl:attribute>
</xsl:copy>
</xsl:template>
<xsl:template match=
"record[@___g_key]
[not(generate-id()
=
generate-id(key('kRecByAtts', @___g_key)[1])
)
]
"/>
<xsl:template match="@___g_key"/>
</xsl:stylesheet>
这可以应用于XML文档,如
<items>
<item att1="a" att2="1" att3="A"/>
<item att1="b" att2="1" att3="A"/>
<item att1="a" att2="1" att3="B"/>
<item att1="c" att2="2" att3="A"/>
<item att1="d" att2="3" att3="C"/>
</items>
输出是
<items>
<item att1="a" att2="1" att3="A"/>
<item att1="b" att2="1" att3="A"/>
<item att1="c" att2="2" att3="A"/>
<item att1="d" att2="3" att3="C"/>
</items>
如果希望将属性名称作为参数传入,那么一种方法可以是两步转换,第一步采用任何XML输入,仅将属性名称和元素名称作为参数,以生成第二个样式表,然后消除重复项。 以下是第一个样式表示例:
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:exsl="http://exslt.org/common"
xmlns:axsl="http://www.w3.org/1999/XSL/TransformAlias"
exclude-result-prefixes="axsl exsl"
version="1.0">
<xsl:param name="parent-name" select="'items'"/>
<xsl:param name="element-name" select="'item'"/>
<xsl:param name="att-names" select="'att1,att2'"/>
<xsl:param name="sep" select="'|'"/>
<xsl:namespace-alias stylesheet-prefix="axsl" result-prefix="xsl"/>
<xsl:output method="xml" indent="yes"/>
<xsl:variable name="key-value">
<xsl:text>concat(</xsl:text>
<xsl:call-template name="define-values">
<xsl:with-param name="att-names" select="$att-names"/>
</xsl:call-template>
<xsl:text>)</xsl:text>
</xsl:variable>
<xsl:template name="define-values">
<xsl:param name="att-names"/>
<xsl:choose>
<xsl:when test="contains($att-names, ',')">
<xsl:value-of select="concat('@', substring-before($att-names, ','), ',"', $sep, '",')"/>
<xsl:call-template name="define-values">
<xsl:with-param name="att-names" select="substring-after($att-names, ',')"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="concat('@', $att-names)"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="/">
<axsl:stylesheet version="1.0">
<axsl:output indent="yes"/>
<axsl:key name="k1" match="{$parent-name}/{$element-name}" use="{$key-value}"/>
<axsl:template match="@* | node()">
<axsl:copy>
<axsl:apply-templates select="@* | node()"/>
</axsl:copy>
</axsl:template>
<axsl:template match="{$parent-name}">
<axsl:copy>
<axsl:apply-templates select="@*"/>
<axsl:apply-templates select="{$element-name}[generate-id() = generate-id(key('k1', {$key-value})[1])]"/>
</axsl:copy>
</axsl:template>
</axsl:stylesheet>
</xsl:template>
</xsl:stylesheet>
<axsl:stylesheet xmlns:axsl="http://www.w3.org/1999/XSL/Transform" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<axsl:output indent="yes"/>
<axsl:key name="k1" match="items/item" use="concat(@att1,"|",@att2)"/>
<axsl:template match="@* | node()">
<axsl:copy>
<axsl:apply-templates select="@* | node()"/>
</axsl:copy>
</axsl:template>
<axsl:template match="items">
<axsl:copy>
<axsl:apply-templates select="@*"/>
<axsl:apply-templates select="item[generate-id() = generate-id(key('k1', concat(@att1,"|",@att2))[1])]"/>
</axsl:copy>
</axsl:template>
</axsl:stylesheet>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ext="http://exslt.org/common">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:param name="pAttribs">
<name>operator1</name>
<name>operator2</name>
<name>operator3</name>
</xsl:param>
<xsl:variable name="vAttribs" select=
"document('')/*/xsl:param[@name='pAttribs']"/>
<xsl:key name="kRecByAtts" match="record"
use="@___g_key"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/">
<xsl:variable name="vrtdPass1">
<xsl:apply-templates/>
</xsl:variable>
<xsl:variable name="vPass1" select=
"ext:node-set($vrtdPass1)/*"/>
<xsl:apply-templates select="$vPass1"/>
</xsl:template>
<xsl:template match="record[not(@___g_key)]">
<xsl:copy>
<xsl:copy-of select="@*"/>
<xsl:attribute name="___g_key">
<xsl:for-each select="@*[name()=$vAttribs/name]">
<xsl:sort select="name()"/>
<xsl:value-of select=
"concat('___Attrib___',name(),'___Value___',.,'+++')"/>
</xsl:for-each>
</xsl:attribute>
</xsl:copy>
</xsl:template>
<xsl:template match=
"record[@___g_key]
[not(generate-id()
=
generate-id(key('kRecByAtts', @___g_key)[1])
)
]
"/>
<xsl:template match="@___g_key"/>
</xsl:stylesheet>
这可以应用于XML文档,如
<items>
<item att1="a" att2="1" att3="A"/>
<item att1="b" att2="1" att3="A"/>
<item att1="a" att2="1" att3="B"/>
<item att1="c" att2="2" att3="A"/>
<item att1="d" att2="3" att3="C"/>
</items>
输出是
<items>
<item att1="a" att2="1" att3="A"/>
<item att1="b" att2="1" att3="A"/>
<item att1="c" att2="2" att3="A"/>
<item att1="d" att2="3" att3="C"/>
</items>
通过两个步骤实现单个转换的其他方法:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt"
exclude-result-prefixes="msxsl">
<xsl:key name="kItemByLocal" match="record[@local-key]" use="@local-key"/>
<xsl:param name="pAttNames" select="'operator1 operator2 operator3'"/>
<xsl:template match="/">
<xsl:variable name="vFirstRTF">
<xsl:apply-templates/>
</xsl:variable>
<xsl:apply-templates select="msxsl:node-set($vFirstRTF)/node()"/>
</xsl:template>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="record[not(@local-key)]">
<xsl:copy>
<xsl:attribute name="local-key">
<xsl:call-template name="local-key"/>
</xsl:attribute>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="record[@local-key]
[count(.|key('kItemByLocal',@local-key)[1])
!= 1]|@local-key"/>
<xsl:template name="local-key">
<xsl:param name="pAttributes" select="concat($pAttNames,' ')"/>
<xsl:if test="normalize-space($pAttributes)">
<xsl:variable name="vName"
select="substring-before($pAttributes,' ')"/>
<xsl:variable name="vAttribute" select="@*[name()=$vName]"/>
<xsl:value-of select="concat($vName,'+',$vAttribute,'+')"/>
<xsl:call-template name="local-key">
<xsl:with-param name="pAttributes"
select="substring-after($pAttributes,' ')"/>
</xsl:call-template>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
注意:如果您确信所有元素的属性顺序都相同,则可以删除排序。通过两个步骤实现单个转换的其他方法:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt"
exclude-result-prefixes="msxsl">
<xsl:key name="kItemByLocal" match="record[@local-key]" use="@local-key"/>
<xsl:param name="pAttNames" select="'operator1 operator2 operator3'"/>
<xsl:template match="/">
<xsl:variable name="vFirstRTF">
<xsl:apply-templates/>
</xsl:variable>
<xsl:apply-templates select="msxsl:node-set($vFirstRTF)/node()"/>
</xsl:template>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="record[not(@local-key)]">
<xsl:copy>
<xsl:attribute name="local-key">
<xsl:call-template name="local-key"/>
</xsl:attribute>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="record[@local-key]
[count(.|key('kItemByLocal',@local-key)[1])
!= 1]|@local-key"/>
<xsl:template name="local-key">
<xsl:param name="pAttributes" select="concat($pAttNames,' ')"/>
<xsl:if test="normalize-space($pAttributes)">
<xsl:variable name="vName"
select="substring-before($pAttributes,' ')"/>
<xsl:variable name="vAttribute" select="@*[name()=$vName]"/>
<xsl:value-of select="concat($vName,'+',$vAttribute,'+')"/>
<xsl:call-template name="local-key">
<xsl:with-param name="pAttributes"
select="substring-after($pAttributes,' ')"/>
</xsl:call-template>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
注意:如果确定所有元素的属性顺序都相同,则可以删除排序。使用此转换(简单且无需生成新样式表):
操作员1
操作员2
操作员3
应用于上一个问题的XML文档时:
<data id = "root">
<record id="1" operator1='xxx' operator2='yyy' operator3='zzz'/>
<record id="2" operator1='abc' operator2='yyy' operator3='zzz'/>
<record id="3" operator1='abc' operator2='yyy' operator3='zzz'/>
<record id="4" operator1='xxx' operator2='yyy' operator3='zzz'/>
<record id="5" operator1='xxx' operator2='lkj' operator3='tyu'/>
<record id="6" operator1='xxx' operator2='yyy' operator3='zzz'/>
<record id="7" operator1='abc' operator2='yyy' operator3='zzz'/>
<record id="8" operator1='abc' operator2='yyy' operator3='zzz'/>
<record id="9" operator1='xxx' operator2='yyy' operator3='zzz'/>
<record id="10" operator1='rrr' operator2='yyy' operator3='zzz'/>
</data>
<data id="root">
<record id="1" operator1="xxx" operator2="yyy" operator3="zzz"/>
<record id="2" operator1="abc" operator2="yyy" operator3="zzz"/>
<record id="5" operator1="xxx" operator2="lkj" operator3="tyu"/>
<record id="10" operator1="rrr" operator2="yyy" operator3="zzz"/>
</data>
生成所需的正确结果:
<data id = "root">
<record id="1" operator1='xxx' operator2='yyy' operator3='zzz'/>
<record id="2" operator1='abc' operator2='yyy' operator3='zzz'/>
<record id="3" operator1='abc' operator2='yyy' operator3='zzz'/>
<record id="4" operator1='xxx' operator2='yyy' operator3='zzz'/>
<record id="5" operator1='xxx' operator2='lkj' operator3='tyu'/>
<record id="6" operator1='xxx' operator2='yyy' operator3='zzz'/>
<record id="7" operator1='abc' operator2='yyy' operator3='zzz'/>
<record id="8" operator1='abc' operator2='yyy' operator3='zzz'/>
<record id="9" operator1='xxx' operator2='yyy' operator3='zzz'/>
<record id="10" operator1='rrr' operator2='yyy' operator3='zzz'/>
</data>
<data id="root">
<record id="1" operator1="xxx" operator2="yyy" operator3="zzz"/>
<record id="2" operator1="abc" operator2="yyy" operator3="zzz"/>
<record id="5" operator1="xxx" operator2="lkj" operator3="tyu"/>
<record id="10" operator1="rrr" operator2="yyy" operator3="zzz"/>
</data>
使用此转换(简单且无需生成新样式表):
操作员1
操作员2
操作员3
应用于上一个问题的XML文档时:
<data id = "root">
<record id="1" operator1='xxx' operator2='yyy' operator3='zzz'/>
<record id="2" operator1='abc' operator2='yyy' operator3='zzz'/>
<record id="3" operator1='abc' operator2='yyy' operator3='zzz'/>
<record id="4" operator1='xxx' operator2='yyy' operator3='zzz'/>
<record id="5" operator1='xxx' operator2='lkj' operator3='tyu'/>
<record id="6" operator1='xxx' operator2='yyy' operator3='zzz'/>
<record id="7" operator1='abc' operator2='yyy' operator3='zzz'/>
<record id="8" operator1='abc' operator2='yyy' operator3='zzz'/>
<record id="9" operator1='xxx' operator2='yyy' operator3='zzz'/>
<record id="10" operator1='rrr' operator2='yyy' operator3='zzz'/>
</data>
<data id="root">
<record id="1" operator1="xxx" operator2="yyy" operator3="zzz"/>
<record id="2" operator1="abc" operator2="yyy" operator3="zzz"/>
<record id="5" operator1="xxx" operator2="lkj" operator3="tyu"/>
<record id="10" operator1="rrr" operator2="yyy" operator3="zzz"/>
</data>
生成所需的正确结果:
<data id = "root">
<record id="1" operator1='xxx' operator2='yyy' operator3='zzz'/>
<record id="2" operator1='abc' operator2='yyy' operator3='zzz'/>
<record id="3" operator1='abc' operator2='yyy' operator3='zzz'/>
<record id="4" operator1='xxx' operator2='yyy' operator3='zzz'/>
<record id="5" operator1='xxx' operator2='lkj' operator3='tyu'/>
<record id="6" operator1='xxx' operator2='yyy' operator3='zzz'/>
<record id="7" operator1='abc' operator2='yyy' operator3='zzz'/>
<record id="8" operator1='abc' operator2='yyy' operator3='zzz'/>
<record id="9" operator1='xxx' operator2='yyy' operator3='zzz'/>
<record id="10" operator1='rrr' operator2='yyy' operator3='zzz'/>
</data>
<data id="root">
<record id="1" operator1="xxx" operator2="yyy" operator3="zzz"/>
<record id="2" operator1="abc" operator2="yyy" operator3="zzz"/>
<record id="5" operator1="xxx" operator2="lkj" operator3="tyu"/>
<record id="10" operator1="rrr" operator2="yyy" operator3="zzz"/>
</data>
能否将示例xml和所需输出添加到问题中?能否将示例xml和所需输出添加到问题中question@Dimitre:这种生成新属性值的方法的唯一问题是缺少原始属性的可能性:如果没有@operator2
和一条没有@operator3
的记录
@Alejandro:谢谢你的另一个好观察。这是一个即时解决方案,我会在今天下午晚些时候做,到时候我有10分钟的空闲时间。@Alejandro:恭喜!欢迎来到10K+俱乐部。:)@迪米特:谢谢!我花了7个月的时间。。。啊@亚历杭德罗:我想我现在已经修好了。@Dimitre:我看到这种生成新属性值的方法的唯一问题是可能会丢失原始属性:没有@operator2
的记录和没有@operator3
的记录可能会发生键冲突@Alejandro:谢谢你的另一个好消息观察这是一个即时解决方案,我会在今天下午晚些时候做,到时候我有10分钟的空闲时间。@Alejandro:恭喜!欢迎来到10K+俱乐部。:)@迪米特:谢谢!我花了7个月的时间。。。啊@亚历杭德罗:我想我现在已经修好了。+1表示比我更小心,不监督明显的事情。+1表示比我更小心,不监督明显的事情。实际上,我还希望输入xml中的第三个节点在生成的输出中被删除。如果看到第三个节点,则不应删除,因为它是唯一的节点(根据所有3个属性,输入中没有其他节点与此节点完全相同)。如果单击了,请告诉我。我实际上还希望输入xml中的第三个节点在生成的输出中被删除。如果看到第三个节点,则不应删除,因为它是唯一的节点(根据所有3个属性,输入中没有其他节点与此节点完全相同)。如果点击,请告诉我。