XSLT 替换命名空间并添加新的(未使用的)命名空间

标签 xslt namespaces

我想替换以下 XML 文档的命名空间

<?xml version="1.0" encoding="UTF-8"?> 
<ns0:Document xmlns:ns0="http://mydata.com/H2H/Automation">    
  <CstmrCdtTrfInitn>
    <GrpHdr>
    </GrpHdr>
  </CstmrCdtTrfInitn> 
</ns0:Document>
与以下
<?xml version="1.0" encoding="UTF-8"?> 
<Document xmlns="urn:iso:std:iso" 
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">    
  <CstmrCdtTrfInitn>
    <GrpHdr>
    </GrpHdr>
  </CstmrCdtTrfInitn> 
</Document>
关于可以转换它的 XSLT 有什么想法吗?
我尝试了以下 XSL,但它添加了带有第二个节点的命名空间,也无法删除第一个命名空间。
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output encoding="UTF-8" indent="yes"/>
  <xsl:template match="/*">
    <xsl:element name="{local-name()}" namespace="http://www.w3.org/2001/XMLSchema-instance">
      <xsl:copy-of select="./*" />
    </xsl:element>
  </xsl:template>
</xsl:stylesheet>

最佳答案

您的要求可能有点棘手:替换 Document 的默认命名空间元素很简单。但是添加未使用的xslns:xsi XSLT-1.0 中的命名空间需要 EXSLT 扩展和 Michael Kay 在回复 this question 时解释的特殊技术。 .它涉及在全局变量中创建一个未使用的元素,然后将其命名空间复制到模板中以替换默认命名空间。在 XSLT-2.0 及更高版本中,这会更容易(见下文)。
EXSLT 扩展并非在所有 XSLT-1.0 处理器中都可用。但是有必要从变量创建一个节点集。
所以所有的命名空间都将在 xsl:stylesheet 中定义元素,然后根元素(此处为 ns0:Document )与模板匹配并替换为其 local-name()添加新的默认命名空间的部分,然后复制变量中定义的元素的“虚拟”命名空间。

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:ns0="http://mydata.com/H2H/Automation" xmlns:urn="urn:iso:std:iso"  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ext="http://exslt.org/common">
<xsl:output method="xml" omit-xml-declaration="yes" indent="yes"/>
    
    <!-- identity template (except elements)-->
    <xsl:template match="node()[not(self::*)]|@*">
        <xsl:copy>
            <xsl:apply-templates select="node()|@*" />
        </xsl:copy>
    </xsl:template>  

    <xsl:variable name="nsXSI">
        <xsl:element name="xsi:dummy" namespace="http://www.w3.org/2001/XMLSchema-instance" />
    </xsl:variable>   
   
    <xsl:template match="ns0:*|*">
        <xsl:element name="{local-name()}" namespace="urn:iso:std:iso">
            <xsl:copy-of select="ext:node-set($nsXSI)/*/namespace::xsi" />
            <xsl:apply-templates select="node() | @*" />
        </xsl:element>
    </xsl:template>

</xsl:stylesheet>
即使在 XSLT-1.0 中,输出也应该符合预期:
<Document xmlns="urn:iso:std:iso" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
   <CstmrCdtTrfInitn>
      <GrpHdr>
      </GrpHdr>
   </CstmrCdtTrfInitn>
</Document>

简化的解决方案需要一个支持 XSLT-2.0 的处理器。然后你可以使用xsl:namespace指令如下,不需要“虚拟”变量:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:ns0="http://mydata.com/H2H/Automation">
<xsl:output method="xml" omit-xml-declaration="yes" indent="yes"/>

    <!-- identity template (except elements)-->
    <xsl:template match="node()[not(self::element())]|@*">
        <xsl:copy>
            <xsl:apply-templates select="node()|@*" />
        </xsl:copy>
    </xsl:template>  
   
    <xsl:template match="ns0:*|*">
        <xsl:element name="{local-name(.)}" namespace="urn:iso:std:iso">
            <xsl:namespace name="xsi">http://www.w3.org/2001/XMLSchema-instance</xsl:namespace>
            <xsl:apply-templates select="node() | @*" />
        </xsl:element>
    </xsl:template>

</xsl:stylesheet>
输出是一样的。

通过使用 XSLT-3.0+ 的 xsl:mode 可以进一步简化上述 XSLT-2.0 解决方案将身份模板替换为
<xsl:mode on-no-match="shallow-copy"/>

关于XSLT 替换命名空间并添加新的(未使用的)命名空间,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66199585/

相关文章:

java - 错误: The processing instruction target matching “[xX][mM][lL]” is not allowed

.net - 使用自定义 xslt 转换堆栈溢出问题

xslt - XPath 通过命名空间从同级中获取值(value)

php - 在 Laravel 5 中使用 PSR4 的名称间距如何工作?

c# - 是否有更有效的方法来转换已经包含对 XSLT 的引用的 XDocument?

xml - 使用 Xpath 找到共同的 parent

Java:我可以在枚举中使用两个不同的名称来算作同一事物吗?

尝试使用 View 时出现 extjs 4 错误

Magento 从 Mage 命名空间调用我的命名空间 block

PHP 命名空间,目录重要吗?