Преобразование плоского xml в древовидную иерархию на основе идентификаторов внутренних элементов

#xml #xslt

Вопрос:

Мой исходный XML-файл состоит из неупорядоченного плоского списка каталогов, содержащего элемент, каждый из которых имеет свой собственный идентификатор, и дочерний идентификатор, если он у них есть.

Мой исходный XML выглядит следующим образом:

 lt;rootgt;  lt;cataloguegt;  lt;itemgt;  lt;idgt;item2lt;/idgt;  lt;childgt;  lt;idgt;item3lt;/idgt;  lt;/childgt;  lt;/itemgt; lt;/cataloguegt;  lt;cataloguegt;  lt;itemgt;  lt;idgt;item1lt;/idgt;  lt;childgt;  lt;idgt;item2lt;/idgt;  lt;/childgt;  lt;/itemgt; lt;/cataloguegt;  lt;cataloguegt;  lt;itemgt;  lt;idgt;item3lt;/idgt;  lt;/itemgt; lt;/cataloguegt;  lt;/rootgt;  

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

Мой результирующий XML-файл должен выглядеть следующим образом:

 lt;rootgt;  lt;cataloguegt;  lt;itemgt;  lt;idgt;item1lt;/idgt;  lt;childgt;  lt;idgt;item2lt;/idgt;  lt;/childgt;  lt;/itemgt;  lt;cataloguegt;  lt;itemgt;  lt;idgt;item2lt;/idgt;  lt;childgt;  lt;idgt;item3lt;/idgt;  lt;/childgt;  lt;/itemgt;  lt;cataloguegt;  lt;itemgt;  lt;idgt;item3lt;/idgt;  lt;/itemgt;  lt;/cataloguegt;  lt;/cataloguegt; lt;/cataloguegt;  lt;/rootgt;  

Я несколько приблизился к решению, но не могу заставить полученный XML-файл не содержать ненужных повторяющихся элементов.

In the following XML file, the top and bottom catalogues inside the root are duplicate unwanted entries. I need only the large, middle catalogue.

My current result XML looks like this:

 lt;rootgt;  lt;cataloguegt;  lt;itemgt;  lt;idgt;item2lt;/idgt;  lt;childgt;  lt;idgt;item3lt;/idgt;  lt;/childgt;  lt;/itemgt;  lt;cataloguegt;  lt;itemgt;  lt;idgt;item3lt;/idgt;  lt;/itemgt;  lt;/cataloguegt; lt;/cataloguegt;  lt;cataloguegt;  lt;itemgt;  lt;idgt;item1lt;/idgt;  lt;childgt;  lt;idgt;item2lt;/idgt;  lt;/childgt;  lt;/itemgt;  lt;cataloguegt;  lt;itemgt;  lt;idgt;item2lt;/idgt;  lt;childgt;  lt;idgt;item3lt;/idgt;  lt;/childgt;  lt;/itemgt;  lt;cataloguegt;  lt;itemgt;  lt;idgt;item3lt;/idgt;  lt;/itemgt;  lt;/cataloguegt;  lt;/cataloguegt; lt;/cataloguegt;  lt;cataloguegt;  lt;itemgt;  lt;idgt;item3lt;/idgt;  lt;/itemgt; lt;/cataloguegt;  lt;/rootgt;  

Мой текущий результат XML создается с помощью этого файла XSLT:

 lt;xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"gt;  lt;xsl:template match="catalogue"gt;  lt;xsl:copygt;  lt;xsl:apply-templates select="node() | @*"/gt;  lt;xsl:for-each select="/root/catalogue[item/id/text() = current()/item/child/id/text()]"gt;  lt;xsl:apply-templates select="."/gt;  lt;/xsl:for-eachgt;  lt;/xsl:copygt; lt;/xsl:templategt;  lt;xsl:template match="node() | @*"gt;  lt;xsl:copygt;  lt;xsl:apply-templates select="node() | @*"/gt;  lt;/xsl:copygt; lt;/xsl:templategt;  lt;/xsl:stylesheetgt;  

Я слишком долго пытался найти решение этой проблемы, поэтому надеюсь, что кто-нибудь сможет мне помочь.

Ответ №1:

Может быть, вот так:

XSLT 1.0

 lt;xsl:stylesheet version="1.0"  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"gt; lt;xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/gt; lt;xsl:strip-space elements="*"/gt;  lt;xsl:key name="cat" match="catalogue" use="item/id" /gt;  lt;xsl:template match="/root"gt;  lt;xsl:copygt;  lt;!-- start with items that are not children of any item --gt;  lt;xsl:apply-templates select="catalogue[not(item/id = //child/id)]"/gt;  lt;/xsl:copygt; lt;/xsl:templategt;  lt;xsl:template match="catalogue"gt;  lt;xsl:copygt;  lt;xsl:copy-of select="item"/gt;  lt;!-- recurse with current item's children --gt;  lt;xsl:apply-templates select="key('cat', item/child/id)"/gt;  lt;/xsl:copygt; lt;/xsl:templategt;  lt;/xsl:stylesheetgt;