如何使用XSLT根据属性将XML同级节点转换为父子层级结构
XSLT实现同级r节点转为p节点子节点方案
核心思路
基于XSLT标准标识转换能力,仅做两处定制逻辑即可满足需求:
- 处理p节点时,将其后续紧接的所有同级r节点(到下一个p节点前为止)插入到当前p节点内部作为子节点
- 单独匹配的同级r节点直接跳过,避免重复输出
完整XSLT代码
<?xml version="1.0" encoding="UTF-8"?> <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> <!-- 定制处理p节点 --> <xsl:template match="p"> <xsl:copy> <!-- 复制p节点所有属性 --> <xsl:apply-templates select="@*"/> <!-- 复制p节点自身的内容 --> <xsl:apply-templates select="text()"/> <!-- 选中当前p后、下一个p前的所有同级r节点 --> <xsl:for-each select="following-sibling::r[preceding-sibling::p[1] = current()]"> <!-- 插入换行和缩进,匹配输出格式要求 --> <xsl:text>
 </xsl:text> <xsl:copy> <xsl:apply-templates select="@* | node()"/> </xsl:copy> </xsl:for-each> <!-- 存在子r节点时,p闭合前加换行 --> <xsl:if test="count(following-sibling::r[preceding-sibling::p[1] = current()]) > 0"> <xsl:text>
</xsl:text> </xsl:if> </xsl:copy> </xsl:template> <!-- 跳过所有已被p节点处理的同级r节点,避免重复输出 --> <xsl:template match="r[preceding-sibling::*[1][self::p or self::r]]"/> </xsl:stylesheet>
逻辑说明
关键选择规则following-sibling::r[preceding-sibling::p[1] = current()]的作用是精准定位当前p节点对应的r节点:只筛选那些前一个最近的p节点就是当前处理p的r节点,不会错误选中其他p对应的r。
该代码兼容XSLT 1.0及以上版本,直接对输入XML执行转换即可得到期望的输出结果。
内容的提问来源于stack exchange,提问作者user16488643
相关产品推荐
相关产品推荐

