![](/img/trans.png)
[英]<xsl:apply-templates> usage with <xsl:for-each> using XSLT1.0 transformations
[英]XSL style: using <xsl:for-each select> or <xsl:template match> or other solutions in XSLT?
我正在学习使用 XSL 将 XML 解析为 HTML/XHTML。
XLST <xsl:for-each>
元素是允许循环的语言的核心元素。 然而,这里和其他地方的帖子建议使用这对初学者来说很常见(我就是。)而且风格很差。
我的问题是: <xsl:for-each>
循环有哪些更好的(如更高效/优雅/更好的风格)选项,为什么?
在下面的示例中,我使用嵌套<xsl:for-each>
和<xsl:choose>
元素通过条件<xsl:when>
测试循环遍历所需的节点。 这工作正常并选择我需要的节点,但感觉相当笨重......
您的智慧和见解将不胜感激!
我的示例 XML 是由斯坦福 HIVdb 数据库查询生成的报告: https://hivdb.stanford.edu/hivdb/by-sequences/
XSD 架构在这里: https://hivdb.stanford.edu/DR/schema/sierra.xsd
我的示例 XML 报告在这里: https://github.com/delfair/xml_examples/blob/main/Resistance_1636677016671.Z0F635D0E0F3874CFF8AZ58E
我的示例 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>
结果 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>
我猜您所说的“高级样式”是指使用模板(进行模式匹配)而不是xsl:for-each
“循环”。
您的代码的核心功能可以转换如下:
...
<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>
在上面的代码中,两组节点( .//geneData
和.//mutation
)都被传递给xsl:apply-templates
,后者将结果节点传递给所有模板。 那些匹配的人将被处决。 因此,简短的xsl:template
带有谓词( match="..."
的[...]
部分),它们替换了代码的xsl:when
。
这应该是 XSLT 开发的“标准”方法。 在实践中,在某些用例中, xsl:for-each
可能更适合代码清晰,但通常这两种方法是可以互换的。
首先, xsl:for-each
不用于“循环”。 它没有退出条件,也无法将一次迭代的结果传递给另一次迭代。
接下来,使用xsl:for-each
不仅限于初学者,也不是“糟糕的风格”——尽管您可能在这里或其他任何地方读过。
xsl:for-each
指令只不过是在特殊情况下使用的快捷方式。 一般方法分为两个阶段:
首先,您 select 一组节点并告诉处理器将模板应用于它们;
接下来,处理器找到与所选节点集中的每个节点最匹配的模板并应用它。
如果 (1) 您想对所选集中的所有节点应用统一处理,并且 (2) 不需要递归应用模板或重新使用它,您可以简单地告诉处理器:获取这些节点并将此模板应用于他们。
这正是xsl:for-each
指令的作用。 它有一个select
属性到 select 要处理的节点,其内容是要应用于所选节点集的模板。 不多也不少。 这里没有范式转变。 没有“推式”与“拉式”。 没有善与恶。
当xsl:for-each
是样式表作者工具箱中的唯一工具时,就会出现唯一的问题。 正如我所说,它是一种可以在特殊情况下使用的捷径。 当这些情况不适用时,使用它会导致代码非常糟糕。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.