XSLT плоский список в древовидную иерархию

Недавно столкнулся с проблемой, решения которой пока не нашел.

Мне дан файл XML с плоской иерархией, и я хочу преобразовать его в определенную иерархию.

<xml_file>
<dd/>
<b/>
<b/>
<dd/>
<b/>
<b/>
<dd/>
<k/>
<b/>
<b/>
<dd/>
<b/>
<b/>
</xml_file>

Во что я хочу превратить это:

<xml_file>
    <dd>
        <b/>
        <b/>
    </dd>
    <dd>
        <b/>
        <b/>
    </dd>
    <dd>
        <k>
           <b/>
           <b/>
        </k>
    </dd>
    <dd>
        <b/>
        <b/>
    </dd>
</xml_file>

Как лучше всего это сделать с помощью xslt 2.0?

Большое спасибо за твою помощь.

Изменить:

Извини. я толком не объяснила..

Мне дан список элементов, которые упорядочены по порядку в списке.

Все b и k после dd должны быть дочерними элементами предшествующего dd.

Все b после k должны быть дочерними элементами предыдущего k.


person Community    schedule 29.08.2017    source источник
comment
Является ли ваш образец XML действительно репрезентативным для вашего фактического XML? На данный момент он сформирован неправильно, так как (кроме xml_file) ни один из тегов не связан с закрывающими тегами, а это означает, что XSLT не сможет его обработать.   -  person Tim C    schedule 29.08.2017
comment
Вам необходимо объяснить логику, по которой определяется иерархия.   -  person michael.hor257k    schedule 29.08.2017
comment
Спасибо за ваши ответы. Я обновил описание моего вопроса.   -  person    schedule 29.08.2017
comment
Используйте вложенный xsl:for-each-group group-starting-with например. <xsl:for-each-group select="*" group-starting-with="dd"><xsl:copy><xsl:for-each-group select="current-group() except ." group-starting-with="k">...   -  person Martin Honnen    schedule 29.08.2017


Ответы (1)


Ты можешь использовать

<xsl:template match="xml_file">
    <xsl:copy>
        <xsl:for-each-group select="*" group-starting-with="dd">
            <xsl:copy>
                <xsl:for-each-group select="current-group() except ." group-starting-with="k">
                    <xsl:choose>
                        <xsl:when test="self::k">
                            <xsl:copy>
                                <xsl:apply-templates select="current-group() except ."/>
                            </xsl:copy>
                        </xsl:when>
                        <xsl:otherwise>
                            <xsl:apply-templates select="current-group()"/>
                        </xsl:otherwise>
                    </xsl:choose>
                </xsl:for-each-group>
            </xsl:copy>
        </xsl:for-each-group>
    </xsl:copy>
</xsl:template>

плюс шаблон преобразования личности.

person Martin Honnen    schedule 29.08.2017