使用xslt

时间:2015-11-20 07:38:55

标签: xml xslt ibm-datapower

我的要求是使用xslt从输入xml中删除命名空间声明,如果某些条件为真。

我已经经历了stackoverflow中的各种论坛,之后我设法建立了一个xsl,但它仍然无法正常工作。我对xsl很新,因此需要一个帮助才能实现这一目标。

输入xml(名称空间声明正在出现)

           <?xml version="1.0"?>
              <message xmlns="http://www.origoservices.com"     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xsi:schemaLocation="http://www.origoservices.com CEBondRealTimeValuationResponse.XSD">
             <m_control>
              <control_timestamp>2015-11-18T12:15:00</control_timestamp>
               <message_id>428f7945-a3d8-49f8-ada3-b6e898ace9fe</message_id>
    <retry_number>0</retry_number>
    <message_type>test</message_type>
<message_version>test</message_version>
<message_status>Success</message_status>
<expected_response_type>synchronous</expected_response_type>
<initiator_id>Testing</initiator_id>
<responder_id>Test-comp</responder_id>
 </m_control>
     <m_content>
         <b_control>
    <contract_enquiry_reference/>
    <enquiry_response_status>Error</enquiry_response_status>
    <enquiry_error_note code="1005" sequence_number="1">
        <short_description>Contract not found.</short_description>
    </enquiry_error_note>
</b_control>
<intermediary/>
<request_scope>
    <valuation_request type="Current"/>
    <valuation_request type="Surrender"/>
    <fund_breakdown_request>
        <detailed_breakdown_ind>Yes</detailed_breakdown_ind>
    </fund_breakdown_request>
</request_scope>
<contract>
    <contract_reference_number>20015</contract_reference_number>
</contract>
   </m_content>
     </message>

预期输出:(应该没有http://www.origoservices.com并且必须保留其他名称空间声明)

   <?xml version="1.0" encoding="UTF-8"?>
     <message xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xsi:schemaLocation="http://www.origoservices.com CEBondRealTimeValuationResponse.XSD">
         <m_control>
             <control_timestamp>2015-11-18T12:15:00</control_timestamp>
    <message_id>428f7945-a3d8-49f8-ada3-b6e898ace9fe</message_id>
    <retry_number>0</retry_number>
    <message_type>test</message_type>
    <message_version>test</message_version>
    <message_status>Success</message_status>
    <expected_response_type>synchronous</expected_response_type>
    <initiator_id>Testing</initiator_id>
    <responder_id>Test-comp</responder_id>
</m_control>
<m_content>
    <b_control>
        <contract_enquiry_reference/>
        <enquiry_response_status>Error</enquiry_response_status>
        <enquiry_error_note code="1005" sequence_number="1">
            <short_description>Contract not found.</short_description>
        </enquiry_error_note>
    </b_control>
    <intermediary/>
    <request_scope>
        <valuation_request type="Current"/>
        <valuation_request type="Surrender"/>
        <fund_breakdown_request>
            <detailed_breakdown_ind>Yes</detailed_breakdown_ind>
        </fund_breakdown_request>
    </request_scope>
    <contract>
        <contract_reference_number>20015</contract_reference_number>
    </contract>
</m_content>
   </message>

我试过下面的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" extension-element-prefixes="dp" exclude-result-prefixes="dp">
          <xsl:output method="xml" indent="yes" version="1.0" /> 
         <xsl:variable name="origo-svc-augmented" select="'Y'"/>  
      <xsl:variable name="origo-svc-ns" select="'http://www.origoservices.com'" /> 
      <xsl:template match="*">
        <xsl:variable name="namespace" select="namespace-uri(.)" /> 
          <xsl:choose>
              <!-- 
          xsl:when test="$namespace = ''
                  or ($origo-svc-augmented='Y' and $namespace=$origo-svc-ns)"

         --> 
               <xsl:when test="$origo-svc-augmented = 'Y'">
                   <xsl:message dp:type="business-log" dp:priority="info">Namespace was augmented in the request rule</xsl:message> 
                <!-- Note: If we use "local-name()" instead of "name()" in below statement, then namespace prefixes will not be preserved. Using name(), will preserve the namespace prefixes
                  --> 
             <!-- xsl:element name="{name()} namespace="{$namespace}"
          --> 
                  <xsl:element name="{name()}">
               <xsl:copy-of select="namespace::*[not(namespace-uri()=$origo-svc-ns)]" /> 
               <xsl:apply-templates select="@*|node()|comment()|processing-instruction()|text()" /> 
               </xsl:element>
              </xsl:when>
           <xsl:otherwise>
         <xsl:element name="{name()}" namespace="{$namespace}">
        <xsl:copy-of select="namespace::*" /> 
          <xsl:apply-templates select="@*|node()|comment()|processing-instruction()|text()" /> 
        </xsl:element>
        </xsl:otherwise>
      </xsl:choose>
       </xsl:template>
     <xsl:template match="@*|comment()|processing-instruction()|text()">
   <xsl:copy>
     <xsl:apply-templates select="@*|node()|comment()|processing-instruction()|text()" /> 
      </xsl:copy>
     </xsl:template>
   </xsl:stylesheet>

更新

我试图将两个答案结合起来,并能够找到解决方案。请在下面找到有效的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" extension-element-prefixes="dp" exclude-result-prefixes="dp">
       <xsl:output method="xml" indent="yes" version="1.0"/>

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

      <xsl:template match="*">
        <xsl:variable name="namespace" select="namespace-uri(.)"/>
         <xsl:choose>
           <xsl:when test="($origo-svc-augmented = 'Y') and (namespace-uri() = $origo-svc-ns)">
            <xsl:message dp:type="business-log" dp:priority="info">Namespace was augmented in the request rule</xsl:message>
             <xsl:element name="{local-name()}">
            <xsl:copy-of select="namespace::*[.!='http://www.origoservices.com']"/>
              <xsl:apply-templates
                select="@* | node() | comment() | processing-instruction() | text()"/>
        </xsl:element>
         </xsl:when>
          <xsl:otherwise>
             <xsl:element name="{name()}" namespace="{$namespace}">
            <xsl:copy-of select="namespace::*"/>
            <xsl:apply-templates
                select="@* | node() | comment() | processing-instruction() | text()"/>
        </xsl:element>
        </xsl:otherwise>
        </xsl:choose>
        </xsl:template>
      </xsl:stylesheet>

4 个答案:

答案 0 :(得分:2)

重要的是要理解,就XDM数据模型而言,您正在做的不是删除命名空间,而是更改元素的名称。 / p>

除非您的元素或属性的内容(而不是其名称)中出现QNames(或名称空间前缀),否则您不必担心使用命名空间轴或生成命名空间节点。只需使用正确的名称生成元素和属性(我指的是名称空间URI加本地名称),名称空间声明将自行处理。

xsl:copy指令在应用于元素时,会复制元素的整个名称(名称空间URI加本地名称)。如果要生成具有相同本地名称但位于不同名称空间或没有名称空间的元素,则需要使用xsl:element name="{local-name()}"

您已经有大量的回复建议您需要编写哪些代码,但我认为在基本原则上添加一个词是有帮助的。

答案 1 :(得分:1)

如果我猜对了,你想做的事情如下:

XSLT 1.0

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

<xsl:param name="no-namespace" select="false()"/>

<xsl:template match="*">
    <xsl:choose>
        <xsl:when test="$no-namespace">
            <xsl:element name="{local-name()}">
                <xsl:copy-of select="namespace::*[.!='http://www.origoservices.com']"/>
                <xsl:copy-of select="@*"/>
                <xsl:apply-templates/>
            </xsl:element>
        </xsl:when>
        <xsl:otherwise>
            <xsl:copy>
                <xsl:copy-of select="namespace::*[.!='http://www.origoservices.com']"/>
                <xsl:copy-of select="@*"/>
                <xsl:apply-templates/>
            </xsl:copy>
        </xsl:otherwise>
    </xsl:choose>
</xsl:template>

</xsl:stylesheet>

no-namespace参数为true时,应用于输入示例的结果可能(请参阅下面的注释)为:

<?xml version="1.0" encoding="UTF-8"?>
<message xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xsi:schemaLocation="http://www.origoservices.com CEBondRealTimeValuationResponse.XSD">
   <m_control>
      <control_timestamp>2015-11-18T12:15:00</control_timestamp>
      <message_id>428f7945-a3d8-49f8-ada3-b6e898ace9fe</message_id>
      <retry_number>0</retry_number>
      <message_type>test</message_type>
      <message_version>test</message_version>
      <message_status>Success</message_status>
      <expected_response_type>synchronous</expected_response_type>
      <initiator_id>Testing</initiator_id>
      <responder_id>Test-comp</responder_id>
   </m_control>
   <m_content>
      <b_control>
         <contract_enquiry_reference/>
         <enquiry_response_status>Error</enquiry_response_status>
         <enquiry_error_note code="1005" sequence_number="1">
            <short_description>Contract not found.</short_description>
         </enquiry_error_note>
      </b_control>
      <intermediary/>
      <request_scope>
         <valuation_request type="Current"/>
         <valuation_request type="Surrender"/>
         <fund_breakdown_request>
            <detailed_breakdown_ind>Yes</detailed_breakdown_ind>
         </fund_breakdown_request>
      </request_scope>
      <contract>
         <contract_reference_number>20015</contract_reference_number>
      </contract>
   </m_content>
</message>

如果no-namespace参数为false,则结果将是输入的相同副本。

注意:

根据所使用的特定XSLT处理器,实际结果可能会有所不同。命名空间声明xmlns:ds="http://www.w3.org/2000/09/xmldsig#"不在任何地方使用,因此是多余的。您无法真正强制XSLT 1.0处理器输出冗余的命名空间声明。上面的结果对于Saxon 6.5和libxslt是正确的 - 但是Xalan将忽略复制命名空间的指令,并且 将被抑制。

答案 2 :(得分:0)

假设您只想删除与http://www.origoservices.com URI相关的命名空间,我会将删除命名空间的条件更改为:

 <xsl:when test="($origo-svc-augmented = 'Y') and (namespace-uri() = $origo-svc-ns)">

然后输出这样的元素,以避免复制名称空间:

<xsl:element name="{local-name()}">

使用<xsl:copy-of select="namespace::*[not(namespace-uri() = $origo-svc-ns)]"/>复制命名空间节点变得无用,您可以删除它。

然后您最终得到以下模板:

<xsl:template match="*">
    <xsl:variable name="namespace" select="namespace-uri(.)"/>
    <xsl:choose>
        <xsl:when test="($origo-svc-augmented = 'Y') and (namespace-uri() = $origo-svc-ns)">
            <xsl:message dp:type="business-log" dp:priority="info">Namespace was augmented in the request rule</xsl:message>
            <xsl:element name="{local-name()}">
                <xsl:apply-templates
                    select="@* | node() | comment() | processing-instruction() | text()"/>
            </xsl:element>
        </xsl:when>
        <xsl:otherwise>
            <xsl:element name="{name()}" namespace="{$namespace}">
                <xsl:copy-of select="namespace::*"/>
                <xsl:apply-templates
                    select="@* | node() | comment() | processing-instruction() | text()"/>
            </xsl:element>
        </xsl:otherwise>
    </xsl:choose>
</xsl:template>

这是获得的结果XML:

<?xml version="1.0" encoding="UTF-8"?>
<message xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://www.origoservices.com CEBondRealTimeValuationResponse.XSD">
    <m_control>
        <control_timestamp>2015-11-18T12:15:00</control_timestamp>
        <message_id>428f7945-a3d8-49f8-ada3-b6e898ace9fe</message_id>
        <retry_number>0</retry_number>
        <message_type>test</message_type>
        <message_version>test</message_version>
        <message_status>Success</message_status>
        <expected_response_type>synchronous</expected_response_type>
        <initiator_id>Testing</initiator_id>
        <responder_id>Test-comp</responder_id>
    </m_control>
    <m_content>
        <b_control>
            <contract_enquiry_reference/>
            <enquiry_response_status>Error</enquiry_response_status>
            <enquiry_error_note code="1005" sequence_number="1">
                <short_description>Contract not found.</short_description>
            </enquiry_error_note>
        </b_control>
        <intermediary/>
        <request_scope>
            <valuation_request type="Current"/>
            <valuation_request type="Surrender"/>
            <fund_breakdown_request>
                <detailed_breakdown_ind>Yes</detailed_breakdown_ind>
            </fund_breakdown_request>
        </request_scope>
        <contract>
            <contract_reference_number>20015</contract_reference_number>
        </contract>
    </m_content>
</message>

由于命名空间xmlns:ds="http://www.w3.org/2000/09/xmldsig#"从未在输入XML文档中使用,因此不会输出。

答案 3 :(得分: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" extension-element-prefixes="dp" exclude-result-prefixes="dp">
   <xsl:output method="xml" indent="yes" version="1.0"/>

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

  <xsl:template match="*">
    <xsl:variable name="namespace" select="namespace-uri(.)"/>
     <xsl:choose>
       <xsl:when test="($origo-svc-augmented = 'Y') and (namespace-uri() = $origo-svc-ns)">
        <xsl:message dp:type="business-log" dp:priority="info">Namespace was augmented in the request rule</xsl:message>
         <xsl:element name="{local-name()}">
        <xsl:copy-of select="namespace::*[.!='http://www.origoservices.com']"/>
          <xsl:apply-templates
            select="@* | node() | comment() | processing-instruction() | text()"/>
    </xsl:element>
     </xsl:when>
      <xsl:otherwise>
         <xsl:element name="{name()}" namespace="{$namespace}">
        <xsl:copy-of select="namespace::*"/>
        <xsl:apply-templates
            select="@* | node() | comment() | processing-instruction() | text()"/>
    </xsl:element>
    </xsl:otherwise>
    </xsl:choose>
    </xsl:template>
  </xsl:stylesheet>