Использование XSLT Apply-Templates для условного выбора узлов
предположим, у меня есть 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:Если или для каждого цикла (я придумал этот пример как более простую версию того, что я делаю, чтобы вы могли помочь мне понять, как использовать xpath в инструкции match)
вот что у меня так далеко:
<?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>
В основном я просто не уверен, как отфильтровать узлы с помощью XPath в атрибуте соответствия шаблона. Любая помощь будет здорово!
3 ответов
условие должно быть на xsl: apply-templates вместо xsl: template:
<Plays>
<xsl:apply-templates select="play[a='Will Smith']">"/>
</Plays>
в вашем решении вы преобразуете все узлы
кроме того, вы можете сохранить условие в xsl: template match, но добавить другой шаблон для
<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>
I. Вероятно, наиболее эффективное решение 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>
обратите внимание:
эффективность достигается с помощью клавиши как для всех пьес, в которых принимал участие Мелл Гибсон, так и для всех актеров, которые принимали участие в данном (название) Играй.
даже если название игры с Мэлом Гибсоном было указано более одного раза (из-за случайной ошибки, возможно...) он будет указан только один раз в результате.
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>
этот стиль:
<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>