XSL转换:将&转为&报错及mdash实体转换需求处理
问题解决
错误原因分析
报错“无法在包含元素的子元素之后创建属性节点”是因为你的XSL模板顺序违规:复制元素后先输出了文本内容,再处理属性节点。而XML语法明确要求,元素的属性必须放在所有子节点之前,这个顺序违反了规则,导致解析报错。
需求实现方案
要同时完成两个转换需求——将十六进制实体—转为—,以及将XML中的&转为&,可以按以下方式修改XSL代码:
<xsl:stylesheet version='1.0' xmlns:xsl='http://www.w3.org/1999/XSL/Transform' > <xsl:output method="xml" omit-xml-declaration="no" use-character-maps="mdash" /> <xsl:character-map name="mdash"> <xsl:output-character character="—" string="&mdash;" /> </xsl:character-map> <!-- 处理元素节点:先复制元素,再处理属性,最后处理子节点 --> <xsl:template match="*"> <xsl:copy> <xsl:apply-templates select="@*"/> <xsl:apply-templates select="node()"/> </xsl:copy> </xsl:template> <!-- 直接复制属性节点,字符映射会自动处理属性中的emdash --> <xsl:template match="@*"> <xsl:copy/> </xsl:template> <!-- 处理文本节点:替换所有&为& --> <xsl:template match="text()"> <xsl:call-template name="replace-ampersands"> <xsl:with-param name="text" select="."/> </xsl:call-template> </xsl:template> <!-- 递归替换文本中的&字符 --> <xsl:template name="replace-ampersands"> <xsl:param name="text"/> <xsl:choose> <xsl:when test="contains($text, '&')"> <xsl:value-of select="substring-before($text, '&')"/> <xsl:text>&amp;</xsl:text> <xsl:call-template name="replace-ampersands"> <xsl:with-param name="text" select="substring-after($text, '&')"/> </xsl:call-template> </xsl:when> <xsl:otherwise> <xsl:value-of select="$text"/> </xsl:otherwise> </xsl:choose> </xsl:template> </xsl:stylesheet>
关键说明
- 修复模板顺序:元素模板中先处理属性节点(
@*),再处理子节点,符合XML语法要求,彻底解决报错问题。 - 字符映射保留:继续使用
<xsl:character-map>将—(emdash字符)转换为—实体输出,保留原有需求的转换逻辑。 - &字符替换:通过递归模板遍历文本节点,将所有
&字符(对应原XML中的&amp;)替换为&实体,实现目标转换效果。
内容的提问来源于stack exchange,提问作者Rahul
相关产品推荐
相关产品推荐

