Распечатать все имена узлов между двумя тегами в XML с помощью XSLT - PullRequest
0 голосов
/ 11 октября 2018

У меня есть следующая структура XML:

<node0>
  <beforeContainer @id="test">
   <beforeContainer2/>
  </beforeContainer> 
    <container id='1'>
      <node1>
        <node2>
          <text>Test1</text>
        </node2>
      </node1>
    </container>
    <node3>
      <node4>
        <text>Test2</text>
        <node5>
          <container id='2'>
            <node6>
              <button>Click</button>
            </node6>
          </container>
        </node5>
      </node4>
    </node3>
    <text>Test3</text>
     <node7>
       <node8>
         <node9>
           <container id='3'>
             <node10>
               <button>Click2</button>
             </node10>
           </container>
         </node9>
       </node8>
     </node7>
   </node0>

Мне нужно извлечь все имена узлов между последовательными <container> узлами.Узлы <container> находятся на разном уровне глубины в дереве.

Вывод должен выглядеть следующим образом:

<container id='1'>
  <node1/>
  <node2/>
  <text/>
  <node3/>
  <node4/>
  <text/>
  <node5/>
</container>
<container id='2'>
  <node6/>
  <button/>
  <text/>
  <node7/>
  <node8/>
  <node9/>
</container>
<container id='3'>
  <node10/><button/>
</container>

Я пробовал разные выражения x-Path, но безуспешно, так как они всегда имеютнекоторая конкретная область (потомок-или-self :: node (), потомок и т. д.)

1 Ответ

0 голосов
/ 11 октября 2018

Простая проблема группировки в XSLT 2 или 3:

  <xsl:template match="/*">
      <xsl:for-each-group select="descendant::*" group-starting-with="container">
          <xsl:copy>
              <xsl:copy-of select="@*"/>
              <xsl:apply-templates select="current-group() except ." mode="copy"/>
          </xsl:copy>
      </xsl:for-each-group>
  </xsl:template>

  <xsl:template match="*" mode="copy">
      <xsl:copy/>
  </xsl:template>

Полный пример https://xsltfiddle.liberty -development.net / bdxtqQ :

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

  <xsl:mode on-no-match="shallow-copy"/>

  <xsl:output method="xml" indent="yes"/>

  <xsl:template match="/*">
      <xsl:for-each-group select="descendant::*" group-starting-with="container">
          <xsl:copy>
              <xsl:copy-of select="@*"/>
              <xsl:apply-templates select="current-group() except ." mode="copy"/>
          </xsl:copy>
      </xsl:for-each-group>
  </xsl:template>

  <xsl:template match="*" mode="copy">
      <xsl:copy/>
  </xsl:template>

</xsl:stylesheet>

Asдля редактирования наличия элементов, предшествующих первому container, который вы не хотите выводить, измените шаблон, выполняющий группировку, на

  <xsl:template match="/*">
      <xsl:for-each-group select="descendant::*" group-starting-with="container">
          <xsl:if test="self::container">
              <xsl:copy>
                  <xsl:copy-of select="@*"/>
                  <xsl:apply-templates select="current-group() except ." mode="copy"/>
              </xsl:copy>              
          </xsl:if>
      </xsl:for-each-group>
  </xsl:template>

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

Принцип работы for-each-group group-starting-with (см. https://www.w3.org/TR/xslt-30/#element-for-each-group) заключается в том, что если первый элемент в группе не соответствует шаблону group-starting-with, он, тем не менее, образует группу:

Если присутствует атрибут group-начиная-с, то его значение должно быть шаблоном.

Элементы в совокупности проверяются в порядке заполнения. Если элемент соответствует шаблону, или является первым элементом в совокупности, затем создается новая группа, и элемент становится его первым членом. В противном случае элемент добавляется в ту же группу, что и предыдущий элемент в совокупности.

Это полезно во многих случаях, но часто требуетo использовать вложенный xsl:if или xsl:choose внутри xsl:for-each-group, который проверяет, есть ли у нас "настоящая" группа, соответствующая шаблону group-starting-with, или мы только что собрали какие-либо элементы перед первой такой группой.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...