这是一个使用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" />
(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
这确实假设每个人不能有超过一个兄弟或姐妹等。