使用xslt样式表转换xml时发生命名空间问题

时间:2021-10-14 21:54:33

In my case,The Input xml must have a declaration of namespace of which the root element (i.e. <message>) is part of .

在我的例子中,Input xml必须具有命名空间的声明,其中根元素(即 )是其中的一部分。

In the example 1,<message> element is a part of namespace http://www.origostandards.com/schema/mtg/v2.It is declared in the xml and the <message> element is present in the xml with the prefix mtg.The styelesheet which I have developed conforms to this requirement, but doesn't preserve the namespace for other elements than the root element. If namespace of which the message element is a part of, is not declared (example2), then the styelesheet must produce an output having the default namespace http://www.origoservices.com declared in the root element.(See example2)

在示例1中, 元素是命名空间的一部分http://www.origostandards.com/schema/mtg/v2.It在xml中声明, 元素在xml中以前缀出现mtg。我开发的styelesheet符合此要求,但不保留除根元素之外的其他元素的命名空间。如果未声明消息元素所属的名称空间(example2),那么styelesheet必须生成一个输出,该输出具有在根元素中声明的默认名称空间http://www.origoservices.com。(参见example2)

However, the stylesheet which I have developed works well in case of (example 2) which doesn't have the namespace prefixes assigned to the elements and doesn't work for the xmls having namespace element names prefixed with namespace (example1).

但是,我开发的样式表在(示例2)的情况下运行良好,该示例没有为元素分配名称空间前缀,并且对于具有名称空间元素名称前缀为命名空间(example1)的xmls不起作用。

Example 1 input xml

示例1输入xml

<?xml version="1.0"?>
<mtg:message xmlns:ce="http://www.origostandards.com/schema/ce/v2" xmlns:mtg="http://www.origostandards.com/schema/mtg/v2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<mtg:m_control id="m_control1">
    <mtg:control_timestamp>2014-12-18T10:06:00-05:00</mtg:control_timestamp>
    <mtg:message_id>c5-a4e0-aa0090358c7f</mtg:message_id>
    <mtg:retry_number>0</mtg:retry_number>
    <mtg:expected_response_type>synchronous</mtg:expected_response_type>
    <mtg:initiator_id>temp</mtg:initiator_id>
    <mtg:responder_id/>
</mtg:m_control>
<ce:m_content>
    <ce:b_control>
        <ce:reference>xyz</ce:reference>
    </ce:b_control>
</ce:m_content>
</mtg:message>

Actual output

 <?xml version="1.0" encoding="UTF-8"?>
 <mtg:message xmlns:ce="http://www.origostandards.com/schema/ce/v2" xmlns:mtg="http://www.origostandards.com/schema/mtg/v2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<m_control xmlns="http://www.origostandards.com/schema/mtg/v2" id="m_control1">
    <control_timestamp>2014-12-18T10:06:00-05:00</control_timestamp>
    <message_id>c5-a4e0-aa0090358c7f</message_id>
    <retry_number>0</retry_number>
    <expected_response_type>synchronous</expected_response_type>
    <initiator_id>temp</initiator_id>
    <responder_id/>
</m_control>
<m_content xmlns="http://www.origostandards.com/schema/mtg/v2">
    <b_control>
        <reference>xyz</reference>
    </b_control>
</m_content>
</mtg:message>

Expected Output

 <?xml version="1.0"?>
 <mtg:message xmlns:ce="http://www.origostandards.com/schema/ce/v2" xmlns:mtg="http://www.origostandards.com/schema/mtg/v2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <mtg:m_control id="m_control1">
    <mtg:control_timestamp>2014-12-18T10:06:00-05:00</mtg:control_timestamp>
    <mtg:message_id>c5-a4e0-aa0090358c7f</mtg:message_id>
    <mtg:retry_number>0</mtg:retry_number>
    <mtg:expected_response_type>synchronous</mtg:expected_response_type>
    <mtg:initiator_id>temp</mtg:initiator_id>
    <mtg:responder_id/>
</mtg:m_control>
<ce:m_content>
    <ce:b_control>
        <ce:reference>xyz</ce:reference>
    </ce:b_control>
</ce:m_content>
</mtg:message>

Example 2 - Stylesheet is working as expected for this Input xml

示例2 - 样式表正在按预期为此输入xml工作

<message>
  <m_control>
    <control_timestamp>2014-11-05T09:30:38.308</control_timestamp>
    <retry_number>0</retry_number>
    <expected_response_type>synchronous</expected_response_type>
     <responder_id>Exchange Life 1</responder_id>
   </m_control>
</message>

Expected and Actual Output

预期和实际产出

<message xmlns="http://www.origoservices.com">
<m_control>
  <control_timestamp>2014-11-05T09:30:38.308</control_timestamp>
  <retry_number>0</retry_number>
  <expected_response_type>synchronous</expected_response_type>
  <responder_id>Exchange Life 1</responder_id>
 </m_control>
 </message>

My stylesheet

    <?xml version="1.0" encoding="UTF-8"?>
    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:dp="http://www.datapower.com/extensions" xmlns:regexp="http://exslt.org/regular-expressions" extension-element-prefixes="dp" xmlns:exsl="http://exslt.org/common" exclude-result-prefixes="dp regexp exsl">
      <xsl:output method="xml" indent="yes" version="1.0"/>

       <xsl:variable name="origo-svc-ns" select="'http://www.origoservices.com'"/>

      <!--xsl:template match="/message"-->
      <xsl:template match="/*[local-name()='message']">
         <xsl:variable name="name" select="name()"/>
         <xsl:variable name="namespace-in" select="namespace-uri(/*[1])"/>
         <xsl:variable name="initiator_id" select="/*[local-name()='message']/*[local-name()='m_control']/*[local-name()='initiator_id']"/>

   <!--Below code tests if default namespace declaration is present. If not, then assigns the 'default namespace' to 'namespace' variable. Also, it assigns context variable  "AddNamespace"  with value "Y" if default namespace declaration is not present -->       

         <xsl:variable name="namespace">
                  <xsl:choose>
                      <xsl:when test="$namespace-in = '' and ($initiator_id = 'True Potential' or $initiator_id = '2Plan' or $initiator_id = '356356536' or $initiator_id = 'Assyst Software') ">
                              <xsl:value-of select="$origo-svc-ns"/>
                              <dp:set-variable name="'var://context/FL/AddNamspace'" value="'Y'"/>
                      </xsl:when>
                     <xsl:otherwise>
                              <xsl:value-of select="$namespace-in"/>
                     </xsl:otherwise>
                </xsl:choose>
      </xsl:variable>

     <!-- - In below statement, {$namespace} will copy over the default namespace declarartion to the destination.
  - copy-of select statement will copy over all the namespace declaration in the source xml 
  - apply-template will copy over evrything else from the source to destination
  - xsl:element wil create an element node (in this case <message> ) in the destination document.      
    -->

    <xsl:element name="{$name}" namespace="{$namespace}">
       <xsl:copy-of select="namespace::*"/>
      <xsl:apply-templates select="@*|node()|comment()|processing-instruction()|text()">
      <xsl:with-param name="ns-uri" select="$namespace"/>

     </xsl:apply-templates>
     </xsl:element>
  </xsl:template>

  <xsl:template match="node()">

    <xsl:param name="ns-uri"/>
    <xsl:element name="{local-name()}" namespace="{$ns-uri}">
     <xsl:copy-of select="namespace::*"/>
       <xsl:apply-templates select="@*|node()|comment()|processing-instruction()|text()">
        <xsl:with-param name="ns-uri" select="$ns-uri"/>
       </xsl:apply-templates>
     </xsl:element>
  </xsl:template>

  <xsl:template match="@*|comment()|processing-instruction()|text()">
       <xsl:param name="ns-uri"/>
       <xsl:copy>
      <xsl:apply-templates select="@*|node()|comment()|processing-instruction()|text()">
        <xsl:with-param name="ns-uri" select="$ns-uri"/>
      </xsl:apply-templates>
    </xsl:copy>
  </xsl:template>
</xsl:stylesheet>

Example of the xml having default namespace declared http://www.origoservices.com is a default namespace in the below example.

声明为http://www.origoservices.com的默认名称空间的xml示例是以下示例中的默认名称空间。

  <message xmlns="http://www.origoservices.com" xmlns:a="https://www.bbb.com">
  <m_control>
    <control_timestamp>2014-11-05T09:30:38.308</control_timestamp>
    <message_id>2840c35d-d294-4179-baa1-55ea2ce0b9ac</message_id>
    <retry_number>0</retry_number>
    <message_type>Quotation Request</message_type>
          <message_version>/origo/3.7/QNBPensionAnnuityQuoteRequest.xsd</message_version>
    <expected_response_type>synchronous</expected_response_type>
    <initiator_id>Friends Provident</initiator_id>
       <initiator_orchestration_id>2944460</initiator_orchestration_id>
    <responder_id>Exchange Life 1</responder_id>
</m_control>
 </message>

2 个解决方案

#1


It is a bit messy, I can't figure out why you don't use the <xsl:copy-of> instruction.

它有点乱,我无法弄清楚为什么你不使用 指令。

Such stylesheet is much more simple and will do the job properly (I have remove some the the code in first template because I didn't find any use to it for the issue we're interested in here:

这样的样式表更加简单,并且可以正常工作(我已经删除了第一个模板中的一些代码,因为我没有找到任何用途,我们对此感兴趣的问题:

<xsl:stylesheet version="1.0" 
        xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
        xmlns:dp="http://www.datapower.com/extensions" 
        xmlns:regexp="http://exslt.org/regular-expressions" 
        xmlns:ce="http://www.origostandards.com/schema/ce/v2"
        xmlns:mtg="http://www.origostandards.com/schema/mtg/v2"
        xmlns:exsl="http://exslt.org/common" 
        exclude-result-prefixes="dp regexp exsl">

    <xsl:output method="xml" indent="yes" version="1.0"/>

    <xsl:variable name="origo-svc-ns" select="'http://www.origoservices.com'"/>

    <xsl:template match="/message">
        <xsl:variable name="name" select="name()"/>


     <!-- - In below statement, {$namespace} will copy over the default namespace declarartion to the destination.
  - copy-of select statement will copy over all the namespace declaration in the source xml 
  - apply-template will copy over evrything else from the source to destination
  - xsl:element wil create an element node (in this case <message> ) in the destination document.      
    -->

      <xsl:element name="{$name}" namespace="{$origo-svc-ns}">
        <!--xsl:copy-of select="namespace::*"/-->
        <xsl:apply-templates select="@*|node()|comment()|processing-instruction()|text()" />
      </xsl:element>
    </xsl:template>

    <xsl:template match="* | mtg:* | ce:*">
        <xsl:copy-of select="."/>
    </xsl:template>

</xsl:stylesheet>

Some explanations:

  1. first I declare the mtg and ce namespaces so that I can use them in the stylesheet.
  2. 首先,我声明了mtg和ce命名空间,以便我可以在样式表中使用它们。

  3. then I match and process the <message> element with no namespace attached. This element is copied with the appropriate namespace attached, and the child elements are processed
  4. 然后我匹配并处理没有附加名称空间的 元素。复制此元素并附加相应的命名空间,并处理子元素

  5. all the other elements are simply copied in the output, with all the sub-elements (and the namespaces).
  6. 所有其他元素都只是在输出中复制,包含所有子元素(和命名空间)。

I've checked this code with both entries (XML examples 1 and 2).

我用两个条目检查了这段代码(XML示例1和2)。

#2


Your question is very difficult, if not impossible, to understand. Same as your previous question (of which this is a spin-off), it lacks a clear statement of purpose.

你的问题很难理解,如果不是不可能的话。与您之前的问题(这是分拆的)相同,它缺乏明确的目的陈述。

If we assume that you just want your stylesheet to perform a certain transformation when the root element is in a default namespace (or in no namespace), and another transformation when it isn't (i.e. it has a prefix), then this could be achieved quite simply, for example:

如果我们假设您只希望样式表在根元素位于默认命名空间(或没有命名空间)时执行某个转换,而另一个转换则不是(即它具有前缀),那么这可能是实现非常简单,例如:

<xsl:template match="/">
    <xsl:choose>
        <xsl:when test="name(*)=local-name(*)">
            <!-- root element is in a default or no namespace; apply transformation A -->
        </xsl:when>
        <xsl:otherwise>
            <!-- root element has a prefix; apply transformation B -->
        </xsl:otherwise>
    </xsl:choose>
</xsl:template>

#1


It is a bit messy, I can't figure out why you don't use the <xsl:copy-of> instruction.

它有点乱,我无法弄清楚为什么你不使用 指令。

Such stylesheet is much more simple and will do the job properly (I have remove some the the code in first template because I didn't find any use to it for the issue we're interested in here:

这样的样式表更加简单,并且可以正常工作(我已经删除了第一个模板中的一些代码,因为我没有找到任何用途,我们对此感兴趣的问题:

<xsl:stylesheet version="1.0" 
        xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
        xmlns:dp="http://www.datapower.com/extensions" 
        xmlns:regexp="http://exslt.org/regular-expressions" 
        xmlns:ce="http://www.origostandards.com/schema/ce/v2"
        xmlns:mtg="http://www.origostandards.com/schema/mtg/v2"
        xmlns:exsl="http://exslt.org/common" 
        exclude-result-prefixes="dp regexp exsl">

    <xsl:output method="xml" indent="yes" version="1.0"/>

    <xsl:variable name="origo-svc-ns" select="'http://www.origoservices.com'"/>

    <xsl:template match="/message">
        <xsl:variable name="name" select="name()"/>


     <!-- - In below statement, {$namespace} will copy over the default namespace declarartion to the destination.
  - copy-of select statement will copy over all the namespace declaration in the source xml 
  - apply-template will copy over evrything else from the source to destination
  - xsl:element wil create an element node (in this case <message> ) in the destination document.      
    -->

      <xsl:element name="{$name}" namespace="{$origo-svc-ns}">
        <!--xsl:copy-of select="namespace::*"/-->
        <xsl:apply-templates select="@*|node()|comment()|processing-instruction()|text()" />
      </xsl:element>
    </xsl:template>

    <xsl:template match="* | mtg:* | ce:*">
        <xsl:copy-of select="."/>
    </xsl:template>

</xsl:stylesheet>

Some explanations:

  1. first I declare the mtg and ce namespaces so that I can use them in the stylesheet.
  2. 首先,我声明了mtg和ce命名空间,以便我可以在样式表中使用它们。

  3. then I match and process the <message> element with no namespace attached. This element is copied with the appropriate namespace attached, and the child elements are processed
  4. 然后我匹配并处理没有附加名称空间的 元素。复制此元素并附加相应的命名空间,并处理子元素

  5. all the other elements are simply copied in the output, with all the sub-elements (and the namespaces).
  6. 所有其他元素都只是在输出中复制,包含所有子元素(和命名空间)。

I've checked this code with both entries (XML examples 1 and 2).

我用两个条目检查了这段代码(XML示例1和2)。

#2


Your question is very difficult, if not impossible, to understand. Same as your previous question (of which this is a spin-off), it lacks a clear statement of purpose.

你的问题很难理解,如果不是不可能的话。与您之前的问题(这是分拆的)相同,它缺乏明确的目的陈述。

If we assume that you just want your stylesheet to perform a certain transformation when the root element is in a default namespace (or in no namespace), and another transformation when it isn't (i.e. it has a prefix), then this could be achieved quite simply, for example:

如果我们假设您只希望样式表在根元素位于默认命名空间(或没有命名空间)时执行某个转换,而另一个转换则不是(即它具有前缀),那么这可能是实现非常简单,例如:

<xsl:template match="/">
    <xsl:choose>
        <xsl:when test="name(*)=local-name(*)">
            <!-- root element is in a default or no namespace; apply transformation A -->
        </xsl:when>
        <xsl:otherwise>
            <!-- root element has a prefix; apply transformation B -->
        </xsl:otherwise>
    </xsl:choose>
</xsl:template>