XSLT实现:将单个属性拆分为带属性的多个元素
问题:拆分多rid的元素为独立元素
我有一段XML,其中的<xref>元素的rid属性包含多个交叉引用值,需要将其拆分为多个独立的<xref>元素,每个元素对应一个rid值。
输入XML
<p>Blah blah blah <xref ref-type="bibr" rid="ref004 ref005 ref006 ref007">4–7</xref>.</p>
期望输出XML
<p>Blah blah blah <xref ref-type="bibr" rid="ref004">4</xref><xref ref-type="bibr" rid="ref005"/><xref ref-type="bibr" rid="ref006"/>–<xref ref-type="bibr" rid="ref007">7</xref>.</p>
注意:中间两个交叉引用为空元素。
我使用了如下XSLT,但无法得到正确输出——它会将属性值作为元素内容插入:
错误的XSLT代码
<xsl:template match="@*|node()"> <xsl:copy> <xsl:apply-templates select="@*|node()"/> </xsl:copy> </xsl:template> <xsl:template match="xref"> <xsl:variable name="rid" select="@rid"/> <xsl:choose> <xsl:when test="contains($rid, ' ')"> <!-- Multiple references --> <xsl:variable name="refs" select="tokenize($rid, ' ')"/> <xsl:for-each select="$refs"> <xsl:if test="position() > 1"> <xsl:text> </xsl:text> </xsl:if> <xsl:variable name="refNum" select="substring-after(., 'ref')"/> <xsl:element name="xref"> <xsl:attribute name="ref-type">bibr</xsl:attribute> <xsl:attribute name="rid"> <xsl:value-of select="concat('ref', $refNum)"/> </xsl:attribute> <xsl:value-of select="."/> </xsl:element> </xsl:for-each> </xsl:when> <xsl:otherwise> <!-- Single reference --> <xsl:element name="xref"> <xsl:attribute name="ref-type">bibr</xsl:attribute> <xsl:attribute name="rid"> <xsl:value-of select="$rid"/> </xsl:attribute> <xsl:value-of select="."/> </xsl:element> </xsl:otherwise> </xsl:choose> </xsl:template>
修正后的XSLT解决方案
<xsl:template match="@*|node()"> <xsl:copy> <xsl:apply-templates select="@*|node()"/> </xsl:copy> </xsl:template> <xsl:template match="xref[@rid and contains(@rid, ' ')]"> <!-- 拆分rid属性为单独的引用列表 --> <xsl:variable name="refs" select="tokenize(@rid, ' ')"/> <!-- 拆分原文本的起始和结束数字 --> <xsl:variable name="textParts" select="tokenize(normalize-space(.), '–')"/> <xsl:variable name="startNum" select="$textParts[1]"/> <xsl:variable name="endNum" select="$textParts[2]"/> <xsl:for-each select="$refs"> <xsl:variable name="pos" select="position()"/> <xsl:element name="xref"> <!-- 复制原ref-type属性 --> <xsl:copy-of select="../@ref-type"/> <xsl:attribute name="rid" select="."/> <!-- 第一个元素用起始数字,最后一个用结束数字,中间为空 --> <xsl:if test="$pos = 1"> <xsl:value-of select="$startNum"/> </xsl:if> <xsl:if test="$pos = count($refs)"> <xsl:value-of select="$endNum"/> </xsl:if> </xsl:element> <!-- 在倒数第二个元素后插入连接符 --> <xsl:if test="$pos = count($refs) - 1"> <xsl:text>–</xsl:text> </xsl:if> </xsl:for-each> </xsl:template>
关键修正点
- 解析原
<xref>的文本内容,拆分出起始和结束数字,不再错误地将rid值作为元素内容 - 根据每个拆分后
<xref>的位置决定内容:第一个显示起始数字,最后一个显示结束数字,中间的为空元素 - 在倒数第二个
<xref>之后插入–连接符,替代原代码中错误的空格分隔 - 直接复制原
<xref>的ref-type属性,避免硬编码,提升通用性
内容的提问来源于stack exchange,提问作者user2093335
相关产品推荐
相关产品推荐

