XSLT 2.0 在应用模板后更改 ROOT 的默认命名空间值

XSLT 2.0 changing the default namespace value of ROOT after applying templates

我的目标是能够:

  1. 将根元素的 xmlns="http://xmlns.example.com/v1" 替换为 xmlns="http://xmlns.example.com" 没有 v1
  2. 将根元素的 schemaVersion="1" 替换为 schemaVersion="2" (版本 2)
  3. 应用其他 模板匹配 以排除(而不是添加)我需要从输入 xml.
  4. 中删除的节点

输入xml

<account xmlns="http://xmlns.example.com/v1" 
        xmlns:ns2="http://xmlns.example/v2"
        schemaVersion="1">
    <head>Jane Doe</head>    
    <accountNumber>1234567</accountNumber>
    <messageType>CREATE</messageType>
    <create>
        <ns2:profile>
            <ns2:accountNumber>1234567</ns2:accountNumber>
        </ns2:profile>
    </create>
    <ns2:tax>
        <ns2:taxExempt>false</ns2:taxExempt>
    </ns2:tax>
    <contact>
        <ns2:address>US</ns2:address>
    </contact>
</account>

期望输出xml

<account xmlns="http://xmlns.example.com" 
        xmlns:ns2="http://xmlns.example/v2"
        schemaVersion="2">
    <head>Jane Doe</head>    
    <messageType>ADD</messageType>
    <action>A</action>
        <ns2:profile>
            <ns2:accountNumber>1234567</ns2:accountNumber>
        </ns2:profile>
    <contact>
        <ns2:address>US</ns2:address>
    </contact>
</account>

在想要的输出中,我

  1. 已将根元素第一个命名空间值从 xmlns="http://xmlns.example.com/v1" 更改为 xmlns="http://xmlns.example.com" (无 v1)
  2. 已将根元素的 schemaVersion 属性值从 schemaVersion="1" 更改为 schemaVersion="2" (版本 2)
  3. 已删除 <accountNumber>
  4. 已将 <messageType> 值从 CREATE 更改为 ADD
  5. 已添加<action>A</action>
  6. 删除父节点 <create> 保留 其子节点。
  7. 删除了整个 <ns2:tax> 节点及其子节点

我设法产生了所需的输出。但是,它引入了一个问题

问题:在当前输出中 xml,xmlns="http://xmlns.example.com/v1" (版本 1) 添加到 <head><contact>.

xmlns="http://xmlns.example.com/v1"该走了.

我的 xsl 的当前输出

<account xmlns="http://xmlns.example.com" 
        xmlns:ns2="http://xmlns.example/v2"
        schemaVersion="2">
    <head xmlns="http://xmlns.example.com/v1">Jane Doe</head>    
    <messageType>ADD</messageType>
    <action>A</action>
        <ns2:profile>
            <ns2:accountNumber>1234567</ns2:accountNumber>
        </ns2:profile>
    <contact xmlns="http://xmlns.example.com/v1">
        <ns2:address>US</ns2:address>
    </contact>
</account>

我的 XSL 代码

<xsl:stylesheet version="2.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xpath-default-namespace="http://xmlns.example.com/v1"
    xmlns:ns2="http://xmlns.example/v2">

    <xsl:output method="xml" encoding="utf-8" indent="yes" />
    <xsl:strip-space elements="*" />

    <!-- Copy all text nodes, elements and attributes -->
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()" />
        </xsl:copy>
    </xsl:template>

    <!-- Replace root's xmlns and schemaVersion value -->
    <xsl:template match="account">
        <account xmlns="http://xmlns.example.com" 
                 xmlns:ns2="http://xmlns.example/v2"
                 schemaVersion="2">
            <xsl:apply-templates />
        </account>
    </xsl:template>
    
    <!-- remove <accountNumber> -->
    <xsl:template match="accountNumber" />
    
    <!-- Change messageType value from CREATE to ADD -->
    <!-- Add <action>A</action> -->
    <xsl:template
        match="account/messageType[text()='CREATE']">
        <xsl:element name='messageType'
            namespace='http://xmlns.example.com'>
            <xsl:value-of select="'ADD'" />
        </xsl:element>
        <xsl:element name='action'
            namespace='http://xmlns.example.com'>
            <xsl:value-of select="'A'" />
        </xsl:element>
    </xsl:template>
    
    <!-- remove node <create> but keep its children -->
    <xsl:template match="create">
        <xsl:apply-templates />
    </xsl:template>
    
    <!-- Removed entire <ns2:tax> node and its children -->
    <xsl:template match="ns2:tax" />

    <!-- Ensure that the namespace of nodes prefixed with ns2 has "http://xmlns.example/v2" value --> 
    <xsl:template match="ns2:*">
        <xsl:element name="ns2:{local-name()}"
            namespace="http://xmlns.example/v2">
            <xsl:apply-templates select="@*, node()" />
        </xsl:element>
    </xsl:template>

</xsl:stylesheet>

我遇到了困难,因为我必须首先将 xpath-default-namespace="http://xmlns.example.com/v1" 设置为版本 1 以匹配我要删除的节点然后我最终需要将 xmlns 值替换为不是版本 1 (xmlns="http://xmlns.example.com/")

对于解决此问题的任何建议或想法,我将不胜感激。

谢谢。

如果您想要或需要更改元素的命名空间(并且在某些元素上声明的命名空间适用于其所有后代,因此您需要更改根的命名空间及其所有后代);基于此,我认为您需要编写一个模板作为更改元素命名空间的起点:

<xsl:stylesheet version="2.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns="http://xmlns.example.com"
    xmlns:v1="http://xmlns.example.com/v1"
    xpath-default-namespace="http://xmlns.example.com/v1"
    xmlns:ns2="http://xmlns.example/v2"
    exclude-result-prefixes="v1">

    <xsl:output method="xml" encoding="utf-8" indent="yes" />
    <xsl:strip-space elements="*" />
        
    <xsl:template match="/*/@schemaVersion">
      <xsl:attribute name="{name()}">2</xsl:attribute>
    </xsl:template>
    
    <!-- Change namespace http://xmlns.example.com/v1 to http://xmlns.example.com-->
    <xsl:template match="v1:*">
        <xsl:element name="{local-name()}">
          <xsl:copy-of select="namespace::*[not(. = 'http://xmlns.example.com/v1')]"/>
          <xsl:apply-templates select="@* | node()"/>
        </xsl:element>
    </xsl:template>
    
    <!-- remove <accountNumber> -->
    <xsl:template match="accountNumber" />
    
    <!-- Change messageType value from CREATE to ADD -->
    <!-- Add <action>A</action> -->
    <xsl:template
        match="account/mesageType[.='CREATE']">
        <messageType>ADD</messageType>
        <action>A</action>
    </xsl:template>
    
    <!-- remove node <create> but keep its children -->
    <xsl:template match="create">
        <xsl:apply-templates />
    </xsl:template>
    
    <xsl:template match="ns2:*">
      <xsl:copy copy-namespaces="no">
        <xsl:copy-of select="namespace::*[not(. = 'http://xmlns.example.com/v1')]"/>
        <xsl:apply-templates select="@* | node()"/>
      </xsl:copy>
    </xsl:template>
    
    <!-- Removed entire <ns2:tax> node and its children -->
    <xsl:template match="ns2:tax" />

</xsl:stylesheet>