XSLT がその入力から最上位 ID が 1 であることをどのように判断するのか、100% 確信が持てません (pid
対応するcid
値がない唯一の値なのか、それとも常に 1 なのか?)。それにもかかわらず、これは仕事をするはずです:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:key name="kItemsByC" match="e1" use="cid" />
<xsl:key name="kItemsByP" match="e1" use="pid" />
<xsl:template match="/">
<tree>
<xsl:call-template name="Unit">
<!-- This will be the value of the <pid> that has no <cid> references to
it (assuming there is only one top-level <pid>) -->
<xsl:with-param name="id"
select="string(/elements/e1/pid[not(key('kItemsByC', .))])" />
</xsl:call-template>
</tree>
</xsl:template>
<xsl:template match="e1" name="Unit">
<xsl:param name="id" select="cid" />
<unit id="{$id}">
<xsl:apply-templates select="key('kItemsByP', $id)" />
<data />
</unit>
</xsl:template>
</xsl:stylesheet>
これをサンプル入力で実行すると、次のようになります。
<tree>
<unit id="1">
<unit id="2">
<unit id="4">
<data />
</unit>
<data />
</unit>
<unit id="3">
<data />
</unit>
<data />
</unit>
</tree>
注:上記の XSLT には、最上位 ID を動的に見つけようとするロジックがあります。最上位ユニットの ID が常に 1 であると想定できる場合、1 つのキーと上記の XSLT の (やや) 複雑な式は省略できます。
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:key name="kItemsByP" match="e1" use="pid" />
<xsl:template match="/">
<tree>
<xsl:call-template name="Unit">
<xsl:with-param name="id" select="1" />
</xsl:call-template>
</tree>
</xsl:template>
<xsl:template match="e1" name="Unit">
<xsl:param name="id" select="cid" />
<unit id="{$id}">
<xsl:apply-templates select="key('kItemsByP', $id)" />
<data />
</unit>
</xsl:template>
</xsl:stylesheet>
サンプル入力で実行すると、要求された出力も生成されます。