这是一个纯 XPath 3.1 解决方案:
下面的函数$allProps () 返回一个字符串序列,这些字符串是元素的所有属性的名称,其id等于传递给函数的$id参数。
在这个示例表达式中,函数$allProps () 被调用了 3 次——每个“elem”元素调用一次,返回的属性由 NL 字符分隔:
let $root := /,
$allProps-inner := function($id as xs:integer, $self as function(*)) as xs:string*
{
let $elem := $root/*/elem[xs:integer(@id )eq $id],
$ownProperties := $elem/property/@name[not(. eq 'inherits')]/string(),
$ParentId := $elem/property[@name eq 'inherits']/@value
return
(
$ownProperties,
if(empty($ParentId)) then ()
else
$self($ParentId, $self)
)
},
$allProps := function($id as xs:integer) as xs:string*
{ $allProps-inner($id, $allProps-inner ) }
return
(
$allProps(1), '
',
$allProps(2), '
',
$allProps(3), '
'
)
基于 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">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="/">
<xsl:value-of select=
"let $root := /,
$allProps-inner := function($id as xs:integer, $self as function(*)) as xs:string*
{
let $elem := $root/*/elem[xs:integer(@id )eq $id],
$ownProperties := $elem/property/@name[not(. eq 'inherits')]/string(),
$ParentId := $elem/property[@name eq 'inherits']/@value
return
(
$ownProperties,
if(empty($ParentId)) then ()
else
$self($ParentId, $self)
)
},
$allProps := function($id as xs:integer) as xs:string*
{ $allProps-inner($id, $allProps-inner ) }
return
(
$allProps(1), '
',
$allProps(2), '
',
$allProps(3), '
'
)
"/>
</xsl:template>
</xsl:stylesheet>
当此转换应用于提供的 XML 文档时:
<elems>
<elem id="1">
<property name="a" value="alpha"/>
</elem>
<elem id="2">
<property name="inherits" value="1"/>
<property name="b" value="bravo"/>
</elem>
<elem id="3">
<property name="inherits" value="2"/>
<property name="c" value="charlie"/>
</elem>
</elems>
产生了想要的正确结果:
a
b a
c b a
最后,我们自然而然地得到了原始问题的解决方案:
因此,对具有属性 c 的元素的查询将返回 3,其反向将返回 1 和 2。对具有属性 b 的元素的查询将返回 2 和 3,其反向将返回 1。最后,对具有属性 a 的元素的调用将返回 1、2 和 3,它的反向不会返回任何东西。
我怎么做?
let $root := /,
$allProps-inner := function($id as xs:integer, $self as function(*)) as xs:string*
{
let $elem := $root/*/elem[xs:integer(@id )eq $id],
$ownProperties := $elem/property/@name[not(. eq 'inherits')]/string(),
$ParentId := $elem/property[@name eq 'inherits']/@value
return
(
$ownProperties,
if(empty($ParentId)) then ()
else
$self($ParentId, $self)
)
},
$allProps := function($id as xs:integer) as xs:string*
{ $allProps-inner($id, $allProps-inner ) }
return
(
for $name in ('a', 'b', 'c')
return
( $root/*/elem[$name = $allProps(@id) ]/@id, '
' )
)
当这个 XPath 表达式被求值时(只需用这个替换转换中的 XPath 表达式),那么输出时的结果是想要的,更正一个:
1 2 3
2 3
3