【问题标题】:Why this XSL template renders / generate 2 times?为什么这个 XSL 模板渲染/生成 2 次?
【发布时间】:2018-04-26 14:32:24
【问题描述】:

我今天开始了我的第一次 xsl 冒险,希望能快速完成这个“简单”的脚本。 现在 4 小时后我仍然不知道为什么它会生成 2 次...

我需要您的帮助来查找我的脚本中的错误,因为我自己找不到...

我正在使用 XSL 创建基于 XML 的 HTML 表单。
我基本上有一个自动创建两次的模板。我只想要<div class="columnDiv">中的那个。

屏幕截图 error reasult
屏幕截图 achieve

我的 XML

<?xml version="1.0" encoding="UTF-8"?>
<labels>
    <options>
        <option type="Top Text 1"/>
        <option type="Top Text 2"/>
        <option type="Top Text 2"/>
    </options>
    <statuses>
        <status type="Correct">
            <answer description="Yes"/>
            <answer description="No"/>
        </status>
        <status type="Error - Type 1">
            <answer description="Option 1"/>
            <answer description="Option 2"/>
            <answer description="Option 3"/>
            <answer description="Option 4"/>
        </status>
        <status type="Error - Type 2">
            <answer description="Option 1"/>
            <answer description="Option 2"/>
            <answer description="Option 3"/>
            <answer description="Option 4"/>
        </status>
    </statuses>
</labels>

我的 XSL

<?xml version="1.0" ?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

    <xsl:template match="/">
        <form method="POST" action="new-process.php">
            <div class="mainC">
                <xsl:apply-templates/> 
            </div>
            <input type="submit" name="submit" value="Submit" />
        </form>
    </xsl:template>

    <xsl:template match="options">
        <xsl:for-each select="option"> 

            <div class="columnDiv">
                <h3><xsl:value-of select="@type"/></h3>
                <xsl:apply-templates select="/labels/statuses"/>
            </div>

        </xsl:for-each>
    </xsl:template>

     <xsl:template match="status">
        <xsl:for-each select="."> 
                <label><xsl:value-of select ="@type"/></label>
                <select>
                    <xsl:for-each select="answer"> 
                            <option><xsl:value-of select="@description"/></option>
                    </xsl:for-each>
                </select>
        </xsl:for-each>
    </xsl:template>

</xsl:stylesheet>

当前输出以及所需输出的注释

<?xml version="1.0" encoding="UTF-8"?>
<form method="POST" action="new-process.php">
    <div class="mainC">
        <div class="columnDiv">
            <h3>Top Text 1</h3>
            <label>Correct</label><select><option>Yes</option><option>No</option></select>
            <label>Error - Type 1</label><select><option>Option 1</option><option>Option 2</option><option>Option 3</option><option>Option 4</option></select>
            <label>Error - Type 2</label><select><option>Option 1</option><option>Option 2</option><option>Option 3</option><option>Option 4</option></select>
        </div>
        <div class="columnDiv">
            <h3>Top Text 2</h3>
            <label>Correct</label><select><option>Yes</option><option>No</option></select>
            <label>Error - Type 1</label><select><option>Option 1</option><option>Option 2</option><option>Option 3</option><option>Option 4</option></select>
            <label>Error - Type 2</label><select><option>Option 1</option><option>Option 2</option><option>Option 3</option><option>Option 4</option></select>
        </div>
        <div class="columnDiv">
            <h3>Top Text 2</h3>
            <label>Correct</label><select><option>Yes</option><option>No</option></select>
            <label>Error - Type 1</label><select><option>Option 1</option><option>Option 2</option><option>Option 3</option><option>Option 4</option></select>
            <label>Error - Type 2</label><select><option>Option 1</option><option>Option 2</option><option>Option 3</option><option>Option 4</option></select>
        </div>

        <!-- \ this is the output that I do no want \ -->
        <label>Correct</label><select><option>Yes</option><option>No</option></select>
        <label>Error - Type 1</label><select><option>Option 1</option><option>Option 2</option><option>Option 3</option><option>Option 4</option></select>
        <label>Error - Type 2</label><select><option>Option 1</option><option>Option 2</option><option>Option 3</option><option>Option 4</option></select>
        <!-- / this is the output that I do no want / -->

    </div>
    <input type="submit" name="submit" value="Submit"/>
</form>

【问题讨论】:

标签: xml xslt


【解决方案1】:

每个 cmets,要获得您想要的解决方案,您只需将 select="/labels/options" 添加到您的第一个 apply-templates 语句。 @TimC 在his answer 中对此给出了很好的解释。

也就是说,您还在代码中使用了很多 for-each 循环。通常,对于 XSL,最好在这样的场景中使用模板,因为它可以使代码更清晰*。这是删除了这些循环的调整版本:http://xsltfiddle.liberty-development.net/bFDb2BX/3

<?xml version="1.0" ?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

    <xsl:template match="/">
        <form method="POST" action="new-process.php">
            <div class="mainC">
                <xsl:apply-templates select="/labels/options"/> 
            </div>
            <input type="submit" name="submit" value="Submit" />
        </form>
    </xsl:template>

    <xsl:template match="options/option">
        <div class="columnDiv">
            <h3><xsl:value-of select="@type"/></h3>
            <xsl:apply-templates select="/labels/statuses"/>
        </div>
    </xsl:template>

     <xsl:template match="status">
            <label><xsl:value-of select ="@type"/></label>
            <select>
                <xsl:apply-templates select="./answer"/>
            </select>
    </xsl:template>

     <xsl:template match="answer">
            <option><xsl:value-of select="@description"/></option>
    </xsl:template>


</xsl:stylesheet>

*我最初说过这也改进了并行处理;但正如 Martin 在 cmets 中指出的那样,一些引擎也支持 for-each 的并行处理;我找不到任何文件来支持我原来的陈述;所以怀疑这是杜撰的。

【讨论】:

  • 虽然我完全同意使用模板匹配和应用模板可以使代码更简洁的推理,但我想知道您的经验中哪个 XSLT 处理器“并行匹配”但按顺序执行 for-each环形。 Saxon 当然支持for-each:saxonica.com/html/documentation/xsl-elements/for-each.html 的并行处理(反正只有商业旗舰EE 有这样的高级功能,但我认为开源版本不提供模板匹配的并行处理)。这表明规范并未将for-each 限制为循环。
  • 谢谢@MartinHonnen;这是我第一次学习时读过的东西;但似乎并非普遍如此,所以我将从我的答案中删除。通过快速扫描,我可以发现这条规则隐含(例如ibm.com/developerworks/library/x-tiploopquora.com/XSLT-When-should-the-xsl-for-each-be-used),但没有确凿的证据/官方文档支持。
【解决方案2】:

您的开始并不差,但您现在需要了解 XSLT 的 Built in Template Rules。当您的 XSLT 中没有匹配的模板时,将使用这些模板。

您有一个与文档节点/ 匹配的模板,您在其中执行&lt;xsl:apply-templates /&gt;。这将选择您没有模板的label 节点。所以默认模板是这样的……

<xsl:template match="*|/">
  <xsl:apply-templates/>
</xsl:template>

这将选择optionsstatuses 节点。你有一个匹配options 的模板,这很好,但没有一个匹配statuses,所以内置的模板再次启动。

但在您的 options 模板中,您执行 &lt;xsl:apply-templates select="/labels/statuses"/&gt; 最终会导致 statuses(和子 status 节点)被选中两次。

一种解决方案是将/ 节点中的&lt;xsl:apply-templates /&gt; 更改为仅显式选择options,就像这样...

<xsl:template match="/">
    <form method="POST" action="new-process.php">
        <div class="mainC">
            <xsl:apply-templates select="labels/options"/> 
        </div>
        <input type="submit" name="submit" value="Submit" />
    </form>
</xsl:template>

【讨论】:

    猜你喜欢
    • 2012-10-22
    • 2018-02-21
    • 2016-04-23
    • 1970-01-01
    • 2021-10-21
    • 1970-01-01
    • 2012-01-09
    • 1970-01-01
    • 2023-02-08
    相关资源
    最近更新 更多