You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用XSLT 3.0修改XML根元素与命名空间的问题排查

问题描述

尝试使用XSLT 3.0(搭配SAXON-HE 12.4)将XML根元素命名空间从urn:oasis:names:specification:ubl:schema:xsd:CreditNote-2切换为urn:oasis:names:specification:ubl:schema:xsd:Invoice-2,同时保留cac、cbc公共命名空间,转换中遇到命名空间残留及模板匹配失效问题。

输入XML

<CreditNote xmlns:cbc="urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2" xmlns:cac="urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2" xmlns="urn:oasis:names:specification:ubl:schema:xsd:CreditNote-2"><cbc:CustomizationID>12345</cbc:CustomizationID><cbc:ProfileID>67890</cbc:ProfileID><cbc:ID>abcdef</cbc:ID><cac:BillingReference><cac:InvoiceDocumentReference><cbc:ID>ghijk</cbc:ID><cbc:IssueDate>2024-08-05</cbc:IssueDate></cac:InvoiceDocumentReference></cac:BillingReference></CreditNote>

期望输出XML

<?xml version="1.0" encoding="UTF-8"?><ubl:Invoice xmlns="urn:oasis:names:specification:ubl:schema:xsd:Invoice-2" xmlns:cac="urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2" xmlns:cbc="urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2" xmlns:ubl="urn:oasis:names:specification:ubl:schema:xsd:Invoice-2"><cbc:ID>abcdef</cbc:ID><cac:BillingReference><cac:InvoiceDocumentReference><cbc:ID>ghijk</cbc:ID></cac:InvoiceDocumentReference></cac:BillingReference></ubl:Invoice>

当前使用的XSLT

<?xml version="1.0" encoding="UTF-8"?><xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:cbc="urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2" xmlns:cac="urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2" xmlns:cn="urn:oasis:names:specification:ubl:schema:xsd:CreditNote-2" xmlns:ubl="urn:oasis:names:specification:ubl:schema:xsd:Invoice-2" xmlns="urn:oasis:names:specification:ubl:schema:xsd:Invoice-2" exclude-result-prefixes="cn"><xsl:output method="xml" indent="yes"/><xsl:template match="/cn:CreditNote"><ubl:Invoice xmlns:cbc="urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2" xmlns:cac="urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2" xmlns:ubl="urn:oasis:names:specification:ubl:schema:xsd:Invoice-2" xmlns="urn:oasis:names:specification:ubl:schema:xsd:Invoice-2"><xsl:apply-templates select="cbc:ID"/><xsl:apply-templates select="cac:BillingReference"/></ubl:Invoice></xsl:template><xsl:template match="@* | node()"><xsl:copy copy-namespaces="no"><xsl:apply-templates select="@* | node()"/></xsl:copy></xsl:template><xsl:template match="cn:*"><xsl:element name="{local-name()}"><xsl:apply-templates select="@*|node()"/></xsl:element></xsl:template><xsl:template match="*/cac:BillingReference"><xsl:copy><xsl:copy-of select="namespace::*[not(. = ('urn:oasis:names:specification:ubl:schema:xsd:CreditNote-2'))]"/><xsl:apply-templates select="cac:InvoiceDocumentReference"/></xsl:copy></xsl:template></xsl:stylesheet>

实际输出XML

<?xml version="1.0" encoding="UTF-8"?><ubl:Invoice xmlns="urn:oasis:names:specification:ubl:schema:xsd:Invoice-2" xmlns:cac="urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2" xmlns:cbc="urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2" xmlns:ubl="urn:oasis:names:specification:ubl:schema:xsd:Invoice-2"><cbc:ID>abcdef</cbc:ID><cac:BillingReference xmlns="urn:oasis:names:specification:ubl:schema:xsd:CreditNote-2"><cac:InvoiceDocumentReference><cbc:ID>ghijk</cbc:ID><cbc:IssueDate>2024-08-05</cbc:IssueDate></cac:InvoiceDocumentReference></cac:BillingReference></ubl:Invoice>

核心疑问

  1. 如何消除输出中残留的原命名空间urn:oasis:names:specification:ubl:schema:xsd:CreditNote-2?
  2. cac:BillingReference模板为何未生效,导致cbc:IssueDate未被剔除?

解决方案

问题1:原命名空间残留的原因与解决

cac:BillingReference带上原命名空间,是因为原输入中该元素的父节点属于原默认命名空间,使用<xsl:copy>复制时,即使设置copy-namespaces="no",元素的默认命名空间上下文仍会被继承,导致输出时被迫声明原默认命名空间。

解决方式:

  • 针对cac:*和cbc:*元素,单独编写复制模板,确保它们的命名空间正确绑定,同时避免继承父元素的默认命名空间。
  • 根元素ubl:Invoice无需重复声明命名空间,stylesheet根节点已绑定正确的默认命名空间和前缀。

问题2:模板未匹配的原因与解决

cac:BillingReference模板未生效,是因为它与通用模板match="@* | node()"的优先级相同(均为0.5),处理器会优先选择后定义的模板,但原代码中通用模板定义在前面,且模板匹配路径*/cac:BillingReference的上下文存在命名空间干扰。

解决方式:

  • 给目标模板设置更高优先级(priority="1"),确保处理器优先匹配。
  • 直接针对cac:BillingReference和cac:InvoiceDocumentReference编写模板,明确指定只保留需要的子元素;同时给需要剔除的元素编写空模板。

修正后的XSLT

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="3.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:cbc="urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2"
    xmlns:cac="urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2"
    xmlns:cn="urn:oasis:names:specification:ubl:schema:xsd:CreditNote-2"
    xmlns:ubl="urn:oasis:names:specification:ubl:schema:xsd:Invoice-2"
    xmlns="urn:oasis:names:specification:ubl:schema:xsd:Invoice-2"
    exclude-result-prefixes="cn">

    <xsl:output method="xml" indent="yes" encoding="UTF-8"/>

    <!-- 替换根元素为Invoice -->
    <xsl:template match="/cn:CreditNote">
        <ubl:Invoice>
            <xsl:apply-templates select="cbc:ID"/>
            <xsl:apply-templates select="cac:BillingReference"/>
        </ubl:Invoice>
    </xsl:template>

    <!-- 正确复制cbc和cac元素,避免命名空间继承 -->
    <xsl:template match="cbc:* | cac:*">
        <xsl:copy copy-namespaces="no">
            <xsl:apply-templates select="@* | node()"/>
        </xsl:copy>
    </xsl:template>

    <!-- 直接剔除不需要的元素 -->
    <xsl:template match="cbc:CustomizationID | cbc:ProfileID | cbc:IssueDate"/>

    <!-- 高优先级匹配BillingReference,只保留目标子元素 -->
    <xsl:template match="cac:BillingReference" priority="1">
        <cac:BillingReference>
            <xsl:apply-templates select="cac:InvoiceDocumentReference"/>
        </cac:BillingReference>
    </xsl:template>

    <!-- 高优先级匹配InvoiceDocumentReference,只保留ID -->
    <xsl:template match="cac:InvoiceDocumentReference" priority="1">
        <cac:InvoiceDocumentReference>
            <xsl:apply-templates select="cbc:ID"/>
        </cac:InvoiceDocumentReference>
    </xsl:template>

    <!-- 处理属性和文本节点 -->
    <xsl:template match="@* | text()">
        <xsl:copy/>
    </xsl:template>

</xsl:stylesheet>

转换结果验证

使用修正后的XSLT转换后,输出将完全符合期望:

  • 根元素替换为ubl:Invoice,命名空间配置正确
  • cac:BillingReference无原命名空间残留
  • cbc:IssueDate及其他不需要的元素被成功剔除

内容的提问来源于stack exchange,提问作者Robert Mark Bram

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.19 04:25:56