これは通常、問題を解決する最も効率的な方法であるxsl:keyを利用する XSLT1.0 ソリューションです (Martin に感謝します!) 。基本的にTypeでグループ化しようとしているので、異なるファミリーメンバーのタイプを取得するには、次のようにキーを定義できます
<xsl:key name="Type" match="Type" use="." />
次に、ヘッダー行について、実際に個別のタイプを取得するために、すべてのタイプを反復しますが、指定された値のキーで最初に出現するレコードのみを選択します
<xsl:apply-templates
select="//Type[generate-id() = generate-id(key('Type', .)[1])]"
mode="header" />
(ヘッダーのモードは、Type レコードがすぐに家族の別の場所で照合されるため、一致するテンプレートを区別する必要があるためです)
次に、各Personレコードを選択し、そのようなレコードごとに個別のタイプを再度選択しますが、今回は現在のPersonレコードをパラメーターとして渡して、関連する家族を抽出できるようにします。
<xsl:apply-templates
select="//Type[generate-id() = generate-id(key('Type', .)[1])]"
mode="family">
<xsl:with-param name="Person" select="." />
</xsl:apply-templates>
そして、これに一致するテンプレート(ファミリーのモードを使用)で、タイプの関連するファミリーメンバーを出力できます
ここに完全な XSLT があります
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:key name="Type" match="Type" use="." />
<xsl:template match="/*">
<xsl:text>Name</xsl:text>
<xsl:apply-templates select="//Type[generate-id() = generate-id(key('Type', .)[1])]" mode="header" />
<xsl:text> </xsl:text>
<xsl:apply-templates select="Person" />
</xsl:template>
<xsl:template match="Person">
<xsl:value-of select="Name" />
<xsl:apply-templates select="//Type[generate-id() = generate-id(key('Type', .)[1])]" mode="family">
<xsl:with-param name="Person" select="." />
</xsl:apply-templates>
<xsl:text> </xsl:text>
</xsl:template>
<xsl:template match="Type" mode="header">
<xsl:text>;</xsl:text>
<xsl:value-of select="." />
</xsl:template>
<xsl:template match="Type" mode="family">
<xsl:param name="Person" />
<xsl:text>;</xsl:text>
<xsl:value-of select="$Person/FamilyMembers/FamilyMember[Type=current()]/Name" />
</xsl:template>
</xsl:stylesheet>
XML に適用すると (単一のルート要素を想定)、以下が出力されます。
Name;Sister;Brother;Father
John;Lisa;Tom;
Daniel;;;Peter
これは、Person ごとに複数の兄弟や姉妹などを持つことができないことを前提としています。