假设我有一个像这样的xml文档:
<director>
<play>
<t>Nutcracker</t>
<a>Tom Cruise</a>
</play>
<play>
<t>Nutcracker</t>
<a>Robin Williams</a>
</play>
<play>
<t>Grinch Stole Christmas</t>
<a>Will Smith</a>
</play>
<play>
<t>Grinch Stole Christmas</t>
<a>Mel Gibson</a>
</play>
</director>
现在我希望能够选择威尔·史密斯作为演员的所有戏剧并将其重新格式化为以下内容:
<Plays>
<Play title="Grinch Stole Christmas">
<star>Will Smith</star>
<star>Mel Gibson</star>
</Play>
</Plays>
我只想使用apply-templates ..没有xsl:if或者每个循环(我把这个例子设想为我正在做的更简单的版本,所以你可以帮我理解如何在匹配中使用xpath语句)
这是我到目前为止所做的:
<?xml version="1.0"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes" />
<xsl:template match="/director">
<Plays>
<xsl:apply-templates select="play"/>
</Plays>
</xsl:template>
<xsl:template match="play[a='Will Smith']">
<play title="{data(t)[1]}">
<xsl:apply-templates select="a"/>
</play>
</xsl:template>
<xsl:template match="a">
<star>
<xsl:value-of select="."/>
</star>
</xsl:template>
</xsl:stylesheet>
基本上我只是不确定如何在模板的match属性中使用XPath过滤掉节点。任何帮助都会很棒!
答案 0 :(得分:9)
条件应该是xsl:apply-templates而不是xsl:template:
<Plays>
<xsl:apply-templates select="play[a='Will Smith']">"/>
</Plays>
在您的解决方案中,您正在改变所有&lt; play&gt;节点。 对于与条件匹配的播放节点,将应用您的模板。但对于那些与条件不匹配的人,则应用默认模板(“身份变换”)。
或者,您可以将条件保持在xsl:template match,但为&lt; play&gt;添加另一个模板与条件不匹配,转换那些&lt; play&gt;什么都没有:
<xsl:template match="play[a='Will Smith']">
<play title="{data(t)[1]}">
<xsl:apply-templates select="a"/>
</play>
</xsl:template>
<xsl:template match="play">
</xsl:template>
答案 1 :(得分:5)
<强>予。可能是效率最高的XSLT 1.0解决方案:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:key name="kWSPlayByTitle" match="play[a='Will Smith']"
use="t"/>
<xsl:key name="kActorByTitle" match="a"
use="../t"/>
<xsl:template match="/">
<Plays>
<xsl:apply-templates select=
"*/play[generate-id()
=
generate-id(key('kWSPlayByTitle',t)[1])
]"/>
</Plays>
</xsl:template>
<xsl:template match="play">
<Play title="{t}">
<xsl:apply-templates select="key('kActorByTitle',t)"/>
</Play>
</xsl:template>
<xsl:template match="a">
<star><xsl:value-of select="."/></star>
</xsl:template>
</xsl:stylesheet>
将此转换应用于提供的XML文档:
<director>
<play>
<t>Nutcracker</t>
<a>Tom Cruise</a>
</play>
<play>
<t>Nutcracker</t>
<a>Robin Williams</a>
</play>
<play>
<t>Grinch Stole Christmas</t>
<a>Will Smith</a>
</play>
<play>
<t>Grinch Stole Christmas</t>
<a>Mel Gibson</a>
</play>
</director>
生成了想要的结果:
<Plays>
<Play title="Grinch Stole Christmas">
<star>Will Smith</star>
<star>Mel Gibson</star>
</Play>
</Plays>
请注意:
通过使用按键来实现效率,对于Mell Gibson参与的所有游戏以及参与某个(标题)游戏的所有演员都可以。
即使梅尔吉布森的比赛名称被多次列出(由于意外错误,也许......),结果中只会列出一次。
<强> II。一个简单而有效的XSLT 2.0解决方案:
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="/*">
<Plays>
<xsl:for-each-group select="play[a='Mel Gibson']"
group-by="t">
<xsl:apply-templates select="."/>
</xsl:for-each-group>
</Plays>
</xsl:template>
<xsl:template match="play">
<Play title="{t}">
<xsl:for-each-group select="../play[t = current()/t]/a"
group-by=".">
<xsl:apply-templates select="."/>
</xsl:for-each-group>
</Play>
</xsl:template>
<xsl:template match="a">
<star>
<xsl:value-of select="."/>
</star>
</xsl:template>
</xsl:stylesheet>
答案 2 :(得分:1)
此样式表:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:key name="kActorByTitle" match="a" use="../t"/>
<xsl:param name="pActor" select="'Will Smith'"/>
<xsl:template match="/">
<Plays>
<xsl:apply-templates select="*/play[a=$pActor]"/>
</Plays>
</xsl:template>
<xsl:template match="play">
<Play title="{t}">
<xsl:apply-templates select="key('kActorByTitle',t)"/>
</Play>
</xsl:template>
<xsl:template match="a">
<star>
<xsl:value-of select="."/>
</star>
</xsl:template>
</xsl:stylesheet>
输出:
<Plays>
<Play title="Grinch Stole Christmas">
<star>Will Smith</star>
<star>Mel Gibson</star>
</Play>
</Plays>