xslt от родных братьев до вложенных элементов - PullRequest
0 голосов
/ 04 сентября 2018

Я новичок в xslt, и я действительно борюсь со следующей задачей:

Из этого XML (обратите внимание, я не знаю количество дочерних узлов родительского узла):

<parent>
  <element_a id="e1"/>
  <element_b id="e2"/>
  <element_a id="e3"/>
  <element_c id="e4"/>
  ...
</parent>

Мне нужно получить этот XML:

<e1>
  <e2>
    <e3>
      <e4>
        ...
      </e4>
    </e3>
  </e2>
</e1>

Я пробовал несколько раз, но не могу получить правильный вывод. Вот одна попытка:

<xsl:template name="test">
    <xsl:element name="{@id}">
        <xsl:if test="position() != last()">
            <xsl:call-template name="test"/>
        </xsl:if>
    </xsl:element>
</xsl:template>
<xsl:template match="parent">
    <parent>
        <xsl:for-each select="./*">
            <xsl:for-each select=".">
                <xsl:element name="{@id}">
                    <xsl:if test="position() != last()">
                        <xsl:call-template name="test"/>
                    </xsl:if>
                </xsl:element>
            </xsl:for-each>
        </xsl:for-each>
    </parent>
</xsl:template>

Ответы [ 2 ]

0 голосов
/ 04 сентября 2018

Вот альтернатива в XSLT 3, которая использует for-each-group в рекурсивной функции, чтобы попытаться реализовать вложение способом, который позволяет потоковую передачу с процессорами, такими как Saxon 9.8 EE или обычная обработка XSLT 3 в других выпусках Saxon 9.8 или в Альтова (которая не поддерживает потоковую передачу):

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:mf="http://example.com/mf"
    exclude-result-prefixes="#all"
    version="3.0">

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

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

    <xsl:function name="mf:nest" as="node()*" streamability="absorbing">
        <xsl:param name="nodes" as="node()*"/>
        <xsl:for-each-group select="$nodes" group-adjacent="true()">
            <xsl:element name="{@id}">
                <xsl:sequence select="mf:nest(tail(current-group()))"/>
            </xsl:element>
        </xsl:for-each-group>
    </xsl:function>

    <xsl:template match="parent">
        <xsl:copy>
            <xsl:sequence select="mf:nest(*)"/>
        </xsl:copy>
    </xsl:template>

</xsl:stylesheet>

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

0 голосов
/ 04 сентября 2018

Вот один из способов сделать это:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="parent">
      <xsl:apply-templates select="*[1]"/>
    </xsl:template>

    <xsl:template match="parent/*">
      <xsl:element name="{@id}">
        <xsl:apply-templates select="following-sibling::*[1]"/>
      </xsl:element>
    </xsl:template>
</xsl:stylesheet>

Очевидно, что вам нужно добавить определенную обработку других элементов, но, надеюсь, это должно указать вам правильную структуру.

Он работает так, что родительский элемент обрабатывает только своего первого потомка, затем каждый дочерний элемент родительского элемента создает элемент с именем, соответствующим атрибуту id, а затем обрабатывает следующий элемент как новый дочерний, рекурсивно.

Одна ошибка с этим - если атрибут id когда-либо содержит значение, которое не является допустимым именем элемента, преобразование завершится неудачей.

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