Возможно ли это сделать с помощью XPath? Если да, то как вы могли это сделать?
И. Общее решение XSLT 1.0
Как указано в комментарии ОА:
«Цель состоит в том, чтобы производить родительские элементы раньше их потомков».
Это также известно как "топологическая сортировка сильный>"
А вот моя реализация топологической сортировки XSLT 1.0, датированная 2001 годом:
"Решение. Re: как переупорядочить узлы на основе графа зависимостей?"
А вот еще один вариант этой XSLT-топологической сортировки, «которая удерживает клики вместе» (стабильная топологическая сортировка) https://www.biglist.com/lists/lists.mulberrytech.com/xsl-list/archives/200112/msg01009.html
Что касается получения с помощью чистого XPath последовательности идентификаторов предков подразумеваемой иерархии для данного элемента, ниже приведено решение с использованием XPath 3.0 или более поздней версии.
II. Чистое решение XPath 3
Это выражение XPath 3.0 определяет встроенную (XPath 3.0) функцию, которая вычисляет путь предка элемента, переданный как внешний параметр $pCurrent:
let $pCurrent := current(),
$ancestor-path-inner := function($el as element(), $self as function(*)) as xs:string*
{
let $parent := $el/../element[id eq $el/parentId]
return
if(not(empty($parent))) then $self($parent, $self)
else ()
,
$el/parentId
},
$ancestor-path := function($el as element()) as xs:string*
{ $ancestor-path-inner($el, $ancestor-path-inner)}
return
string-join($ancestor-path($pCurrent), '-')
Проверка на основе XSLT 3.0:
<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="xs">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="element">
<element id="{id}" ancestor-path-ids=
"{let $pCurrent := current(),
$ancestor-path-inner := function($el as element(),
$self as function(*)) as xs:string*
{
let $parent := $el/../element[id eq $el/parentId]
return
if(not(empty($parent))) then $self($parent, $self)
else ()
,
$el/parentId
},
$ancestor-path := function($el as element()) as xs:string*
{ $ancestor-path-inner($el, $ancestor-path-inner)}
return
string-join($ancestor-path($pCurrent), '-')}"/>
</xsl:template>
</xsl:stylesheet>
Когда это преобразование применяется к предоставленному XML-документу:
<root>
<element>
<id>1</id>
</element>
<element>
<id>2</id>
<parentId>1</parentId>
</element>
<element>
<id>3</id>
<parentId>2</parentId>
</element>
<element>
<id>4</id>
<parentId>3</parentId>
</element>
<element>
<id>5</id>
<parentId>2</parentId>
</element>
<element>
<id>6</id>
<parentId>5</parentId>
</element>
</root>
получен желаемый правильный результат:
<element id="1" ancestor-path-ids=""/>
<element id="2" ancestor-path-ids="1"/>
<element id="3" ancestor-path-ids="1-2"/>
<element id="4" ancestor-path-ids="1-2-3"/>
<element id="5" ancestor-path-ids="1-2"/>
<element id="6" ancestor-path-ids="1-2-5"/>
person
Dimitre Novatchev
schedule
30.09.2019