使用xslt有条件地添加默认命名空间

时间:2015-05-06 14:23:28

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

要求:

  • 检查请求xml中是否存在默认命名空间声明xmlns="http://www.origoservices.com

  • 如果没有,请添加默认命名空间声明。

示例请求xml 1:

<message xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<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:xsi="http://www.w3.org/2001/XMLSchema-instance" 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 2

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

<message xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 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>

预期输出:这应该与输入相同,因为它已经声明了默认命名空间。

<message xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 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>

我在xslt下面尝试了,但不知道如何添加条件以检查请求xml中是否存在默认命名空间声明。

   <xsl:stylesheet version="1.0"     xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:dp="http://www.datapower.com/extensions" xmlns="http://www.origoservices.com" extension-element-prefixes="dp" exclude-result-prefixes="dp">
   <xsl:output method="xml"/>
   <xsl:output omit-xml-declaration="yes" indent="yes"/>

   <!-- Below statements will copy all the elements and attributes from source to destination, normally this will copy over the element and attributes tags to destination-->

   <xsl:template match="node()|@*">
   <xsl:copy>
   <xsl:apply-templates select="node()|@*"/>
   </xsl:copy>
   </xsl:template>

  <xsl:template match="/*">
  <message xmlns="http://www.origoservices.com">
  <!--below statement will copy all the existing namespace declaration from source to destination-->
  <xsl:copy-of select="namespace::*" />
  <!--below statement will copy all the elements and attributes within the message root element to the resulting doc -->
  <xsl:apply-templates select="@*|node()" />
  </message>
</xsl:template>

更新 以下xslt以我想要的方式工作。但是,我确信这里有很多改进的范围。我希望专家对此进行审核并提出改进建议,以及任何循环漏洞,以防它们存在。

  <?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:variable name="origo-svc-ns" select="'http://www.origoservices.com'"/>

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

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

         <!--Variable "namespace-in" will contain the namespace uri of the namspace of which message element is a part-->
         <!--As message element is a part of namespace having uri "http://www.origoservices.com", this value will be assigned to the variable -->
         <xsl:variable name="namespace-in" select="namespace-uri()"/>


                     <!--Set Variable which stores the default namespace URI. This step will also set a context variable  "AddNamespace"  with value "Y" -->       
         <xsl:variable name="namespace">
                  <xsl:choose>
                      <xsl:when test="$namespace-in = ''">
                              <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 will 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>

  <!--Above template only copy over the values of element,attributes,etc to the destination, below template copies the names of elements (only nodes) to the destination-->

   <xsl:template match="node()">
     <xsl:param name="ns-uri"/>
       <xsl:element name="{local-name()}" namespace="{$ns-uri}">
         <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)

如果希望输出元素位于已知的命名空间中,可以将它们放在那里,而不检查源节点是否具有默认命名空间。以下样式表:

XSLT 1.0

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns="http://www.origoservices.com">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>

<xsl:template match="*">
    <xsl:element name="{local-name()}">
        <xsl:copy-of select="@*"/>
        <xsl:apply-templates select="node()"/>
    </xsl:element>
</xsl:template>

</xsl:stylesheet>

将返回相同的结果

<?xml version="1.0" encoding="UTF-8"?>
<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>

无论输入是否为:

<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具有不在默认命名空间中的元素,并且您希望保留这种区别,那么它会变得更复杂。

编辑:

回应:

  

为了达到这个目的,我应该跟踪“对于哪些请求   名称空间声明已明确添加“

当您的输出没有可以保留此信息的节点时,我不知道您打算如何做到这一点。如果有,您可以将其值设置为:

<xsl:value-of select="/*/namespace::*[not (name())]='http://www.origoservices.com'"/>

当输入文档的根节点声明默认http://www.origoservices.com命名空间时会使其为“true”,否则为“false”。

答案 1 :(得分:0)

以下xslt对我来说很好。

  <?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:variable name="origo-svc-ns" select="'http://www.origoservices.com'"/>

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

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

     <!--Variable "namespace-in" will contain the namespace uri of the namspace of which message element is a part-->
     <!--As message element is a part of namespace having uri "http://www.origoservices.com", this value will be assigned to the variable -->
      <xsl:variable name="namespace-in" select="namespace-uri()"/>


                 <!--Set Variable which stores the default namespace URI. This step will also set a context variable  "AddNamespace"  with value "Y" -->       
       <xsl:variable name="namespace">
              <xsl:choose>
                  <xsl:when test="$namespace-in = ''">
                          <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 will 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>

   <!--Above template only copy over the values of element,attributes,etc to the destination, below template copies the names of elements (only nodes) to the destination-->

   <xsl:template match="node()">
     <xsl:param name="ns-uri"/>
       <xsl:element name="{local-name()}" namespace="{$ns-uri}">
         <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>