本周早些时候,我问了一个关于使用XSLT进行条件打印的问题,并从helderdarocha收到了一个非常有用的答案。不幸的是,事实证明我需要的答案比我原先想象的要复杂一些。按照他的指示,并使用Muenchian方法进行控制中断,我总结了一个我需要做的新例子。
这是我的XML:
<?xml version="1.0" encoding="UTF-8"?>
<group>
<person>
<datum type='medium'>Cartoon</datum>
<datum type='firstname'>Fred</datum>
<datum type='lastname'>Flintstone</datum>
</person>
<person>
<datum type='medium'>Cartoon</datum>
<datum type='firstname'>Wilma</datum>
<datum type='lastname'>Flintstone</datum>
</person>
<person>
<datum type='medium'>TV</datum>
<datum type='firstname'>Luke</datum>
<datum type='lastname'>Duke</datum>
</person>
<person>
<datum type='medium'>TV</datum>
<datum type='firstname'>Daisy</datum>
<datum type='lastname'>Duke</datum>
</person>
<person>
<datum type='medium'>Reality</datum>
<datum type='firstname'>George</datum>
<datum type='lastname'>Bush</datum>
</person>
<person>
<datum type='medium'>Reality</datum>
<datum type='firstname'>Barbara</datum>
<datum type='lastname'>Bush</datum>
</person>
</group>
这是我的XSLT:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output indent="yes"/>
<xsl:key name="medium" match="person" use="datum[@type='medium']"/>
<xsl:key name="lastname" match="person" use="//person/datum[@type='lastname']"/>
<xsl:template match="person">
<tr>
<td><xsl:value-of select="datum[@type='firstname']"/></td>
</tr>
</xsl:template>
<xsl:template match="group">
<table border="1">
<xsl:for-each select="person[count(. | key('medium', datum[@type='medium'])[1]) = 1]/datum[@type='medium']">
<xsl:sort/>
<tr bgcolor="#cccccc">
<td><xsl:value-of select="."/></td>
</tr>
<xsl:for-each select="//person[count(. | key('lastname', //person/datum[@type='lastname'])[1]) = 1]/datum[@type='lastname']">
<xsl:sort/>
<tr bgcolor="#ccffcc">
<td><xsl:value-of select="."/></td>
</tr>
<xsl:apply-templates select="//person[datum[@type='lastname'] = current()]">
<xsl:sort select="datum[@type='firstname']"/>
</xsl:apply-templates>
</xsl:for-each>
</xsl:for-each>
</table>
</xsl:template>
</xsl:stylesheet>
这是我的输出:
但这就是我正在尝试的事情:
而且,我在这里假设我的问题是这一行:<xsl:for-each select="//person[count(. | key('lastname', //person/datum[@type='lastname'])[1]) = 1]/datum[@type='lastname']">
我相信我没有正确格式化xpath,但不幸的是,我对XPath的理解仍然相对较弱......我的假设是我需要移动那个&#39; = 1&#39;检查其他地方,但不知道该怎么做。
与往常一样,任何和所有线索都表示赞赏。
答案 0 :(得分:3)
通过为&#34;媒体&#34;
定义一个键,您已经正确启动了<xsl:key name="medium" match="person" use="datum[@type='medium']" />
但对于你的&#34;多层次&#34;关键,你正在分组&#34;姓氏&#34;在每个&#34;媒体&#34;。在XSLT 1.0中,这意味着您需要使用连接键,如此
<xsl:key name="medium-lastname"
match="person"
use="concat(datum[@type='medium'], '|', datum[@type='lastname'])" />
注意'|'
分隔符可以是任何内容,只要它不出现在任何&#34;媒体&#34;或&#34;姓氏&#34;值。
所以,然后你开始通过获得独特的&#34;媒体&#34;像这样的价值
<xsl:apply-templates
select="person[generate-id() = generate-id(key('medium', datum[@type='medium'])[1])]"
mode="medium" />
我在这里使用generate-id方法,但你可以像你一样使用count方法。注意使用&#34;模式&#34;这里。因为我使用的是 xsl:apply-templates ,所以我最终会得到多个匹配 person 元素的模板,因此模式会区分它们。
用这个&#34;媒体&#34;模板,然后你会得到不同的&#34;姓氏&#34;条目,但使用类似的连接键(应用于当前组中的所有元素,由&#34; medium&#34;键访问):
<xsl:apply-templates
select="key('medium', datum[@type='medium'])
[generate-id() = generate-id(key('medium-lastname', concat(datum[@type='medium'], '|', datum[@type='lastname']))[1])]"
mode="lastname" />
最后,在&#34;姓氏&#34;模板,您将再次使用连接键获取组中的所有人元素:
<xsl:apply-templates
select="key('medium-lastname', concat(datum[@type='medium'], '|', datum[@type='lastname']))" />
试试这个XSLT
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output indent="yes"/>
<xsl:key name="medium" match="person" use="datum[@type='medium']" />
<xsl:key name="medium-lastname" match="person" use="concat(datum[@type='medium'], '|', datum[@type='lastname'])" />
<xsl:template match="group">
<table>
<xsl:apply-templates select="person[generate-id() = generate-id(key('medium', datum[@type='medium'])[1])]" mode="medium" />
</table>
</xsl:template>
<xsl:template match="person" mode="medium">
<tr class="medium">
<td><xsl:value-of select="datum[@type='medium']" /></td>
</tr>
<xsl:apply-templates select="key('medium', datum[@type='medium'])[generate-id() = generate-id(key('medium-lastname', concat(datum[@type='medium'], '|', datum[@type='lastname']))[1])]" mode="lastname" />
</xsl:template>
<xsl:template match="person" mode="lastname">
<tr class="lastname">
<td><xsl:value-of select="datum[@type='lastname']" /></td>
</tr>
<xsl:apply-templates select="key('medium-lastname', concat(datum[@type='medium'], '|', datum[@type='lastname']))" />
</xsl:template>
<xsl:template match="person">
<tr>
<td><xsl:value-of select="datum[@type='firstname']" /></td>
</tr>
</xsl:template>
</xsl:stylesheet>
应用于此XML
<group>
<person>
<datum type="medium">Cartoon</datum>
<datum type="firstname">Fred</datum>
<datum type="lastname">Flintstone</datum>
</person>
<person>
<datum type="medium">Cartoon</datum>
<datum type="firstname">Wilma</datum>
<datum type="lastname">Flintstone</datum>
</person>
<person>
<datum type="medium">Cartoon</datum>
<datum type="firstname">Barney</datum>
<datum type="lastname">Rubble</datum>
</person>
<person>
<datum type="medium">TV</datum>
<datum type="firstname">Daisy</datum>
<datum type="lastname">Duke</datum>
</person>
<person>
<datum type="medium">TV</datum>
<datum type="firstname">George</datum>
<datum type="lastname">Bush</datum>
</person>
</group>
然后输出以下内容
<table>
<tr class="medium">
<td>Cartoon</td>
</tr>
<tr class="lastname">
<td>Flintstone</td>
</tr>
<tr>
<td>Fred</td>
</tr>
<tr>
<td>Wilma</td>
</tr>
<tr class="lastname">
<td>Rubble</td>
</tr>
<tr>
<td>Barney</td>
</tr>
<tr class="medium">
<td>TV</td>
</tr>
<tr class="lastname">
<td>Duke</td>
</tr>
<tr>
<td>Daisy</td>
</tr>
<tr class="lastname">
<td>Bush</td>
</tr>
<tr>
<td>George</td>
</tr>
</table>
答案 1 :(得分:2)
这里的关键是使用<xsl:for-each-group>
按媒介分组,然后按姓氏分组。以下应该有效。你可以在这里看到它:http://xsltransform.net/eiZQaEM/3
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output indent="yes"/>
<xsl:template match="/">
<table border="1">
<xsl:for-each-group select="/group/person" group-by="datum[@type='medium']">
<tr bgcolor="#cccccc"><td><xsl:value-of select="current-grouping-key()"/></td></tr>
<xsl:for-each-group select="current-group()" group-by="datum[@type='lastname']">
<tr bgcolor="#ccffcc"><td><xsl:value-of select="current-grouping-key()"/></td></tr>
<xsl:for-each select="current-group()">
<tr><td><xsl:value-of select="./datum[@type='firstname']"/></td></tr>
</xsl:for-each>
</xsl:for-each-group>
</xsl:for-each-group>
</table>
</xsl:template>
</xsl:transform>