这种转变:
<xsl:stylesheet version="2.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="p/text()[matches(., 'Story [0-9]+(\.[0-9]+)')]">
<xsl:variable name="vCur" select="."/>
<xsl:variable name="pContent" select="string(.)"/>
<xsl:analyze-string select="$pContent" regex="Story [0-9]*\.[0-9]*" flags="i">
<xsl:matching-substring>
<xsl:variable name="figureToTargetId">
<xsl:analyze-string select="." regex="[0-9]*\.[0-9]*">
<xsl:matching-substring>
<xsl:value-of select="concat('s',.)"/>
</xsl:matching-substring>
</xsl:analyze-string>
</xsl:variable>
<a href="#{$figureToTargetId}">
<xsl:value-of select="."/>
<xsl:if test="not(matches($vCur, 'Story [0-9]+(\.[0-9]+).+$'))">
<xsl:sequence select="$vCur/following-sibling::*[1]"/>
</xsl:if>
</a>
</xsl:matching-substring>
<xsl:non-matching-substring><xsl:value-of select="."/></xsl:non-matching-substring>
</xsl:analyze-string>
</xsl:template>
<xsl:template match=
"p/*[preceding-sibling::node()[1]
[self::text()
and
matches(., 'Story [0-9]+(\.[0-9]+)$')]
]"/>
</xsl:stylesheet>
当应用于本文档时(提供的扩展包含两个有趣的案例):
<t>
<p>Little Red Riding Hood (Story 3.1) </p>
<p>Jack goes up the hill (Story 3.1<i>a</i>) to fetch a pail of water.</p>
</t>
产生想要的正确结果:
<t>
<p>Little Red Riding Hood (<a href="#s3.1">Story 3.1</a>) </p>
<p>Jack goes up the hill (<a href="#s3.1">Story 3.1<i>a</i>
</a>) to fetch a pail of water.</p>
</t>
说明:
我们检查匹配的子字符串是否是当前文本节点的后缀——如果是,那么我们还复制后面的第一个同级元素。
更新:
在评论中,OP 设置了一个新的附加要求——也更改<i>
为<em>
.
这只需要对上述解决方案稍作更新:
<xsl:stylesheet version="2.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="p/text()[matches(., 'Story [0-9]+(\.[0-9]+)')]">
<xsl:variable name="vCur" select="."/>
<xsl:variable name="pContent" select="string(.)"/>
<xsl:analyze-string select="$pContent" regex="Story [0-9]*\.[0-9]*" flags="i">
<xsl:matching-substring>
<xsl:variable name="figureToTargetId">
<xsl:analyze-string select="." regex="[0-9]*\.[0-9]*">
<xsl:matching-substring>
<xsl:value-of select="concat('s',.)"/>
</xsl:matching-substring>
</xsl:analyze-string>
</xsl:variable>
<a href="#{$figureToTargetId}">
<xsl:value-of select="."/>
<xsl:if test="not(matches($vCur, 'Story [0-9]+(\.[0-9]+).+$'))">
<xsl:apply-templates mode="match" select="$vCur/following-sibling::*[1]"/>
</xsl:if>
</a>
</xsl:matching-substring>
<xsl:non-matching-substring><xsl:value-of select="."/></xsl:non-matching-substring>
</xsl:analyze-string>
</xsl:template>
<xsl:template match=
"p/*[preceding-sibling::node()[1]
[self::text()
and
matches(., 'Story [0-9]+(\.[0-9]+)$')]
]"/>
<xsl:template mode="match" match=
"p/i[preceding-sibling::node()[1]
[self::text()
and
matches(., 'Story [0-9]+(\.[0-9]+)$')]
]">
<em><xsl:apply-templates/></em>
</xsl:template>
</xsl:stylesheet>