XSLT转换如何保留选中元素、属性及文本的正确顺序
问题核心原因
你现有代码无法按原有顺序输出内容,本质是犯了XSLT开发的常见错误:
- 没有利用XSLT原生的节点遍历机制,在匹配
<b>节点时手动硬编码用<xsl:value-of>分别选取<e>节点和当前节点文本值,完全打乱了XML文档里节点的原始排列顺序 - 没有处理XML缩进产生的冗余空白节点,也没有对有效文本里的换行、连续空格做规范化
- 标签和结构不符合预期:包裹属性值的标签写成了
<sup>(预期是<sub>),缺少最外层的<output>根容器 - 虽然写了
<skip>节点的空匹配模板,但因为没有按顺序遍历所有子节点,这个过滤逻辑没有按预期生效
修正后的XSLT实现
直接替换你现有XSLT文件内容即可,不需要修改Java调用代码:
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="3.0"> <xsl:output method="xml" indent="no" omit-xml-declaration="yes"/> <!-- 自动清除节点间纯缩进、换行产生的空白节点 --> <xsl:strip-space elements="*"/> <!-- 过滤冗余skip节点,不输出任何内容 --> <xsl:template match="skip"/> <!-- 匹配根节点<a>,生成外层<output>容器 --> <xsl:template match="/a"> <output> <xsl:apply-templates select="b"/> </output> </xsl:template> <!-- 匹配<e>节点:生成<sub>标签包裹h属性值,再输出节点内的有效文本 --> <xsl:template match="e"> <sub> <xsl:value-of select="@h"/> </sub> <xsl:text> </xsl:text> <xsl:value-of select="normalize-space(text())"/> <!-- 后续还有非空内容时补空格分隔,避免内容粘连 --> <xsl:if test="following-sibling::node()[not(self::skip)][normalize-space(.)]"> <xsl:text> </xsl:text> </xsl:if> </xsl:template> <!-- 处理<b>节点下的直接有效文本,过滤空内容 --> <xsl:template match="b/text()[normalize-space(.)]"> <xsl:value-of select="normalize-space(.)"/> <xsl:text> </xsl:text> </xsl:template> </xsl:stylesheet>
关键实现说明
- 保留原始顺序的核心是用
<xsl:apply-templates>按文档顺序遍历节点,不要手动拼接不同位置的节点值,这是XSLT开发的基本原则 - 不需要的属性(比如
<b>的c属性、<e>的f属性)因为没有被主动选取,自然不会出现在输出里,不需要额外写过滤逻辑 normalize-space()函数会自动清除文本首尾的空白、把内部连续空白合并为单个空格,刚好适配你需要的文本格式<xsl:strip-space elements="*">会提前删除纯格式用途的空白文本节点(就是XML缩进产生的换行、空格),减少后续的空白判断逻辑
内容的提问来源于stack exchange,提问作者tm1701
相关产品推荐
相关产品推荐

