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

时间:2015-05-12 15:08:01

标签: xml xslt namespaces xslt-1.0 ibm-datapower

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

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

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

示例1 输入xml

http://www.origoservices.com

实际输出

<?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>

预期输出

 <?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>

示例2 - 样式表正在按此预期用于此输入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>

预期和实际产出

<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>

我的样式表

<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>

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

    <?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>

2 个答案:

答案 0 :(得分:0)

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

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

<xsl:copy-of>

一些解释:

  1. 首先我声明了<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> mtg名称空间,以便我可以在样式表中使用它们。
  2. 然后我匹配并处理没有附加名称空间的ce元素。复制此元素时附加了相应的命名空间,并处理子元素
  3. 所有其他元素都只是在输出中复制,包含所有子元素(和命名空间)。
  4. 我已经用两个条目(XML示例1和2)检查了这段代码。

答案 1 :(得分:0)

您的问题即使不是不可能,也很难理解。与your previous question(其中这是分拆)相同,它缺乏明确的目的陈述。

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

<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>