我是xslt的新手,我担心这个问题取决于我是否会陷入程序化的思维模式。
我有一组我要重命名的信息,在某些情况下,还有一些信息。我可以处理重命名,但是冷凝让我感到高兴。我的方法是重命名所有内容,然后,如果重命名产生重复,则删除重复项。为了清楚起见,这里有一些代码。
输入:
<variables>
<var value="a-value"> a </var>
<var value="b-value"> b </var>
<var value="c-value"> c </var>
<var value="d-value"> d </var>
</variables>
所需的输出:
<variables>
<var value="new-a-value"> new-a </var>
<var value="new-b-and-c-value"> new-b-and-c </var>
<var value="new-d-value"> new-d </var>
</variables>
我的xslt:
<xsl:for-each select="var">
<xsl:choose>
<xsl:when test="@value = 'a-value'">
<var value="new-a-value"> new-a </var>
</xsl:when>
<xsl:when test="@value = 'b-value'">
<var value="new-b-and-c-value"> new-b-and-c </var>
</xsl:when>
<xsl:when test="@value = 'c-value'">
<var value="new-b-and-c-value"> new-b-and-c </var>
</xsl:when>
<xsl:when test="@value = 'd-value'">
<var value="new-d-value"> new-d </var>
</xsl:when>
</xsl:choose>
</xsl:for-each>
我想在重命名后删除重复的条款。我不知道从哪里开始。我的直觉促使我想要在找到b值或c值时设置一些检查,或者通过中间处理的xml运行另一次迭代来删除重复项,但我不认为这两种方法都是在xslt中可行。
答案 0 :(得分:3)
重构:更简单,让真正的问题变得清晰:对映射的键值进行分组。
此样式表:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:v="value"
exclude-result-prefixes="v">
<xsl:key name="kVarByReplace"
match="var"
use="document('')/*/v:v[@o=current()/@value]/@n"/>
<v:v o="a-value" n="new-a-value"/>
<v:v o="b-value" n="new-b-and-c-value"/>
<v:v o="c-value" n="new-b-and-c-value"/>
<v:v o="d-value" n="new-d-value"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="var">
<xsl:variable name="vKey"
select="document('')/*/v:v[@o=current()/@value]/@n"/>
<xsl:if test="count(.|key('kVarByReplace',$vKey)[1]) = 1">
<var value="{$vKey}">
<xsl:value-of select="$vKey"/>
</var>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
输出:
<variables>
<var value="new-a-value">new-a-value</var>
<var value="new-b-and-c-value">new-b-and-c-value</var>
<var value="new-d-value">new-d-value</var>
</variables>
注意:在document()
中使用xsl:key/@use
功能。
这表明这在XSLT 2.0中是多么容易:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:variable name="vMap" as="element()*">
<v o="a-value">new-a-value</v>
<v o="b-value">new-b-and-c-value</v>
<v o="c-value">new-b-and-c-value</v>
<v o="d-value">new-d-value</v>
</xsl:variable>
<xsl:template match="variables">
<variables>
<xsl:for-each-group select="var"
group-by="$vMap[@o=current()/@value]">
<var value="{current-grouping-key()}">
<xsl:value-of select="current-grouping-key()"/>
</var>
</xsl:for-each-group>
</variables>
</xsl:template>
</xsl:stylesheet>
第一个解决方案,也为地图提供了一个键。
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:v="value"
exclude-result-prefixes="v">
<xsl:key name="kValByOld" match="v:v" use="@o"/>
<xsl:key name="kVarByReplace"
match="var"
use="document('')/*/v:v[@o=current()/@value]/@n"/>
<xsl:variable name="vStylesheet" select="document('')"/>
<v:v o="a-value" n="new-a-value"/>
<v:v o="b-value" n="new-b-and-c-value"/>
<v:v o="c-value" n="new-b-and-c-value"/>
<v:v o="d-value" n="new-d-value"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="var">
<xsl:variable name="vOld" select="@value"/>
<xsl:for-each select="$vStylesheet">
<xsl:variable name="vNew"
select="key('kValByOld',$vOld)/@n"/>
<xsl:for-each select="$vOld">
<xsl:if test="count(..|key('kVarByReplace',$vNew)[1])=1">
<var value="{$vNew}">
<xsl:value-of select="$vNew"/>
</var>
</xsl:if>
</xsl:for-each>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
答案 1 :(得分:2)
这是一个XSLT 2.0样式表,可以从输入中生成所需的输出。它是否与其他输入做对是另一个问题,但它的设计是适当的可扩展性,并演示了可用于此类问题的各种技术:
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:f="http://local-functions/"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="f xs">
<xsl:output indent="yes"/>
<xsl:template match="variables">
<variable>
<xsl:for-each-group select="*" group-adjacent="f:is-groupable(.)">
<xsl:choose>
<xsl:when test="f:is-groupable(.)">
<var value="new-{string-join(current-group()/replace(@value, '-value', ''), '-and-')}-value">
<xsl:text> new-</xsl:text>
<xsl:value-of select="string-join(current-group()/normalize-space(.), '-and-')"/>
<xsl:text> </xsl:text>
</var>
</xsl:when>
<xsl:otherwise>
<xsl:for-each select="current-group()">
<var value="new-{@value}">
<xsl:value-of select="replace(., '\S+', 'new-$0')"/>
</var>
</xsl:for-each>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each-group>
</variable>
</xsl:template>
<xsl:function name="f:is-groupable" as="xs:boolean">
<xsl:param name="var" as="element(var)"/>
<xsl:sequence select="$var/@value = ('b-value', 'c-value')"/>
</xsl:function>
</xsl:stylesheet>
答案 2 :(得分:1)
关于“通过中间处理的xml运行另一次迭代将删除重复项” - 这可以在XSLT 2.0中实现,或者在XSLT 1.0中具有nodeset扩展。但在这种情况下,我不认为这是必要的。
而不是for-each和select-when-test-否则,请执行apply-templates:
<xsl:apply-templates select="var" />
然后你有一个模板用于你想要处理的每种类型的var,大致对应于你的xsl:when elements:
<xsl:template match="var[@value = 'a-value']">
<var value="new-a-value"> new-a </var>
</xsl:template>
对于b / c项目,例如:
<xsl:template match="var[@value = 'b-value' or @value = 'c-value'][1]">
<var value="new-b-and-c-value"> new-b-and-c </var>
</xsl:template>
[1]
使模板仅针对其兄弟姐妹中的第一个此类变量触发。这是否正是您想要的,取决于您的输入结构可能会有所不同。
但是考虑到你的样本输入,它是有效的。您还需要一个模板来处理不是第一个的b或c变量:
<xsl:template match="var[@value = 'b-value' or @value = 'c-value']"
priority="-1" />
注意空体;和低优先级,以便 的b / c变量首先不被此模板处理。
总结一下,根据您的示例输入,以下XSLT样式表提供了您请求的输出:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/variables">
<xsl:copy>
<xsl:apply-templates select="var"/>
</xsl:copy>
</xsl:template>
<xsl:template match="var[@value = 'a-value']">
<var value="new-a-value"> new-a </var>
</xsl:template>
<xsl:template match="var[@value = 'b-value' or @value = 'c-value'][1]">
<var value="new-b-and-c-value"> new-b-and-c </var>
</xsl:template>
<xsl:template match="var[@value = 'b-value' or @value = 'c-value']"
priority="-1" />
<xsl:template match="var[@value = 'd-value']">
<var value="new-d-value"> new-d </var>
</xsl:template>
</xsl:stylesheet>
如果这与您的想法不符,请告诉我,我们可以进行迭代。
如果你知道输入中只有一个'b',你可以变得更简单,只需要一个模板来匹配'b'并用新值替换它;并有一个空模板来匹配'c'并扔掉它。但听起来好像你不能做出这样的假设......