如何在已有模板的XSLT中重命名XML元素
解决XSLT嵌套模板报错并实现元素重命名
问题描述
需要将XML中的<NAME>元素重命名为<CD-NAME>,同时将该元素放入<info>节点下,但编写的XSLT因在模板内部嵌套模板报错,错误提示为:Element xsl:template must be top-level。
输入XML
<?xml version="1.0" encoding="UTF-8"?> <CD xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <NAME>Empire Burlesque</NAME> </CD>
错误的XSLT尝试
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" exclude-result-prefixes="xs" xmlns:xs="http://www.w3.org/2001/XMLSchema" version="2.0"> <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/> <xsl:template match="@*|node()"> <xsl:copy> <xsl:apply-templates select="@*|node()" /> </xsl:copy> </xsl:template> <xsl:template match="/CD"> <xsl:variable name="id" select="*[contains(local-name(), 'NAME')]"/> <CD> <info> <xsl:copy-of select="$id" copy-namespaces="no"/> <xsl:template match="CD/NAME"> <CD-NAME><xsl:apply-templates select="@*|node()" /></CD-NAME> </xsl:template> </info> </CD> </xsl:template> </xsl:stylesheet>
错误原因
XSLT规范要求<xsl:template>必须是顶级元素,即直接作为<xsl:stylesheet>的子元素,不能嵌套在其他模板或节点内部。你之前将匹配<NAME>的模板放在了匹配/CD的模板内部,违反了语法规则,导致报错。
正确解决方案
把重命名的模板单独作为顶级元素,同时调整/CD模板的逻辑,用<xsl:apply-templates>触发重命名模板,而非直接复制原元素。
修正后的XSLT
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" exclude-result-prefixes="xs" xmlns:xs="http://www.w3.org/2001/XMLSchema" version="2.0"> <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/> <!-- 身份模板:默认复制所有节点和属性 --> <xsl:template match="@*|node()"> <xsl:copy> <xsl:apply-templates select="@*|node()"/> </xsl:copy> </xsl:template> <!-- 处理根CD节点,生成外层结构并触发内部元素的模板 --> <xsl:template match="/CD"> <CD> <info> <!-- 应用模板到NAME元素,触发重命名模板 --> <xsl:apply-templates select="NAME"/> </info> </CD> </xsl:template> <!-- 顶级模板:将NAME元素重命名为CD-NAME --> <xsl:template match="NAME"> <CD-NAME> <xsl:apply-templates select="@*|node()"/> </CD-NAME> </xsl:template> </xsl:stylesheet>
期望输出
<?xml version="1.0" encoding="UTF-8"?> <CD> <info> <CD-NAME>Empire Burlesque</CD-NAME> </info> </CD>
关键说明
- 身份模板:保留默认的节点复制逻辑,确保未被特殊模板匹配的节点原样输出。
- /CD模板:重新构建外层的
<CD>和<info>结构,通过<xsl:apply-templates select="NAME">触发重命名模板,而非xsl:copy-of(后者会直接复制原元素,不会触发任何模板)。 - NAME重命名模板:作为顶级模板,匹配所有
<NAME>元素,将其替换为<CD-NAME>并保留内部内容。
内容的提问来源于stack exchange,提问作者n718an
相关产品推荐
相关产品推荐

