在XSLT中,我想调用一个模板,并将一些内容传递给模板。但是,内容应按照视频的排序方式(13-41-61)排序,而不是按照内容排序的顺序排序(61-41-13)。
我有以下XML:
<videos>
<video key="13" />
<video key="41" />
<video key="61" />
</videos>
<contents>
<content key="61" />
<content key="41" />
<content key="13" />
<content key="10" />
</contents>
XSLT:
<xsl:call-template name="video">
<xsl:with-param name="content" select="contents/content[@key = videos/video/@key]" />
</xsl:call-template>
有没有办法轻松实现这一目标?
答案 0 :(得分:1)
此转换似乎是当前发布的解决方案中效率最高的 - 没有count(preceding-sibling::*)
,没有//content[@key=$key]
- 两者都导致O(N ^ 2) - 二次时间复杂度:
<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="kContByAtttr" match="content" use="@key"/>
<xsl:key name="kVidByAtttr" match="video" use="@key"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="contents">
<contents>
<xsl:for-each select="/*/videos/video">
<xsl:apply-templates select="key('kContByAtttr', @key)"/>
</xsl:for-each>
<xsl:apply-templates select="*[not(key('kVidByAtttr', @key))]"/>
</contents>
</xsl:template>
</xsl:stylesheet>
当应用于提供的XML(包装成单个顶部元素以成为)文档时:
<t>
<videos>
<video key="13" />
<video key="41" />
<video key="61" />
</videos>
<contents>
<content key="61" />
<content key="41" />
<content key="13" />
<content key="10" />
</contents>
</t>
生成想要的正确结果:
<t>
<videos>
<video key="13"/>
<video key="41"/>
<video key="61"/>
</videos>
<contents>
<content key="13"/>
<content key="41"/>
<content key="61"/>
<content key="10"/>
</contents>
</t>
答案 1 :(得分:0)
复制并粘贴我经常使用的一段代码,它应该可以正常工作
<xsl:template match="/">
<contents>
<xsl:for-each select="//video">
<xsl:call-template name="sortedId">
<xsl:with-param name="key" select="@key"></xsl:with-param>
</xsl:call-template>
</xsl:for-each>
</contents>
</xsl:template>
<xsl:template name="sortedId" >
<xsl:param name="key"></xsl:param>
<xsl:apply-templates select="//content[@key=$key]" />
</xsl:template>
<xsl:template match="content">
<xsl:copy-of select="." />
</xsl:template>
结果是:
<contents>
<content key="13" />
<content key="41" />
<content key="61" />
</contents>
答案 2 :(得分:0)
您需要使用<xsl:call-template>
的具体原因吗?如果您只想按<content>
元素所在的顺序对<video>
元素进行排序,则可以执行以下操作:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="utf-8" indent="yes"
omit-xml-declaration="yes"/>
<xsl:strip-space elements="*"/>
<!--
Index <video> elements according to their position in the tree.
See http://stackoverflow.com/a/5876074/825783
-->
<xsl:key name="kVideo" match="video"
use="count(preceding-sibling::video) + 1"/>
<!-- Identity transform -->
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="content">
<xsl:copy>
<!--
Apply attributes (fallback to account for the extra <content> element)
-->
<xsl:apply-templates select="@*"/>
<!--
Apply the @key attribute of the <video> element that's in a
position corresponding to the position of this <content> element
-->
<xsl:apply-templates select="key('kVideo', position())/@key"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
<root>
<videos>
<video key="13"/>
<video key="41"/>
<video key="61"/>
</videos>
<contents>
<content key="61"/>
<content key="41"/>
<content key="13"/>
<content key="10"/>
</contents>
</root>
<root>
<videos>
<video key="13"/>
<video key="41"/>
<video key="61"/>
</videos>
<contents>
<content key="13"/>
<content key="41"/>
<content key="61"/>
<content key="10"/>
</contents>
</root>