XSLT accumulator如何累积元素引用 保留元素属性及文本
问题原因
- 现有累加器声明的存储类型为
xs:string*(字符串序列),匹配authorialNote节点时通过@marker || .做了字符串拼接,直接将节点转换为拼接后的纯文本,完全丢弃了原节点的属性、子元素结构,自然无法保留完整节点信息 - 输出模板中使用
xsl:value-of仅能提取节点的文本值,同时eId="@eId"是硬编码的固定字符串,无法读取原节点上的真实eId属性值
正确实现方案
核心思路是将累加器的存储类型改为元素节点序列,直接存储匹配到的authorialNote节点引用,不做任何字符串转换,输出时直接读取节点的属性、复制节点结构即可。
注意:XSLT 3.0累加器需要显式声明启用,请在
<xsl:stylesheet>根节点下添加<xsl:use-accumulators name="authorialNote_accumulator"/>,否则累加器不会生效。
1. 修正后的累加器代码
<xsl:output omit-xml-declaration="no" indent="yes"/> <!-- 累加器类型改为元素节点序列,初始值为空序列 --> <xsl:accumulator name="authorialNote_accumulator" as="element()*" initial-value="()"> <!-- 匹配到authorialNote时,直接将当前节点追加到累积序列中,不做字符串转换 --> <xsl:accumulator-rule match="authorialNote" select="$value, ."/> <!-- 匹配到eop结束阶段时清空累加器,为下一段内容的累积做准备 --> <xsl:accumulator-rule match="eop" select="()" phase="end"/> </xsl:accumulator>
2. 修正后的eop节点匹配模板
<xsl:template match="eop"> <xsl:variable name="_authorialNote" select="accumulator-before('authorialNote_accumulator')"/> <div class="authorial-note"> <xsl:for-each select="$_authorialNote"> <!-- 通过属性值模板读取当前节点的真实eId属性 --> <div eId="{@eId}"> <!-- 复制当前节点下所有子元素、文本、结构,完整保留原内容 --> <xsl:copy-of select="node()"/> <!-- 如果需要连同authorialNote标签本身、其所有属性一起完整输出,直接替换为<xsl:copy-of select="."/>即可 --> </div> </xsl:for-each> </div> </xsl:template>
关键逻辑说明
- 累加器存储
element()*类型的节点序列时,保存的是源文档中对应节点的引用,不会丢失节点的任何属性、子元素、文本结构信息 - 需要读取节点属性作为输出属性值时,要使用属性值模板
{@属性名}的写法,直接将属性名写在引号内只会输出固定字符串,不会读取节点属性 - 如果输出不需要额外包裹自定义div层,直接在循环里写
<xsl:copy-of select="."/>就能1:1还原原authorialNote节点的全部内容
内容的提问来源于stack exchange,提问作者OrYo
相关产品推荐
相关产品推荐

