因此,我最近开始在一个项目中使用XSL 1.0,需要迭代一个节点集,并为每个节点调用一个具有节点"属性"的模板
我说"属性"是因为我最终只做了一个内部标记,即我正在迭代的节点集看起来像这样:
<var>
<key>key 1 text here</key>
<value>value 1 text here</value>
</var>
....
<var>
<key>key Nth text here</key>
<value>value Nth text here</value>
</var>
尽管我可以回到<var key="keytext" value="valtext" />
之类的东西,如果有人认为这更好的话,我可以使用实际属性(事实上,这是我第一次处理这个问题的方式,但运气不佳)
无论如何,此节点集用于填充表单。用户从下拉菜单中选择项目名称,该下拉菜单将填充"计划名称"下拉菜单。一旦用户选择了计划名称,表单上就会有一个名为"构建变量"的表,该表将填充该计划的键/值配对。如果用户更改了计划名称,那么构建变量就会更改(我已经负责页面刷新和重新加载,并确保删除了旧变量),表中的行数可能会更改(每个键/值对一行)。
这是XSL的相关部分,它获取<var>
标记的节点集并将其分配给$variables
,然后使用<for-each>
对它们进行迭代,获取键/值对并将它们传递给模板"widget_render"(我不提供widget_reder代码,因为它非常冗长(超过150行),并根据传递的参数调用其他模板)。在这种特殊的情况下,所有的widget_render本质上都是创建一个文本区域框,并用键或值的内容填充它-键的框不能由用户编辑,但它为值创建的框可以是
<xsl:variable name="variables" select="bamb-class:getPlanVariables($projVal, $planVal)" />
<xsl:for-each select="$variables">
<xsl:variable name="key" select="./key" />
<xsl:variable name="value" select="./value"/>
<tr height="30">
<td class="datacell" colspan="1">
<xsl:call-template name="widget_render">
<xsl:with-param name="fieldName" select="concat('keyField[', position(), ']')"/>
<xsl:with-param name="renderCmd" select="'input'" />
<xsl:with-param name="default" select="$key" />
<xsl:with-param name="readOnly" select="'true'" />
</xsl:call-template>
</td>
<td class="datacell" colspan="1">
<xsl:call-template name="widget_render">
<xsl:with-param name="fieldName" select="concat('valueField[', position(), ']')"/>
<xsl:with-param name="renderCmd" select="'input'"/>
<xsl:with-param name="default" select="$value" />
</xsl:call-template>
</td>
</tr>
</xsl:for-each>
希望这是我正在做的事情的足够背景,所以这是有意义的。如果没有,请告诉我。
我的问题是:键和值似乎在对widget_render的调用模板中丢失了。这意味着在表中的任一<td>
标记中都没有显示带文本的输入框。
然而,我可以在适当的<td>
标签内执行<xsl:value-of select="$key" />
和<xsl:value-of select="$value" />
,它会输出正确的值(信息就在那里,只是没有传递到widget_render或其他什么中)。由于没有value-of
语句,我目前得到的只是正确的行数,但它们都是空的。
是的,我必须使用widget_render模板(不能只放在<input>
标签或其他东西中),因为软件后来会重新使用表上的widget_reder逻辑来执行其他操作。不,这不是类型冲突,也不是我传球类型错误的事情,我已经确定了。
我不知道是我错过了什么真正愚蠢的东西,还是有什么更大的东西我只是不明白,但这件事让我很困惑。
简单地说:为什么调用模板(看起来)不起作用,并且在for each循环中用键/值对填充表?即使我知道for each在正确的节点集上迭代,并且$key
和$value
在每次迭代中都有正确的赋值。
如有任何帮助,我们将不胜感激,谢谢!如果有什么不清楚的地方,或者有什么我无意中遗漏的信息需要知道,请告诉我。如果需要的话,我也可以抛出widget_render代码,但我怀疑这对任何人都没有帮助。
编辑:这里有一个链接到一个包含整个文件的dropbox:widget_render从第119行开始https://www.dropbox.com/s/zt3g9idprrca6ak/default-widgets.xml这是一个非常长的模板,它调用的所有其他模板也都在该文件中。
所以我设法找到了一个解决方案——对我来说有点像黑客,但它很有效,而且很适合我的需要。
我用这个替换了循环:
<xsl:variable name="planVariables" select="bamb-class:getPlanVariables($projVal, $planVal)"/>
<xsl:call-template name="renderAllRows">
<xsl:with-param name="i" select="1"/>
<xsl:with-param name="count" select="count($planVariables)"/>
<xsl:with-param name="planVariables" select="$planVariables"/>
</xsl:call-template>
然后调用renderAllRows,该调用递归地调用自己以模拟xsl:for-each
循环,直到表中的所有行都已渲染。
<xsl:template name="renderAllRows">
<xsl:param name="i" />
<xsl:param name="count" />
<xsl:param name="planVariables" />
<xsl:if test="$i <= $count">
<xsl:call-template name="renderRow" >
<xsl:with-param name="rowNum" select="$i"/>
<xsl:with-param name="planVariables" select="$planVariables"/>
</xsl:call-template>
</xsl:if>
<!-- recursion here -->
<xsl:if test="$i <= $count">
<xsl:call-template name="renderAllRows">
<xsl:with-param name="i" select="$i + 1"/>
<xsl:with-param name="count" select="$count"/>
<xsl:with-param name="planVariables" select="$planVariables"/>
</xsl:call-template>
</xsl:if>
</xsl:template>
<xsl:template name="renderRow">
<xsl:param name="rowNum"/>
<xsl:param name="planVariables"/>
<xsl:variable name="key" select="exsl:node-set($planVariables)[position()=$rowNum]/key"/>
<xsl:variable name="value" select="exsl:node-set($planVariables)[position()=$rowNum]/value"/>
<tr height="30">
<td class="datacell" colspan="1">
<xsl:call-template name="widget_render">
<xsl:with-param name="fieldName" select="concat('keyField[', $rowNum, ']')"/>
<xsl:with-param name="renderCmd" select="'input'" />
<xsl:with-param name="default" select="$key" />
<xsl:with-param name="readOnly" select="'true'" />
</xsl:call-template>
</td>
<td class="datacell" colspan="1">
<xsl:call-template name="widget_render">
<xsl:with-param name="fieldName" select="concat('valueField[', $rowNum, ']')"/>
<xsl:with-param name="renderCmd" select="'input'"/>
<xsl:with-param name="default" select="$value" />
</xsl:call-template>
</td>
</tr>
</xsl:template>
为了让一切正常工作,对widget_render的调用正在查看正确的上下文,创建它们应该创建的文本框并填充它们。感谢Jirka的提示,帮助我解决了这个问题。