Добавить новое пространство имен без корневого узла xslt 1.0 - PullRequest
0 голосов
/ 28 сентября 2019

Я видел сообщение XSLT: добавить объявление пространства имен к корневому элементу

Ответ @StuartLC работает в корне.Мне нужна помощь ... ¿Как бы вы добавили новое пространство имен к некорневому узлу?

Входной XML-документ (да, ужас, но он от клиента)

<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
    <soapenv:Header/>
    <S:Body xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
        <ns3:Response xmlns="ttn/xml" xmlns:ns2="rtm/xml" xmlns:ns3="ws/xml">
            <ns3:record>
                <registryID>
                    <registryNumber>232019324</registryNumber>
                </registryID>
                <ns2:Date>28-08-2019 09:12:32</ns2:Date>
                <ns2:registry>
                    <ns2:type>otp</ns2:type>
                    <sender>
                        <ID>260</ID>
                    </sender>
                </ns2:registry>
            </ns3:record>
        </ns3:Response>
    </S:Body>
</soapenv:Envelope>

И я бы хотел получить:

<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
    <soapenv:Header/>
    <S:Body xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
        <ns3:Response xmlns:ns1="ttn/xml" xmlns="ttn/xml" xmlns:ns2="rtm/xml" xmlns:ns3="ws/xml">
            <record>
                <ns1:registryID>
                    <ns1:registryNumber>232019324</ns1:registryNumber>
                </ns1:registryID>
                <ns2:Date>28-08-2019 09:12:32</ns2:Date>
                <ns2:registry>
                    <ns2:type>otp</ns2:type>
                    <ns1:sender>
                        <ns1:ID>260</ns1:ID>
                    </ns1:sender>
                </ns2:registry>
            </record>
        </ns3:Response>
    </S:Body>
</soapenv:Envelope>

Мне нужно добавить / удалить некоторые префиксы узлов.Например, узел <ns3:record> -> <record> или узел <registryID> -> <ns1:registryID> или узел <sender> -> <ns1:sender> .... есть еще несколько узлов xml, но я поставил только несколько.

Мне нужно включить ns1 в ответ узла, потому что когда я импортирую в SAP PO, он говорит "ns1 не объявлен".Я предположил, что я добавил префикс ns1 к узлу, но я не знаю.Я попробовал вручную в тесте SAP включить ns1 в узел и поработать над ним.После других преобразований xslt мне нужен только ответ узла на все xml для сопоставления.

Это xslt, который я использую:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"  xmlns="ttn/xml" xmlns:ns2="rtm/xml" xmlns:ns3="ws/xml"     xmlns:S="http://schemas.xmlsoap.org/soap/envelope/"
            xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">

<xsl:output omit-xml-declaration="yes" method="xml" indent="yes"/>
<xsl:strip-space elements="*"/>

<xsl:variable name ="mynoderecord">record</xsl:variable>
<xsl:variable name ="mynodeResponse">Response</xsl:variable> 
<xsl:variable name ="mynoderegistryNumber">registryNumber</xsl:variable>
<xsl:variable name ="mynodeRegistryID">registryID</xsl:variable>
<xsl:variable name ="mynodesender">sender</xsl:variable>


  <xsl:template match="*" >
  <xsl:choose>

    <xsl:when test="local-name() = $mynodeResponse">
     <xsl:element name="ns3:{local-name()}" xmlns:ns3="ws/xml">
    <xsl:attribute name="ns1:nsdf" namespace="ttn/xml">sdf</xsl:attribute>

       <xsl:for-each select="@*">
           <xsl:attribute name="{local-name()}">
           <xsl:value-of select="."/>
         </xsl:attribute>
       </xsl:for-each>
      <xsl:apply-templates/>
     </xsl:element>
    </xsl:when>


    <xsl:when test="local-name() = $mynoderegistryNumber" >
     <xsl:element name="ns1:{name()}" xmlns:ns1="ttn/xml">
       <!-- procesar atributos de nodo -->
       <xsl:for-each select="@*">
       <!-- eliminar prefijo de atributo -->
         <xsl:attribute name="{local-name()}">
           <xsl:value-of select="."/>
         </xsl:attribute>
       </xsl:for-each>
      <xsl:apply-templates/>
     </xsl:element>
    </xsl:when>

    <xsl:when test="local-name() = $mynodesender" >
     <xsl:element name="ns1:{name()}" xmlns:ns1="ttn/xml">
       <!-- procesar atributos de nodo -->
       <xsl:for-each select="@*">
       <!-- eliminar prefijo de atributo -->
         <xsl:attribute name="{local-name()}">
           <xsl:value-of select="."/>
         </xsl:attribute>
       </xsl:for-each>
      <xsl:apply-templates/>
     </xsl:element>
    </xsl:when>

    <xsl:when test="local-name() = $mynodeRegistryID" >
     <xsl:element name="ns1:{name()}" xmlns:ns1="ttn/xml">
       <!-- procesar atributos de nodo -->
       <xsl:for-each select="@*">
       <!-- eliminar prefijo de atributo -->
         <xsl:attribute name="{local-name()}">
           <xsl:value-of select="."/>
         </xsl:attribute>
       </xsl:for-each>
      <xsl:apply-templates/>
     </xsl:element>
    </xsl:when>

    <xsl:when test="local-name() = $mynoderecord">
     <xsl:element name="{local-name()}" xmlns:ns3="ws/xml">
       <!-- procesar atributos de nodo -->
       <xsl:for-each select="@*">
       <!-- eliminar prefijo de atributo -->
         <xsl:attribute name="{local-name()}">
           <xsl:value-of select="."/>
         </xsl:attribute>
       </xsl:for-each>
      <xsl:apply-templates/>
     </xsl:element>
    </xsl:when>


    <xsl:otherwise>
     <xsl:element name="{name()}">
       <!-- procesar atributos de nodo -->
       <xsl:for-each select="@*">
       <!-- eliminar prefijo de atributo -->
         <xsl:attribute name="{local-name()}">
           <xsl:value-of select="."/>
         </xsl:attribute>
       </xsl:for-each>
      <xsl:apply-templates/>
     </xsl:element>
     </xsl:otherwise>

  </xsl:choose>

  </xsl:template>

</xsl:stylesheet>

При поиске я увидел, что добавление атрибута к узлу <ns3:Response>, пространство имен ns1 добавляется автоматически ... но мне не нравится.Конечно, есть простое решение с лучшим кодом ... xsl сведет меня с ума.

Я пытался, но я не мог найти более простое подходящее решение.

Не могли бы вы посоветовать мне?

Спасибо

Ответы [ 2 ]

0 голосов
/ 30 сентября 2019

Это может или не может дать точный результат, который вы ожидаете получить, в зависимости от прихоти вашего XSLT-процессора:

XSLT 1.0

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

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

<xsl:template match="ns3:Response">
     <ns3:Response xmlns:ns1="ttn/xml" xmlns="ttn/xml" xmlns:ns2="rtm/xml" xmlns:ns3="ws/xml">
        <xsl:apply-templates/>
    </ns3:Response>
</xsl:template>

<xsl:template match="ns3:record">
    <record xmlns="ttn/xml">
        <xsl:apply-templates/>
    </record>
</xsl:template>

<xsl:template match="ns1:*">
    <xsl:element name="ns1:{local-name()}">
        <xsl:apply-templates/>
    </xsl:element>
</xsl:template>

</xsl:stylesheet>

Обратите внимание, что только третий шаблон делает что-то существенное: он перемещает ns3:record в другое пространство имен.Другие шаблоны являются чистой косметикой и не должны быть необходимыми.

0 голосов
/ 29 сентября 2019

Необходимо отличать «добавление узла пространства имен» от «изменения расширенного имени элемента».

Для элемента Response вы добавляете узел пространства имен без изменения имен какого-либо элемента или атрибута.,В XSLT 2.0 вы можете сделать это с помощью инструкции xsl:namespace.В XSLT 1.0 это можно сделать только с довольно запутанным обходным путем: создайте фиктивный элемент в новом пространстве имен, а затем скопируйте его узел пространства имен:

<xsl:variable name="dummy">
  <ns1:dummy xmlns:ns1="ttn/xml"/>
</xsl:variable>
<xsl:copy-of select="exsl:node-set($dummy)//namespace::*"/>

Для элемента registryID вы фактически меняетерасширенное имя элемента, и для достижения этого вам обычно нужно использовать <xsl:element name="ns1:{local-name()} /> `

...