xml 如何使用 XSLT 重复操作 X 次
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3802235/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How I can repeat an action X times with XSLT
提问by ipalaus
I've to populate a total of 20 elements with XSLT. In my XML code I have a <select>with the values, there is anyway to not to write 20 forms?
我必须用 XSLT 填充总共 20 个元素。在我的 XML 代码中我有一个<select>带值的,有没有办法不写 20 个表单?
My XML:
我的 XML:
<output>
<select>
<id>1</id>
<name>One</name>
</select>
<select>
<id>2</id>
<name>Two</name>
</select>
<select>
<id>3</id>
<name>Three</name>
</select>
<!-- An more -->
</output>
My XSLT:
我的 XSLT:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<html>
<body>
<select name="values[]">
<option value="0"> </option>
<xsl:for-each select="output/select">
<option>
<xsl:attribute name="value"><xsl:value-of select="id"></xsl:attribute>
<xsl:value-of select="name" />
</option>
</xsl:for-each>
</select>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
Desired output:
期望的输出:
<html>
<body>
<select name="values[]">
<option value="0"> </option>
<option value="1">One</option>
<option value="2">Two</option>
<option value="3">Three</option>
</select>
<!-- But 20 times -->
</body>
</html>
采纳答案by Oded
First, use templates instead of for-each, then you can use a recursive template call to emulate a for loop (as seen here):
首先,使用模板来代替for-each,那么你可以使用一个递归调用模板来模拟一个for循环(如看到这里):
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<html>
<body>
<xsl:call-template name="selects">
<xsl:with-param name="i">1</xsl:with-param>
<xsl:with-param name="count">20</xsl:with-param>
</xsl:call-template>
</body>
</html>
</xsl:template>
<xsl:template name="selects">
<xsl:param name="i" />
<xsl:param name="count" />
<xsl:if test="$i <= $count">
<select name="values[]">
<xsl:apply-template select="output/select" />
</select>
</xsl:if>
<!--begin_: RepeatTheLoopUntilFinished-->
<xsl:if test="$i <= $count">
<xsl:call-template name="selects">
<xsl:with-param name="i">
<xsl:value-of select="$i + 1"/>
</xsl:with-param>
<xsl:with-param name="count">
<xsl:value-of select="$count"/>
</xsl:with-param>
</xsl:call-template>
</xsl:if>
</xsl:template>
<xsl:template match="output/select">
<option>
<xsl:attribute name="value">
<xsl:value-of select="id">
</xsl:attribute>
<xsl:value-of select="name" />
</option>
</xsl:template>
</xsl:stylesheet>
回答by Dimitre Novatchev
I. XSLT 1.0 solution:
一、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:template match="/">
<html>
<body>
<xsl:apply-templates select="*" mode="iter">
<xsl:with-param name="pCount" select="20"/>
</xsl:apply-templates>
</body>
</html>
</xsl:template>
<xsl:template match="/*" mode="iter">
<xsl:param name="pCount" select="0"/>
<xsl:if test="$pCount > 0">
<select name="values[]">
<xsl:apply-templates/>
</select>
<xsl:apply-templates select="." mode="iter">
<xsl:with-param name="pCount" select="$pCount -1"/>
</xsl:apply-templates>
</xsl:if>
</xsl:template>
<xsl:template match="select">
<option value="{id}"><xsl:value-of select="name"/></option>
</xsl:template>
</xsl:stylesheet>
This is a specific, recursive solution.
这是一个特定的递归解决方案。
When applied to the following XML document:
当应用于以下 XML 文档时:
<output>
<select>
<id>0</id>
<name> </name>
</select>
<select>
<id>1</id>
<name>One</name>
</select>
<select>
<id>2</id>
<name>Two</name>
</select>
<select>
<id>3</id>
<name>Three</name>
</select>
</output>
the wanted, correct result is produced.
产生了想要的、正确的结果。
II. XSLT 2.0 solution using the f:repeat()function of FXSL:
二、使用f:repeat()FXSL功能的XSLT 2.0解决方案:
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:f="http://fxsl.sf.net/"
exclude-result-prefixes="f xs"
>
<xsl:import href="../f/func-repeat.xsl"/>
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:variable name="vSelects" as="element()">
<select name="values[]">
<xsl:apply-templates select="/*/select"/>
</select>
</xsl:variable>
<xsl:template match="/">
<html>
<body>
<xsl:sequence select="f:repeat($vSelects, 20)"/>
</body>
</html>
</xsl:template>
<xsl:template match="select">
<option value="{id}"><xsl:value-of select="name"/></option>
</xsl:template>
</xsl:stylesheet>
Here we use a very generic functionthat will repeat its first argument N(the value of its second argument) times.
这里我们使用一个非常通用的函数,它将重复它的第一个参数N(它的第二个参数的值)次。
The function f:repeat()itself is very simple:
函数f:repeat()本身非常简单:
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:f="http://fxsl.sf.net/"
exclude-result-prefixes="xs f"
>
<xsl:function name="f:repeat" as="item()+">
<xsl:param name="pThis" as="item()"/>
<xsl:param name="pTimes" as="xs:integer"/>
<xsl:for-each select="1 to $pTimes">
<xsl:sequence select="$pThis"/>
</xsl:for-each>
</xsl:function>
</xsl:stylesheet>
回答by Dimitre Novatchev
Other solution with "you-will-go-to-hell-if-you-use-this-pattern":
“如果你使用这个模式,你会下地狱”的其他解决方案:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<xsl:variable name="vChilds" select="node()"/>
<xsl:variable name="vStylesheet" select="document('')"/>
<html>
<body>
<xsl:for-each select="($vStylesheet//node()|
$vStylesheet//@*|
$vStylesheet//namespace::*)
[21 > position()]">
<xsl:apply-templates select="$vChilds"/>
</xsl:for-each>
</body>
</html>
</xsl:template>
<xsl:template match="output">
<select name="values[]">
<option value="0"></option>
<xsl:apply-templates/>
</select>
</xsl:template>
<xsl:template match="select">
<option value="{id}">
<xsl:value-of select="name"/>
</option>
</xsl:template>
</xsl:stylesheet>
回答by Dirk Vollmar
One way to solve this is by loading the option settings into a variable using the XPath document()function and then using a recursive template:
解决此问题的一种方法是使用 XPathdocument()函数将选项设置加载到变量中,然后使用递归模板:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:variable name="options" select="document('options.xml')" />
<xsl:template match="/">
<html>
<body>
<xsl:call-template name="InsertOptions">
<xsl:with-param name="count" select="20" />
</xsl:call-template>
</body>
</html>
</xsl:template>
<xsl:template name="InsertOptions">
<xsl:param name="index" select="1"/>
<xsl:param name="count" select="1"/>
<xsl:if test="$index <= $count">
<select name="{concat('values', count, '[]')}">
<option value="0"> </option>
<xsl:for-each select="$options/output/select">
<option value="{id}"><xsl:value-of select="name" /></option>
</xsl:for-each>
</select>
<xsl:call-template name="InsertOptions">
<xsl:with-param name="index" select="$index + 1" />
<xsl:with-param name="count" select="$count" />
</xsl:call-template>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
回答by árpád Magosányi
If you have an xml structure with at least $n elements (even nested) in $structure:
如果您的 xml 结构在 $structure 中至少包含 $n 个元素(甚至嵌套):
<xsl:for-each select="$structure//*[position() < $n]">
<!-- do whatever you want -->
</xsl:for-each>
Yes, it is hackish, but conceptually easier than a recursive function.
是的,它是hackish,但在概念上比递归函数更容易。

