如何使用XSLT 1.0仅复制XML属性的部分内容到新文档
问题解决:XSLT 1.0处理PRODUCT元素属性需求
需求
- 对所有PRODUCT元素的
name属性,仅保留点号(.)之前的内容 - 将
code属性值为12的PRODUCT节点,移除原code属性,添加delivery="done"属性
输入XML
<START> <LIST> <PRODUCT name="ELEMENT1.HKL" code="12" > <SPEC> <available>yes</available> </SPEC> </PRODUCT> <PRODUCT name="ELEMENT2.HKL" code="14" > <SPEC> <available>yes</available> </SPEC> </PRODUCT> </LIST> </START>
期望输出XML
<?xml version="1.0" encoding="UTF-8"?><START> <LIST> <PRODUCT delivery="done" name="ELEMENT1"> <SPEC> <available>yes</available> </SPEC> </PRODUCT> <PRODUCT code="14" name="ELEMENT2"> <SPEC> <available>yes</available> </SPEC> </PRODUCT> </LIST> </START>
原代码问题分析
原XSLT存在两处核心问题:
- 处理
code="12"的模板中,substring-before(., '.')的目标是当前@code属性值(即12),而非父节点的@name属性,导致无法正确截取name内容 - 未处理所有PRODUCT的
name属性,仅试图在code="12"的模板中修改name,遗漏了其他PRODUCT的需求
修正后的XSLT代码
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/> <xsl:strip-space elements="*"/> <!-- 身份模板:复制所有未被特殊模板匹配的节点和属性 --> <xsl:template match="@*|node()"> <xsl:copy> <xsl:apply-templates select="@*|node()"/> </xsl:copy> </xsl:template> <!-- 处理所有PRODUCT的name属性:截取点号前的内容 --> <xsl:template match="PRODUCT/@name"> <xsl:attribute name="name"> <xsl:choose> <!-- 如果name包含点号,截取前半部分;否则保留原内容 --> <xsl:when test="contains(., '.')"> <xsl:value-of select="substring-before(., '.')"/> </xsl:when> <xsl:otherwise> <xsl:value-of select="."/> </xsl:otherwise> </xsl:choose> </xsl:attribute> </xsl:template> <!-- 处理code属性值为12的情况:替换为delivery="done" --> <xsl:template match="PRODUCT/@code[.='12']"> <xsl:attribute name="delivery">done</xsl:attribute> </xsl:template> </xsl:stylesheet>
修改说明
- 新增专门匹配
PRODUCT/@name的模板,统一处理所有PRODUCT的name属性,确保无论code值如何,都能正确截取点号前的内容 - 修正
PRODUCT/@code[.='12']的模板:仅生成delivery="done"属性,不再处理name(name交给专门模板),同时原code属性会因被该模板匹配而不再被身份模板复制,达到移除原code属性的效果 - 保留身份模板,确保其他未修改的节点和属性正常复制
内容的提问来源于stack exchange,提问作者JC44
相关产品推荐
相关产品推荐

