Вероятно, существует простой способ сделать это с помощью XSLT2.0, но я предположил, что здесь XSLT1.0.
Единственное, что не нужно делать, это то, что ваш XML не является строго допустимым, поскольку в нем отсутствует кореньэлемент.Для целей ответа я предположил, что корневой элемент называется elements
. Для этого, я думаю, вам нужна функция для определения «уровня» элемента.Это можно сделать, посчитав количество полных остановок в атрибуте @lp.В XSLT1.0 я сделал это, удалив из текста все точки остановки и сравнив длину полученной строки с длиной исходной строки
<xsl:variable name="level" select="string-length(@lp) - string-length(translate(@lp, '.', ''))" />
Таким образом, чтобы соответствовать элементам верхнего уровня, вы бы это сделали...
<xsl:apply-templates
select="element[string-length(@lp) - string-length(translate(@lp, '.', '')) = 0]"/>
Это будет соответствовать следующим элементам
<element lp="1."/>
<element lp="2."/>
<element lp="3."/>
Далее, для каждого соответствующего элемента это случай соответствия следующих элементов, где
- Атрибут @lp начинается с текущего атрибута @lp
- Уровень на один больше, чем текущий уровень
Это можно сделать с помощью следующего выбора
<xsl:apply-templates
select="following-sibling::element[substring(@lp, 1, $len) = $lp][string-length(@lp) - string-length(translate(@lp, '.', '')) = $level + 1]"/>
(Примечание: $ len и $ level - это переменные, содержащие длину текущего атрибута @lp и текущий уровень)
Если задать это значение в целом, получится следующий XSLT ....
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/elements">
<elements>
<xsl:apply-templates select="element[string-length(@lp) - string-length(translate(@lp, '.', '')) = 0]"/>
</elements>
</xsl:template>
<xsl:template match="element">
<xsl:variable name="lp" select="@lp"/>
<xsl:variable name="len" select="string-length(@lp)"/>
<xsl:variable name="level" select="$len - string-length(translate(@lp, '.', ''))" />
<xsl:copy>
<xsl:copy-of select="@lp"/>
<xsl:apply-templates select="following-sibling::element[substring(@lp, 1, $len) = $lp][string-length(@lp) - string-length(translate(@lp, '.', '')) = $level + 1]"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
При применении к следующему XML
<elements>
<element lp="1"/>
<element lp="1.1"/>
<element lp="2"/>
<element lp="3"/>
<element lp="3.1"/>
<element lp="3.2"/>
<element lp="3.2.1"/>
</elements>
Создает следующий вывод
<elements>
<element lp="1">
<element lp="1.1"/>
</element>
<element lp="2"/>
<element lp="3">
<element lp="3.1"/>
<element lp="3.2">
<element lp="3.2.1"/>
</element>
</element>
</elements>