a
とb
が最上位要素の子であると仮定して、 を使用します。
for $href in /*/a/@href,
$b in /*/b[@id = $href and not(. = preceding-sibling::b)]
return
string($href)
XSLT-2 ベースの検証:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:template match="/">
<xsl:sequence select=
"for $href in /*/a/@href,
$b in /*/b[@id = $href and not(. = preceding-sibling::b)]
return
string($href)
"/>
</xsl:template>
</xsl:stylesheet>
この変換が提供された XML ドキュメントに適用されると、次のようになります。
<html>
<a href="h1" />
<a href="h2" />
<a href="h3" />
<b id="h1">E1</b>
<b id="h2">E1</b>
<b id="h3">E2</b>
</html>
XPath 式が評価され、この評価の結果が出力にコピーされます。
h1 h3
更新:
Michael Kay が指摘しているように、上記の解は O(N^2) であり、b
兄弟が多い場合は遅くなる可能性があります。
以下は、少なくとも線形 (またはより高速) な XSLT 2.0 ソリューションです。
<xsl:stylesheet version="2.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:key name="kReferrer" match="b" use="@id"/>
<xsl:template match="/*">
<xsl:for-each-group select="key('kReferrer', a/@href)" group-by=".">
<xsl:sequence select="string(@id)"/>
</xsl:for-each-group>
</xsl:template>
</xsl:stylesheet>
繰り返しますが、この変換を同じ XML ドキュメント (上記) に適用すると、必要な正しい結果が生成されます。
h1 h3