【问题标题】:Namespace issues while transforming xml using xslt stylesheet使用 xslt 样式表转换 xml 时的命名空间问题
【发布时间】:2015-07-23 13:28:02
【问题描述】:

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

在示例 1 中,<message> 元素是命名空间 http://www.origostandards.com/schema/mtg/v2 的一部分。它在 xml 中声明,<message> 元素存在于 xml 中,前缀为 mtg。我拥有的样式表开发符合此要求,但不保留根元素以外的其他元素的名称空间。 如果未声明消息元素所属的命名空间(示例 2),则样式表必须生成具有在根元素中声明的默认命名空间 http://www.origoservices.com 的输出。(参见示例 2)

但是,我开发的样式表在(示例 2)没有分配给元素的命名空间前缀的情况下运行良好,并且不适用于具有以命名空间为前缀的命名空间元素名称的 xml(示例 1) .

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

实际输出

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

预期输出

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

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

预期和实际产出

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

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

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

【问题讨论】:

  • 我不明白“默认命名空间声明”的含义。您能否提供一个与您的 XSLT 配合良好的 XML 示例?谢谢。
  • @potame 我已通过在其末尾添加示例 xml 来更新问题。我对命名空间概念的理解不是很清楚,因此我可能误称它为“默认命名空间声明”
  • 好的,它更清楚一点,但在您预期的 XML 输出中,我没有看到添加任何 默认命名空间
  • +1 用于识别我的问题中的缺陷。我已经更新了我的问题。但是,基本上我的问题是,在问题中提供的示例 1 的情况下,我开发的样式表不会保留名称空间。

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


【解决方案1】:

有点乱,搞不懂你为什么不用&lt;xsl:copy-of&gt;指令。

这样的样式表要简单得多,并且可以正确完成工作(我已经删除了第一个模板中的一些代码,因为我没有发现它对我们感兴趣的问题有任何用处:

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

一些解释:

  1. 首先我声明了mtgce 命名空间,以便我可以在样式表中使用它们。
  2. 然后我匹配并处理没有附加命名空间的&lt;message&gt; 元素。复制此元素并附加适当的命名空间,并处理子元素
  3. 所有其他元素都简单地复制到输出中,包括所有子元素(和命名空间)。

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

【讨论】:

  • 我的 xslt 看起来很复杂的原因,因为如果默认命名空间声明中不存在,我必须在 Datapower 中将 context variable 的值设置为某个值(假设为“Y”)请求 xml。在我的 xslt 中,我试图通过使用 &lt;dp:set-variable name="'var://context/FL/AddNamspace'" value="'Y'"/&gt; 来实现这一点。此外,并非所有请求 xml 都具有相同的命名空间,因此我的方法必须是动态的。您的解决方案无法解决这些问题。希望我没有让您感到困惑。
  • 好的,在这个 XSLT 中仍然可以恢复被删除的代码。您能解释一下您的样式表中需要的动态方面吗?这是&lt;xsl:variable name="origo-svc-ns" select="'http://www.origoservices.com'"/&gt;的目的吗?
【解决方案2】:

你的问题很难理解,如果不是不可能的话。与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>

【讨论】:

    猜你喜欢
    • 2010-12-16
    • 1970-01-01
    • 2016-04-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-05-26
    • 2018-06-27
    相关资源
    最近更新 更多