我有xml文件:
<root>
<directors>
<director>
<name></name>
<country></country>
</director>
(...)
<director>
<name></name>
<country></country>
</director>
</directors>
<movies>
<movie>
<country><country>
</movie>
(...)
<movie>
<country></country>
</movie>
</movies>
</root>
在我的XSL转换中,我想创建包含按国家/地区分组的movie
和director
元素的XML文件。我设法提取每个不同的国家:
<xsl:template name="countries">
<xsl:for-each
select="distinct-values(/root/directors/director/country | /root/movies/movie/country)">
<xsl:element name="country">
<xsl:element name="name">
<xsl:value-of select="." />
</xsl:element>
</xsl:element>
</xsl:for-each>
</<xsl:template>
我现在要做的是在<movies>
内创建元素<directors>
和<country>
,其中包含子元素与父国匹配的元素:
<country>
<name>UK</name>
<movies> [movies having element country="UK"] </movies>
<directors> [as above] </directors>
</country>
我试图使用当前国家/地区名称作为模板内的参数调用模板,但它不起作用。
<xsl:template name="countries">
<xsl:for-each
select="distinct-values(/root/directors/director/country | /root/movies/movie/country)">
<xsl:element name="country">
<xsl:element name="name">
<xsl:value-of select="." />
</xsl:element>
<xsl:element name="movies">
<xsl:call-template name="movie">
<xsl:with-param name="country" />
</xsl:call-template>
</xsl:element>
</xsl:element>
</xsl:for-each>
</<xsl:template>
<xsl:template name="movie">
<xsl:param name="country" />
<xsl:for-each select="/root/movies/movie">
<xsl:if test="country=$country">
<!--TODO-->
</xsl:if>
</xsl:for-each>
</xsl:template>
看看我的“解决方案”的复杂程度,我假设我试图以错误的方式做到这一点。如何获取<country>
循环迭代指定的for-each
元素的元素?我想分别为电影和导演做这件事。
答案 0 :(得分:1)
至少,您需要为模板参数赋值:
<xsl:call-template name="movie">
<xsl:with-param name="country" select="." />
</xsl:call-template>
或者,您可以使用XPath谓词表达式来获取movie
个孩子等于当前country
次迭代的country
的{{1}}元素:
xsl:for-each
答案 1 :(得分:1)
您可以使用xsl:for-each-group
进行分组,而不是使用参数调用模板。 (我想如果distinct-values()
对你有用,你必须使用XSLT 2.0。)
XML输入(添加了一些用于测试的值)
<root>
<directors>
<director>
<name>Mr. A</name>
<country>UK</country>
</director>
<director>
<name>Mrs. B</name>
<country>US</country>
</director>
</directors>
<movies>
<movie>
<country>US</country>
</movie>
<movie>
<country>UK</country>
</movie>
</movies>
</root>
XSLT 2.0
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/root">
<xsl:copy>
<xsl:for-each-group select="*/director|*/movie" group-by="country">
<country>
<name><xsl:value-of select="current-grouping-key()"/></name>
<directors>
<xsl:apply-templates select="current-group()[self::director]"/>
</directors>
<movies>
<xsl:apply-templates select="current-group()[self::movie]"/>
</movies>
</country>
</xsl:for-each-group>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
XML输出
<root>
<country>
<name>UK</name>
<directors>
<director>
<name>Mr. A</name>
<country>UK</country>
</director>
</directors>
<movies>
<movie>
<country>UK</country>
</movie>
</movies>
</country>
<country>
<name>US</name>
<directors>
<director>
<name>Mrs. B</name>
<country>US</country>
</director>
</directors>
<movies>
<movie>
<country>US</country>
</movie>
</movies>
</country>
</root>
这应该很容易扩展。例如,如果您要从country
和director
中删除movie
元素,则只需添加一个模板(<xsl:template match="country"/>
)。
答案 2 :(得分:0)
这是一个纯XSLT 1.0解决方案(也可以使用XSLT 2.0处理器正确运行),这是迄今为止最短的。它也与使用$('.go-btn').click(function() {
window.location = $('#my-dropdown').val();
});
<xsl:for-each-group>
请注意其他成就:如果某个国家/地区没有任何导演或任何电影,则不会生成空的<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="kCountryByVal" match="country" use="."/>
<xsl:key name="kDirMovieByCountry" match="director|movie" use="concat(country, name())"/>
<xsl:template match="country[generate-id() = generate-id(key('kCountryByVal',.)[1])]">
<xsl:copy>
<name><xsl:value-of select="."/></name>
<xsl:apply-templates select="key('kDirMovieByCountry',concat(.,'director'))[1]
| key('kDirMovieByCountry',concat(.,'movie'))[1]" mode="do"/>
</xsl:copy>
</xsl:template>
<xsl:template match="director|movie" mode="do">
<xsl:element name="{name()}s">
<xsl:copy-of select="key('kDirMovieByCountry',concat(country,name()))"/>
</xsl:element>
</xsl:template>
<xsl:template match="text()"/>
</xsl:stylesheet>
或<directors/>
元素。
将此转换应用于以下XML文档:
<movies/>
产生了想要的正确结果:
<root>
<directors>
<director>
<name>James Cameron</name>
<country>CA</country>
</director>
<director>
<name>Steven Spielberg</name>
<country>US</country>
</director>
</directors>
<movies>
<movie>
<name>Titanic</name>
<country>US</country>
</movie>
<movie>
<name>E.T. the Extra-Terrestrial</name>
<country>US</country>
</movie>
</movies>
</root>
关键概念:
<强> Muenchian grouping 强>
XSLT处理模型, templates , built-in templates , modes
<country>
<name>CA</name>
<directors>
<director>
<name>James Cameron</name>
<country>CA</country>
</director>
</directors>
</country>
<country>
<name>US</name>
<directors>
<director>
<name>Steven Spielberg</name>
<country>US</country>
</director>
</directors>
<movies>
<movie>
<name>Titanic</name>
<country>US</country>
</movie>
<movie>
<name>E.T. the Extra-Terrestrial</name>
<country>US</country>
</movie>
</movies>
</country>
指令,“推送 -style”,多态,避免<xsl:apply-templates>
AVT <xsl:call-templates>