<ReferenceDesignators>
<ReferenceDesignator>R1</ReferenceDesignator>
<ReferenceDesignator>R2</ReferenceDesignator>
<ReferenceDesignator>R3</ReferenceDesignator>
<ReferenceDesignator>R4</ReferenceDesignator>
<ReferenceDesignator>R5</ReferenceDesignator>
<ReferenceDesignator>R6</ReferenceDesignator>
<ReferenceDesignator>R7</ReferenceDesignator>
<ReferenceDesignator>R8</ReferenceDesignator>
<ReferenceDesignator>R9</ReferenceDesignator>
<ReferenceDesignator>R10</ReferenceDesignator>
<ReferenceDesignator>R17</ReferenceDesignator>
<ReferenceDesignator>SMD</ReferenceDesignator>
</ReferenceDesignators>
大家好, 请参阅上面的XML。我正在生成PDF并编写了如下的XSL代码。
<xsl:for-each select="ReferenceDesignator">
<xsl:value-of select="."/>
<xsl:if test ="position()!=last()">
<xsl:text>,</xsl:text>
</xsl:if>
</xsl:for-each>
因此,我得到所有用逗号分隔的值。但是我希望输出为 R1-R10,R17,SMD。
如何通过正则表达式实现此目标? 请帮忙。
谢谢, 万寿
答案 0 :(得分:2)
一种可能的方法是创建一个函数,该函数可用于向值加1(如果值中包含数字)
<xsl:function name="my:check">
<xsl:param name="current" />
<xsl:variable name="number" select="if (matches($current, '.*\d+')) then xs:int(replace($current, '[A-Z]+', '')) + 1 else ''" />
<xsl:value-of select="replace($current, '\d', ''), $number" separator="" />
</xsl:function>
然后,您可以使用xsl:for-each-group
对元素进行分组,这些元素以与上一个值不连续的元素开头
<xsl:for-each-group select="ReferenceDesignator" group-starting-with="ReferenceDesignator[. != my:check(preceding-sibling::ReferenceDesignator[1])]">
尝试使用此XSLT
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:my="my">
<xsl:output method="text" />
<xsl:template match="ReferenceDesignators">
<xsl:for-each-group select="ReferenceDesignator" group-starting-with="ReferenceDesignator[. != my:check(preceding-sibling::ReferenceDesignator[1])]">
<xsl:if test="position() > 1">,</xsl:if>
<xsl:value-of select="current-group()[1], current-group()[position() > 1][last()]" separator="-" />
</xsl:for-each-group>
</xsl:template>
<xsl:function name="my:check">
<xsl:param name="current" />
<xsl:variable name="number" select="if (matches($current, '.*\d+')) then xs:int(replace($current, '[A-Z]+', '')) + 1 else ''" />
<xsl:value-of select="replace($current, '\d', ''), $number" separator="" />
</xsl:function>
</xsl:stylesheet>
请注意,这确实是假设每个ReferenceDesignator
由一个或多个字母组成,在更多的数字后跟零。
答案 1 :(得分:2)
作为替代方案,以下是使用for-each-group group-adjacent
的XSLT 3模板:
<xsl:template match="ReferenceDesignators">
<xsl:value-of separator=",">
<xsl:for-each-group
select="ReferenceDesignator" composite="yes"
group-adjacent="let $p := position(),
$comps := analyze-string(., '(\p{L}+)([0-9]+)'),
$prefix := $comps//*:group[@nr = 1]/data(), $i := $comps//*:group[@nr = 2]/data()
return ($prefix, $i!(xs:integer(.) - $p))">
<xsl:sequence
select="string-join((. | current-group()[last()]), '-')"/>
</xsl:for-each-group>
</xsl:value-of>
</xsl:template>
https://xsltfiddle.liberty-development.net/eiZQaGg/3
最好将group-adjacent
属性中的表达式分解为一个函数:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:mf="http://example.com/mf"
exclude-result-prefixes="#all"
version="3.0">
<xsl:function name="mf:grouping-key" as="item()+">
<xsl:param name="value" as="xs:string"/>
<xsl:param name="pos" as="xs:integer"/>
<xsl:sequence
select="let $comps := analyze-string($value, '(\p{L}+)([0-9]+)?'),
$prefix := $comps//*:group[@nr = 1]/data(),
$suffix := $comps//*:group[@nr = 2]!(xs:integer(.) - $pos)
return ($prefix, $suffix)"/>
</xsl:function>
<xsl:template match="ReferenceDesignators">
<xsl:value-of separator=",">
<xsl:for-each-group select="ReferenceDesignator" composite="yes" group-adjacent="mf:grouping-key(., position())">
<xsl:sequence
select="string-join((. | current-group()[last()]), '-')"/>
</xsl:for-each-group>
</xsl:value-of>
</xsl:template>
</xsl:stylesheet>
https://xsltfiddle.liberty-development.net/eiZQaGg/4
在XSLT 2中,您可以使用串联的分组密钥而不是组合密钥:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:mf="http://example.com/mf"
exclude-result-prefixes="#all"
version="2.0">
<xsl:function name="mf:grouping-key" as="xs:string">
<xsl:param name="value" as="xs:string"/>
<xsl:param name="pos" as="xs:integer"/>
<xsl:variable name="comps" as="item()*">
<xsl:variable name="pattern" as="xs:string">(\p{L}+)([0-9]+)?</xsl:variable>
<xsl:analyze-string select="$value" regex="{$pattern}">
<xsl:matching-substring>
<xsl:sequence select="regex-group(1), regex-group(2)"/>
</xsl:matching-substring>
</xsl:analyze-string>
</xsl:variable>
<xsl:variable name="prefix" select="$comps[1]"/>
<xsl:variable name="suffix" select="if ($comps[2] castable as xs:integer) then (xs:integer($comps[2]) - $pos) else ()"/>
<xsl:sequence
select="concat($prefix, $suffix)"/>
</xsl:function>
<xsl:template match="ReferenceDesignators">
<xsl:value-of separator=",">
<xsl:for-each-group select="ReferenceDesignator" group-adjacent="mf:grouping-key(., position())">
<xsl:sequence
select="string-join((. | current-group()[last()]), '-')"/>
</xsl:for-each-group>
</xsl:value-of>
</xsl:template>
</xsl:stylesheet>