简体   繁体   English

XSL 风格:使用<xsl:for-each select>或者<xsl:template match>或 XSLT 中的其他解决方案?</xsl:template></xsl:for-each>

[英]XSL style: using <xsl:for-each select> or <xsl:template match> or other solutions in XSLT?

I'm learning to use XSL to parse XML into HTML/XHTML.我正在学习使用 XSL 将 XML 解析为 HTML/XHTML。

The XLST <xsl:for-each> element is a core element of the language that allows looping. XLST <xsl:for-each>元素是允许循环的语言的核心元素。 However posts here and elsewhere suggest using this is common for beginners (which I am.) and is poor style.然而,这里和其他地方的帖子建议使用这对初学者来说很常见(我就是。)而且风格很差。

My question is: what are better (as in more efficient / elegant / better style) options to <xsl:for-each> loops and why?我的问题是: <xsl:for-each>循环有哪些更好的(如更高效/优雅/更好的风格)选项,为什么?

In the example below I used nested <xsl:for-each> and <xsl:choose> elements to loop through the required nodes with a conditional <xsl:when> test.在下面的示例中,我使用嵌套<xsl:for-each><xsl:choose>元素通过条件<xsl:when>测试循环遍历所需的节点。 This works okay and selects the nodes I need, but does feel rather clunky...这工作正常并选择我需要的节点,但感觉相当笨重......

Your wisdom and insights would be greatly appreciated!您的智慧和见解将不胜感激!

My example XML is a report generated by a Stanford HIVdb database query: https://hivdb.stanford.edu/hivdb/by-sequences/我的示例 XML 是由斯坦福 HIVdb 数据库查询生成的报告: https://hivdb.stanford.edu/hivdb/by-sequences/

XSD schema is here: https://hivdb.stanford.edu/DR/schema/sierra.xsd XSD 架构在这里: https://hivdb.stanford.edu/DR/schema/sierra.xsd

My example XML report is here: https://github.com/delfair/xml_examples/blob/main/Resistance_1636677016671.xml我的示例 XML 报告在这里: https://github.com/delfair/xml_examples/blob/main/Resistance_1636677016671.Z0F635D0E0F3874CFF8AZ58E

My example 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>
<head>
    <title>Example Report</title>
</head>
<body>

<h3>Significant mutations</h3>

<xsl:for-each select=".//geneData">
    <xsl:choose>
        <xsl:when test="gene='HIV1PR'">
        Protease inhibitor mutations<br/><br/>
        </xsl:when>
        <xsl:when test="gene='HIV1RT'">
        Reverse transcriptase inhibitor mutations<br/><br/>
        </xsl:when>
        <xsl:when test="gene='HIV1IN'">
        Integrase inhibitor mutations<br/><br/>
        </xsl:when>
    </xsl:choose>
<table>
<xsl:for-each select=".//mutation">
    <xsl:choose>
        <xsl:when test="classification='PI_MAJOR' or classification='PI_MINOR' or classification='NRTI' or classification='NNRTI' or classification='INI_MAJOR' or classification='INI_MINOR'">
        <tr>
        <td>Class</td>
        <td>Mutation</td>
        </tr>
        <tr>
            <td><xsl:value-of select="classification"/></td>
            <td><xsl:value-of select="mutationString"/></td>
        </tr>
        </xsl:when>
    </xsl:choose>
</xsl:for-each>
</table><br/>
</xsl:for-each>

</body>
</html>

</xsl:template>
</xsl:stylesheet>

Resulting HTML:结果 HTML:

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Example Report</title>
</head>
<body>
<h3>Significant mutations</h3>
Protease inhibitor mutations<br><br><table></table>
<br>
Reverse transcriptase inhibitor mutations<br><br><table>
<tr>
<td>Class</td>
<td>Mutation</td>
</tr>
<tr>
<td>NNRTI</td>
<td>K103N</td>
</tr>
</table>
<br>
Integrase inhibitor mutations<br><br><table></table>
<br>
</body>
</html>

I guess what you mean by "advanced style" is using templates (that do pattern matching) instead of xsl:for-each "loops".我猜您所说的“高级样式”是指使用模板(进行模式匹配)而不是xsl:for-each “循环”。

The core functionality of your code could be transformed as follows:您的代码的核心功能可以转换如下:

...
      <h3>Significant mutations</h3>

      <xsl:apply-templates select=".//geneData" />
      <table>
        <xsl:apply-templates select=".//mutation" />
      </table><br/>
    </body>
  </html>
</xsl:template>
<!-- End of main template matching "/" -->

<xsl:template match="geneData[gene='HIV1PR']">Protease inhibitor mutations<br/><br/></xsl:template>
<xsl:template match="geneData[gene='HIV1RT']">Reverse transcriptase inhibitor mutations<br/><br/></xsl:template>
<xsl:template match="geneData[gene='HIV1IN']">Integrase inhibitor mutations<br/><br/></xsl:template>

<xsl:template match="mutation[classification='PI_MAJOR' or classification='PI_MINOR' or classification='NRTI' or classification='NNRTI' or classification='INI_MAJOR' or classification='INI_MINOR']">
        <tr>
            <td>Class</td>
            <td>Mutation</td>
        </tr>
        <tr>
            <td><xsl:value-of select="classification"/></td>
            <td><xsl:value-of select="mutationString"/></td>
        </tr>
</xsl:template>

</xsl:stylesheet>

In the above code both sets of nodes ( .//geneData and .//mutation ) are passed to xsl:apply-templates which passes the resulting nodes to all the templates.在上面的代码中,两组节点( .//geneData.//mutation )都被传递给xsl:apply-templates ,后者将结果节点传递给所有模板。 And those who match are executed.那些匹配的人将被处决。 Hence the short xsl:template 's with the predicates (the [...] parts of the match="..." ) which replace the xsl:when s of your code.因此,简短的xsl:template带有谓词( match="..."[...]部分),它们替换了代码的xsl:when

This is supposedly the "standard" approach of XSLT development.这应该是 XSLT 开发的“标准”方法。 In practice there are use-cases where xsl:for-each may be preferable for code clarity, but generally both approaches are interchangeable.在实践中,在某些用例中, xsl:for-each可能更适合代码清晰,但通常这两种方法是可以互换的。

First of all, xsl:for-each is NOT used for "looping".首先, xsl:for-each不用于“循环”。 It has no exit condition and there is no way to pass the result of one iteration to another.它没有退出条件,也无法将一次迭代的结果传递给另一次迭代。

Next, using xsl:for-each is NOT limited to beginners, nor is it "poor style" - despite what you might have read here or anywhere else.接下来,使用xsl:for-each不仅限于初学者,也不是“糟糕的风格”——尽管您可能在这里或其他任何地方读过。

The xsl:for-each instruction is no more than a shortcut used in a special case. xsl:for-each指令只不过是在特殊情况下使用的快捷方式。 The general approach works in two stages:一般方法分为两个阶段:

  • first, you select a set of nodes and tell the processor to apply templates to them;首先,您 select 一组节点并告诉处理器将模板应用于它们;

  • next, the processor finds the template that best matches each node in the selected node-set and applies it.接下来,处理器找到与所选节点集中的每个节点最匹配的模板并应用它。

In the case where (1) you want to apply uniform processing to all nodes in the selected set and (2) there is no need to apply the template recursively or re-use it otherwise, you can simply tell the processor: take these nodes and apply this template to them.如果 (1) 您想对所选集中的所有节点应用统一处理,并且 (2) 不需要递归应用模板或重新使用它,您可以简单地告诉处理器:获取这些节点并将此模板应用于他们。

And that's exactly what the xsl:for-each instruction does.这正是xsl:for-each指令的作用。 It has a select attribute to select the nodes to process and its content is a template to be applied to the selected node-set.它有一个select属性到 select 要处理的节点,其内容是要应用于所选节点集的模板 Nothing more, nothing less.不多也不少。 There is no paradigm shift here.这里没有范式转变。 There is no "push style" vs. "pull-style".没有“推式”与“拉式”。 There is no good vs. evil.没有善与恶。

The only problem with xsl:for-each arises when it is the only tool in the stylesheet author's toolbox.xsl:for-each是样式表作者工具箱中的唯一工具时,就会出现唯一的问题。 As I said, it is a shortcut that can be used in special circumstances.正如我所说,它是一种可以在特殊情况下使用的捷径。 When those circumstances do not apply, using it leads to very poor code.当这些情况不适用时,使用它会导致代码非常糟糕。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM