XSLT实现子节点对转父节点:verse标签合并技术问询
问题解决:合并成对的verse节点并修复模板未触发问题
问题分析
当前XSL代码存在两个核心问题:
- 自定义的
osis/osisText/div/chapter模板覆盖了默认身份模板,但这些模板未复制自身节点,直接执行<xsl:apply-templates/>会导致父节点丢失,破坏XML结构的同时让verse节点的匹配上下文异常。 - 原
verse模板写法错误(存在多余的</xsl:text>标签),且没有处理成对节点的逻辑,无法实现合并需求。
解决方案代码
以下是修正后的XSLT 1.0代码,既保留原有XML结构,又能完成成对verse节点的合并:
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="xml" indent="yes"/> <!-- 身份模板:默认复制所有节点和属性,保证XML结构完整 --> <xsl:template match="@*|node()"> <xsl:copy> <xsl:apply-templates select="@*|node()"/> </xsl:copy> </xsl:template> <!-- 匹配带sID的起始verse节点 --> <xsl:template match="verse[@sID and @osisID]"> <!-- 创建新的verse节点,保留原sID和osisID属性 --> <verse sID="{@sID}" osisID="{@osisID}"> <!-- 处理起始verse和对应结束verse之间的所有内容 --> <xsl:apply-templates select="following-sibling::node()[ not(self::verse[@eID = current()/@sID]) and generate-id(preceding-sibling::verse[@sID][1]) = generate-id(current()) ]"/> </verse> </xsl:template> <!-- 匹配带eID的结束verse节点,直接跳过不输出 --> <xsl:template match="verse[@eID]"/> </xsl:stylesheet>
代码说明
- 身份模板:保留默认的节点复制逻辑,确保所有未被自定义模板匹配的节点(包括
osis/osisText等父节点)正常复制,解决原模板丢失父节点的问题。 - 起始verse模板:精准匹配带
sID和osisID的起始节点,生成包含原属性的新verse节点,并收集该节点到对应eID节点之间的所有内容作为子节点。 - 结束verse模板:匹配带
eID的结束节点,直接不输出,完成合并操作。
效果验证
输入示例:
<chapter> <verse sID="v1" osisID="Gen.1.1"/> <para>起初神创造天地。</para> <verse eID="v1"/> <verse sID="v2" osisID="Gen.1.2"/> <para>地是空虚混沌,渊面黑暗;神的灵运行在水面上。</para> <verse eID="v2"/> </chapter>
输出结果:
<chapter> <verse sID="v1" osisID="Gen.1.1"> <para>起初神创造天地。</para> </verse> <verse sID="v2" osisID="Gen.1.2"> <para>地是空虚混沌,渊面黑暗;神的灵运行在水面上。</para> </verse> </chapter>
内容的提问来源于stack exchange,提问作者adamm
相关产品推荐
相关产品推荐

