如何用XSLT将前置文本及内联元素统一包裹进<p>标签
XML转换需求:将前置文本及内联元素包裹到单个
节点
需求说明
需要对指定XML进行转换:将<content>节点下的所有前置文本节点(包含其中的内联元素)包裹在单个<p>节点中,后续的<ol>、<p>等节点保持原有结构不变。当前使用的XSLT模板会将文本拆分包裹,无法将含<b>的前置内容放在同一<p>内,需正确实现方案。
输入XML
<content>This text in not inside a p <b>inline element</b> also not inside a p: <ol> <li>list item text</li> <li>list item text</li> </ol> <p>This text <b>lorem</b> is inside p in the source and should stay like this.</p> </content>
期望转换结果
<content><p>This text in not inside a p <b>inline element</b> also not inside a p:</p> <ol> <li>list item text</li> <li>list item text</li> </ol> <p>This text <b>lorem</b> is inside p in the source and should stay like this.</p> </content>
(注:原期望结果存在一处笔误,已修正结尾的<p>标签)
当前使用的XSLT模板及错误结果
当前模板
<xsl:template match="content/text()"> <p><xsl:copy-of select="."/></p> </xsl:template>
错误转换结果
<content><p>This text in not inside a p</p> <b>inline element</b> <p>also not inside a p:</p> <ol> <li>list item text</li> <li>list item text</li> </ol> <p>This text <b>lorem</b> is inside p in the source and should stay like this. </p> </content>
正确XSLT实现方案
<xsl:stylesheet version="1.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> <!-- 重写content节点的处理逻辑 --> <xsl:template match="content"> <xsl:copy> <!-- 包裹第一个块级元素(ol/p)之前的所有节点:文本+内联元素 --> <p> <xsl:apply-templates select="node()[count(preceding-sibling::*[self::ol or self::p])=0]"/> </p> <!-- 处理后续的块级元素,保持原有结构 --> <xsl:apply-templates select="ol|p"/> </xsl:copy> </xsl:template> </xsl:stylesheet>
方案说明
- 默认模板:负责复制所有未被特殊匹配的节点和属性,保证后续的
<ol>、<p>等节点结构不变。 - content节点处理:
- 先筛选出所有在第一个
<ol>或<p>之前的节点(包括文本和内联<b>元素),将它们统一包裹到一个<p>节点中。 - 再正常处理后续的
<ol>和<p>节点,保留原有层级和内容。
- 先筛选出所有在第一个
内容的提问来源于stack exchange,提问作者Chad Dybdahl
相关产品推荐
相关产品推荐

