如何合并与文本交错的相邻兄弟codeph元素?
问题需求
需要将父元素中相邻的codeph直接兄弟元素(含子元素)合并为单个codeph元素,同时保留与文本节点的交错结构。
XML输入
<p>Information about specific mio levels, accessed as <codeph><i>metaMio</i></codeph><codeph>[</codeph><codeph><i>N</i></codeph><codeph>]</codeph> , in which <codeph><i>N</i></codeph><codeph> < kMaxMioLevels</codeph> . </p>
期望XML输出
<p>Information about specific mio levels, accessed as <codeph><i>metaMio</i>[<i>N</i>]</codeph> , in which <codeph><i>N</i> < kMaxMioLevels</codeph> . </p>
尝试的XSLT(存在重复问题)
<xsl:template match="codeph[not(preceding-sibling::node()[1][./local-name()='codeph'])][following-sibling::node()[1][./local-name()='codeph']]"> <xsl:copy copy-namespaces="no"> <xsl:apply-templates/> <xsl:choose> <xsl:when test="following-sibling::codeph[preceding-sibling::node()[position()=1][local-name()='codeph']]"> <xsl:apply-templates select="following-sibling::codeph[preceding-sibling::node()[position()=1][local-name()='codeph']]" mode="codeph-merger"/> </xsl:when> <xsl:when test="following-sibling::*[1][text()[not(parent::codeph)]]"/> </xsl:choose> </xsl:copy> </xsl:template> <xsl:template match="*" mode="codeph-merger"> <xsl:apply-templates/> </xsl:template> <xsl:template match="codeph[preceding-sibling::node()[1][local-name()='codeph']]"/>
当前输出(存在文本重复)
<p>Information about specific mio levels, accessed as <codeph><i>metaMio</i>[<i>N</i>] < kMaxMipLevels</codeph> , in which <codeph><i>N</i> < kMaxMipLevels</codeph> . </p>
解决方案(XSLT 2.0)
使用xsl:for-each-group的group-adjacent属性精准分组相邻codeph,避免内容重复:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <!-- 身份模板:默认复制所有未匹配的节点 --> <xsl:template match="@*|node()"> <xsl:copy> <xsl:apply-templates select="@*|node()"/> </xsl:copy> </xsl:template> <!-- 处理p元素的子节点,按是否为codeph分组 --> <xsl:template match="p"> <xsl:copy> <xsl:for-each-group select="node()" group-adjacent="local-name()='codeph'"> <!-- 合并相邻的codeph组为单个codeph元素 --> <xsl:if test="current-grouping-key()"> <codeph> <xsl:apply-templates select="current-group()/node()"/> </codeph> </xsl:if> <!-- 非codeph组直接输出原内容 --> <xsl:if test="not(current-grouping-key())"> <xsl:apply-templates select="current-group()"/> </xsl:if> </xsl:for-each-group> </xsl:copy> </xsl:template> </xsl:stylesheet>
方案说明
- 身份模板保证所有未匹配的节点(如嵌套的
<i>元素、文本节点)原样复制,不破坏原有结构。 - 针对
<p>的子节点,用group-adjacent="local-name()='codeph'"将连续的codeph归为一组,非codeph节点(文本、其他元素)单独成组。 - 对
codeph组,创建新的<codeph>元素,将组内所有codeph的子节点(包括嵌套元素和文本)合并进去。 - 非
codeph组直接输出,保留原有的文本和排版结构。
该方案能准确处理多组codeph与文本交错的场景,完全符合需求且无内容重复问题。
内容的提问来源于stack exchange,提问作者Daniel
相关产品推荐
相关产品推荐

