Удаление объявления пространства имен с помощью xslt

Мое требование состоит в том, чтобы удалить объявление пространства имен из входного xml с помощью xslt, если определенное условие истинно.

Я просмотрел различные форумы в stackoverflow, после этого мне удалось создать xsl, но он все еще не работает. Я довольно новичок в xsl и, следовательно, мне нужна помощь, чтобы добиться этого.

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

person user2607367    schedule 20.11.2015    source источник
comment
Мое требование состоит в том, чтобы удалить объявление пространства имен из входного xml с помощью xslt, если выполняется определенное условие. Каково условие?   -  person har07    schedule 20.11.2015
comment
И хотели бы удалить все объявления пространств имен? Что мы должны делать с пространствами имен xsi и ds (последнее не используется в вашем XML)?   -  person potame    schedule 20.11.2015
comment
@ har07 Я хочу удалить только пространство имен, связанное с origoservices.com. когда $origo-svc-augmented = 'Y'   -  person user2607367    schedule 20.11.2015


Ответы (4)


Важно понимать, что с точки зрения модели данных XDM вы делаете не удаление пространства имен, а скорее изменение имени элемента.

Если у вас нет QName (или префиксов пространств имен), появляющихся в содержимом ваших элементов или атрибутов (в отличие от их имен), вам не нужно беспокоиться об использовании оси пространства имен или создании узлов пространства имен. Просто создайте элементы и атрибуты с правильными именами (под которыми я подразумеваю URI пространства имен плюс локальное имя), и объявления пространств имен позаботятся о себе сами.

Инструкция xsl:copy при применении к элементу копирует полное имя (URI пространства имен плюс локальное имя) элемента. Если вы хотите сгенерировать элемент с тем же локальным именем, но в другом пространстве имен или вообще без пространства имен, вам нужно использовать xsl:element name="{local-name()}"

У вас было много ответов, предлагающих, какой код вам нужно написать, но я подумал, что было бы полезно добавить пару слов об основных принципах.

person Michael Kay    schedule 20.11.2015

Если я правильно догадываюсь, вы хотите сделать что-то вроде:

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 проигнорирует инструкцию по копированию пространств имен, и избыточное пространство имен будет подавлено.

person michael.hor257k    schedule 20.11.2015
comment
Предоставлено обновление вопроса с рабочим XSLT - person user2607367; 20.11.2015

Предполагая, что вы хотите удалить только пространство имен, связанное с 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-документе, оно не будет выводиться.

person potame    schedule 20.11.2015
comment
Вы правильно догадались, я хочу удалить только пространство имен, связанное с origoservices.com. когда $origo-svc-augmented = 'Y' я попробовал ваш код, но на выходе все объявления пространств имен удаляются. - person user2607367; 20.11.2015
comment
Предоставлено обновление вопроса с рабочим XSLT - person user2607367; 20.11.2015
comment
Хорошо, я понимаю, но ИМХО нет смысла сохранять пространство имен xmlns:ds="http://www.w3.org/2000/09/xmldsig#", так как оно не используется. - person potame; 20.11.2015
comment
И, пожалуйста, рассмотрите добавление ответа на свой вопрос, а не как его обновление, и примите его, чтобы вопрос был закрыто (и, возможно, добавление полезных флажков для вопросов, которые помогли вам). Спасибо. - person potame; 20.11.2015

попытались объединить оба ответа и смогли найти решение для этого. Пожалуйста, найдите рабочий 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>
person user2607367    schedule 20.11.2015