Как я могу повторить действие X раз с помощью XSLT
Я должен заполнить в общей сложности 20 элементов с помощью XSLT. В моем XML-коде у меня есть <select> со значениями, есть все равно, чтобы не писать 20 форм?
Мой 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>
Мой 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>
Желаемый результат:
<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>
4 ответов:
Сначала используйте шаблоны вместо
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>
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: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>При применении к следующему 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>Желаемый, правильный результат получается .
II. Решение XSLT 2.0 с использованием функции
f:repeat()FXSL :<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>Здесь мы используем очень общую функцию , которая будет повторять свой первый аргумент
N(значение своего второго аргумента) раз.Функция
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>
Другое решение с "вы-пойдете-в-ад-если-вы-используете-этот-паттерн":
<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>
Один из способов решить эту проблему-загрузить параметры опции в переменную с помощью функции XPath
document(), а затем использовать рекурсивный шаблон:<?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>
Comments