我正在使用XSLT 1.0(所以我不能使用replace()函数),我需要在使用该字符串进行排序之前在字符串中进行替换。简而言之,我的XML文档如下所示:
<root>
<item>
<name>ABC</name>
<rating>good</rating>
</item>
<item>
<name>BCD</name>
<rating>3</rating>
</item>
</root>
然后我需要将'good'替换为'4',以便使用sort()函数打印按评级排序的整个项目列表。由于我使用的是XSLT 1.0,我使用此模板进行替换:
<xsl:template name="string-replace">
<xsl:param name="subject" select="''" />
<xsl:param name="search" select="''" />
<xsl:param name="replacement" select="''" />
<xsl:param name="global" select="false()" />
<xsl:choose>
<xsl:when test="contains($subject, $search)">
<xsl:value-of select="substring-before($subject, $search)" />
<xsl:value-of select="$replacement" />
<xsl:variable name="rest" select="substring-after($subject, $search)" />
<xsl:choose>
<xsl:when test="$global">
<xsl:call-template name="string-replace">
<xsl:with-param name="subject" select="$rest" />
<xsl:with-param name="search" select="$search" />
<xsl:with-param name="replacement" select="$replacement" />
<xsl:with-param name="global" select="$global" />
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$rest" />
</xsl:otherwise>
</xsl:choose>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$subject" />
</xsl:otherwise>
</xsl:choose>
</xsl:template>
这个模板工作正常,但问题是它总是打印值,(即总是在我打印模板时打印的东西)。因此,在这种情况下,此模板无用,因为我需要修改“评级”值,然后按评级对项目进行排序,最后打印出来。
提前致谢!
PS:解决方法是使用两个不同的XSLT,但由于多种原因,在这种情况下我无法做到。
答案 0 :(得分:2)
你可以这样做:
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
>
<xsl:output method="xml" encoding="utf-8" />
<xsl:template match="/root">
<xsl:for-each select="item">
<!-- be sure to include every possible value of <rating>! -->
<xsl:sort select="
concat(
substring('4', 1, rating = 'good' ),
substring('3', 1, rating = 'medioce' ),
substring('2', 1, rating = 'bad' ),
substring('1', 1, rating = 'abyssmal' ),
substring('4', 1, rating = '4' ),
substring('3', 1, rating = '3' ),
substring('2', 1, rating = '2' ),
substring('1', 1, rating = '1' )
)
" order="descending" />
<xsl:copy-of select="." />
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
输入:
<root>
<item>
<name>ABC</name>
<rating>abyssmal</rating>
</item>
<item>
<name>GEH</name>
<rating>bad</rating>
</item>
<item>
<name>DEF</name>
<rating>good</rating>
</item>
<item>
<name>IJK</name>
<rating>medioce</rating>
</item>
</root>
我明白了:
<item>
<name>DEF</name>
<rating>good</rating>
</item>
<item>
<name>IJK</name>
<rating>medioce</rating>
</item>
<item>
<name>GEH</name>
<rating>bad</rating>
</item>
<item>
<name>ABC</name>
<rating>abyssmal</rating>
</item>
要获得解释,see my other answer。 ; - )
修改
根据OP的评论改变了解决方案:
我需要使用评级(使用 字符串替换为整数分数),3 时间:
- 使用评分
使用<xsl:key ...
制作密钥- 使用评级
对项目进行排序- 打印评级。
醇>在每一步中我都应该使用评级 替换之后(即使用整数 分数)。我已经做了重复
concat(...)
代码3次,但和你一样 可以看出这不太酷......我 我想找个办法放置concat (...)
一次,不需要 重复一遍。
以下XSLT 1.0解决方案满足所有这些要求:
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:tmp="http://tempuri.org/"
exclude-result-prefixes="tmp"
>
<xsl:output method="xml" encoding="utf-8" />
<!-- prepare a list of possible ratings for iteration -->
<tmp:ratings>
<tmp:rating num="1" />
<tmp:rating num="2" />
<tmp:rating num="3" />
<tmp:rating num="4" />
</tmp:ratings>
<!-- index items by their rating -->
<xsl:key
name="kItemByRating"
match="item"
use="concat(
substring('4', 1, rating = 'good' ),
substring('3', 1, rating = 'medioce' ),
substring('2', 1, rating = 'bad' ),
substring('1', 1, rating = 'abyssmal' ),
substring('4', 1, rating = '4' ),
substring('3', 1, rating = '3' ),
substring('2', 1, rating = '2' ),
substring('1', 1, rating = '1' )
)
" />
<!-- we're going to need that later-on -->
<xsl:variable name="root" select="/" />
<xsl:template match="/root">
<!-- iterate on the prepared list of ratings -->
<xsl:apply-templates select="document('')/*/tmp:ratings/tmp:rating">
<xsl:sort select="@num" order="descending" />
</xsl:apply-templates>
</xsl:template>
<xsl:template match="tmp:rating">
<xsl:variable name="num" select="@num" />
<!--
The context node is part of the XSL file now. As a consequence,
a call to key() would be evaluated within the XSL file.
The for-each is a means to change the context node back to the
XML file, so that the call to key() can return <item> nodes.
-->
<xsl:for-each select="$root">
<!-- now pull out all items with a specific rating -->
<xsl:apply-templates select="key('kItemByRating', $num)">
<!-- note that we use the variable here! -->
<xsl:with-param name="num" select="$num" />
<xsl:sort select="@name" />
</xsl:apply-templates>
</xsl:for-each>
</xsl:template>
<xsl:template match="item">
<xsl:param name="num" select="''" />
<xsl:copy>
<!-- print out the numeric rating -->
<xsl:attribute name="num">
<xsl:value-of select="$num" />
</xsl:attribute>
<xsl:copy-of select="node() | @*" />
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
答案 1 :(得分:1)
如果您只有一小组预定义的替换,您可以使用以下方法:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:myExt="http://www.example.com/myExtension"
exclude-result-prefixes="myExt">
<xsl:output method="xml" indent="yes"/>
<myExt:replacements>
<item>
<value>good</value>
<replacement>4</replacement>
</item>
<item>
<value>very good</value>
<replacement>5</replacement>
</item>
</myExt:replacements>
<xsl:template match="root">
<out>
<xsl:for-each select="item">
<xsl:sort select="number(document('')/xsl:stylesheet/myExt:replacements/item[value=current()/rating]/replacement | rating)" order="ascending"/>
<item>
<name>
<xsl:value-of select="name"/>
</name>
<rating>
<xsl:value-of select="document('')/xsl:stylesheet/myExt:replacements/item[value=current()/rating]/replacement | rating"/>
</rating>
</item>
</xsl:for-each>
</out>
</xsl:template>
使用document('')
是一种技巧,可以让您访问样式表文档中的节点。在我们的例子中,这是一组节点,指定要进行的替换。
在| rating
元素的select属性中使用xsl:sort
是另一招。这意味着select表达式的结果是document('')/xsl:stylesheet/myExt:replacements/item[value=current()/rating]/replacement
和rating
的并集。在计算select表达式时,仅考虑结果节点集的第一个元素。这样做的结果是,如果没有定义替换,将使用rating
元素的值。
输出文档将如何为您提供示例输入:
<?xml version="1.0" encoding="utf-8"?>
<out>
<item>
<name>BCD</name>
<rating>3</rating>
</item>
<item>
<name>ABC</name>
<rating>4</rating>
</item>
</out>
答案 2 :(得分:1)
如果您只需要用4替换好的评级,那么试试这个。它会将4的良好评级替换为排序目的,并保留所有不良的评级。额外的空间是为了便于阅读/理解。
<xsl:for-each select="item">
<xsl:sort select="
concat(
substring(
'4',
1,
boolean(rating = 'good')
),
substring(
rating,
1,
not(boolean(rating = 'good'))
)
)
"/>
</xsl:for-each>
如果您需要更换多个评级但有些已经是数字,则可以执行以下操作:
concat(
substring(
'4',
1,
boolean(rating = 'good')
),
substring(
'3',
1,
boolean(rating = 'average')
),
substring(
'2',
1,
boolean(rating = 'bad')
),
substring(
rating,
1,
not(boolean(rating = 'bad') or boolean(rating = 'average') or boolean(rating = 'good'))
)
)
布尔值要么转换为1表示true,要么转换为0表示false。然后在子字符串中使用它,因此只有一个为true的子字符串将长度为1,其他字符串将以长度为0的子字符串连接。将这些连接在一起会使您获得替换值。