XSLT 1.0, скопировать все дочерние узлы, кроме некоторых - PullRequest
0 голосов
/ 04 января 2019

Я пытаюсь скопировать все дочерние узлы на определенный узел, кроме нескольких. Не удалось заставить это работать? Любые указатели на то, что я делаю неправильно?

Использование этого XML:

<ns0:Envelope xmlns:ns0="http://schemas.xmlsoap.org/soap/envelope/">
    <ns0:Header>
        <wsse:Sec xmlns:wsse="http://docs.x.org/wsse/"> 
            <saml:Ass xmlns:saml="http://docs.x.org/saml/">
                <ds:Sign xmlns:ds="http://docs.x.org/ds/">
                    <ds:SignVal>SignatureValue</ds:SignVal>
                </ds:Sign>
                <saml:subj>SubjectValue</saml:subj>
            </saml:Ass>
        </wsse:Sec>
        <To>http://localhost:8080/Test/</To>
        <Action>SendTest</Action>
    </ns0:Header>
    <ns0:Body>...</ns0:Body>
</ns0:Envelope>

Требуемый результат - получить тег Sec и всех потомков:

<wsse:Sec xmlns:wsse="http://docs.x.org/wsse/"> 
   <saml:Ass xmlns:saml="http://docs.x.org/saml/">
      <ds:Sign xmlns:ds="http://docs.x.org/ds/">
         <ds:SignVal>SignatureValue</ds:SignVal>
      </ds:Sign>
      <saml:subj>SubjectValue</saml:subj>
   </saml:Ass>
</wsse:Sec>

Я пробовал множество XSL, включая это:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" encoding="utf-8" indent="yes"/>
    <xsl:template match="Header">
        <xsl:copy-of select="*"/>
    </xsl:template>
    <!-- Exclude these -->
    <xsl:template match="To" />
    <xsl:template match="Action" />
</xsl:stylesheet>

В результате я получаю значения, но без тегов ...

Ответы [ 2 ]

0 голосов
/ 04 января 2019

Вам потребуется использовать XSLT 2 или 3 с

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:wsse="http://docs.x.org/wsse/"
    exclude-result-prefixes="#all"
    version="3.0">

  <xsl:template match="/">
      <xsl:copy-of select="//wsse:Sec" copy-namespaces="no"/>
  </xsl:template>

</xsl:stylesheet>

чтобы получить опубликованный результат с помощью простой инструкции копирования: https://xsltfiddle.liberty -development.net / bnnZVw

В XSLT 1 копия всегда будет копировать пространство имен в области действия xmlns:ns0="http://schemas.xmlsoap.org/soap/envelope/", поэтому, чтобы удалить его из результата, вам нужно будет выполнить код через какое-то преобразование, убирающее пространства имен в области действия (кроме одного из сам элемент):

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:wsse="http://docs.x.org/wsse/"
    exclude-result-prefixes="wsse"
    version="1.0">

  <xsl:template match="@*">
      <xsl:attribute name="{name()}" namespace="{namespace-uri()}">
          <xsl:value-of select="."/>
      </xsl:attribute>
  </xsl:template>

  <xsl:template match="*">
      <xsl:element name="{name()}" namespace="{namespace-uri()}">
          <xsl:apply-templates select="@* | node()"/>
      </xsl:element>
  </xsl:template>

  <xsl:template match="/">
      <xsl:apply-templates select="//wsse:Sec"/>
  </xsl:template>

</xsl:stylesheet>

https://xsltfiddle.liberty -development.net / bnnZVw / 1

0 голосов
/ 04 января 2019

Вы не учли пространства имен в вашем XSLT. В вашем XML Header находится в пространстве имен http://schemas.xmlsoap.org/soap/envelope/, но ваш XSLT пытается соответствовать Header без пространства имен.

Вам необходимо объявить пространства имен в вашем XSLT и использовать их в шаблонах совпадений

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                              xmlns:ns0="http://schemas.xmlsoap.org/soap/envelope/"
                              xmlns:wsse="http://docs.x.org/wsse/">
    <xsl:output method="xml" encoding="utf-8" indent="yes"/>

    <xsl:template match="ns0:Header">
        <xsl:copy-of select="wsse:Sec"/>
    </xsl:template>

    <xsl:template match="ns0:Body" />
</xsl:stylesheet>

Обратите внимание, что для XSLT не требуются шаблоны, соответствующие "Кому" и "Действие", поскольку явная копия wsse:Sec использует этот подход. Тем не менее, вам необходимо создать шаблон, чтобы убедиться, что любой тест в ns0:Body не выбран.

Другой подход заключается в использовании шаблона идентификации, и тогда у вас будут шаблоны для исключения To и ActionBody)

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                              xmlns:ns0="http://schemas.xmlsoap.org/soap/envelope/"
                              xmlns:wsse="http://docs.x.org/wsse/">
    <xsl:output method="xml" encoding="utf-8" indent="yes"/>

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

    <xsl:template match="ns0:Envelope|ns0:Header">
        <xsl:apply-templates />
    </xsl:template>

    <!-- Exclude these -->
    <xsl:template match="ns0:Body|To|Action" />
</xsl:stylesheet>

Обратите внимание, что существует шаблон, соответствующий ns0:Envelope и ns0:Header, поскольку, хотя сами эти элементы вам не нужны, вам нужно обработать дочерние узлы.

...