是否可以将 XSLT 标记化处理从 for-each 重构到模板中?
Is it possible to refactor XSLT tokenization handling out of a for-each and into a template?
我有以下 XML 源文件,其中包含以不同货币显示的字符串列表价格:
<?xml version="1.0" encoding="UTF-8"?>
<menu>
<item>
<name id="A">Onion Rings</name>
<prices>.00,R45.00</prices>
<kcal>270</kcal>
</item>
<!-- Some more items -->
</menu>
以及以下对价格字符串进行标记的 XSL 文件,以便输出文件对每个价格都有一个单独的价格元素:
<xsl:output method="xml" omit-xml-declaration="no" indent="yes" media-type="text/xml" />
<xsl:template match="/">
<foods>
<xsl:apply-templates select="menu/item">
<xsl:sort select="name/@id" order="descending" />
</xsl:apply-templates>
</foods>
</xsl:template>
<xsl:template match="menu/item">
<food>
<xsl:attribute name="id">
<xsl:value-of select="name/@id" />
</xsl:attribute>
<name><xsl:value-of select="name" /></name>
<prices>
<xsl:for-each select="tokenize(prices, ',')">
<price><xsl:value-of select="." /></price>
</xsl:for-each>
</prices>
<calories><xsl:value-of select="kcal" /></calories>
</food>
</xsl:template>
这会产生我想要的输出,但有没有办法分解出 for-each 并让每个项目由模板处理?类似于:
<food>
...
<prices>
<xsl:apply-templates select="tokenize(prices, ',')" />
</prices>
...
</food>
<template match="tokenize(prices, ',')">
<price><xsl:value-of select="." /></price>
</template>
在 Exselt 或 Saxon 9.6/9.7 PE 和 EE 支持的 XSLT 3.0 中,您可以按如下方式进行操作:
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="3.0"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs">
<xsl:output method="xml" omit-xml-declaration="no" indent="yes" media-type="text/xml" />
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/">
<foods>
<xsl:apply-templates select="menu/item">
<xsl:sort select="name/@id" order="descending" />
</xsl:apply-templates>
</foods>
</xsl:template>
<xsl:template match="menu/item">
<food id="{name/@id}">
<xsl:apply-templates select="name"/>
<prices>
<xsl:apply-templates select="tokenize(prices, ',')"/>
</prices>
<xsl:apply-templates select="kcal"/>
</food>
</xsl:template>
<xsl:template match="kcal">
<calories>
<xsl:value-of select="."/>
</calories>
</xsl:template>
<xsl:template match=".[. instance of xs:string]">
<price><xsl:value-of select="." /></price>
</xsl:template>
</xsl:transform>
使用 XSLT 2.0,您只能编写匹配节点的模板,而不能编写字符串(或日期或数字)等原始值,这是从 XSLT 3.0 开始的新功能。
我有以下 XML 源文件,其中包含以不同货币显示的字符串列表价格:
<?xml version="1.0" encoding="UTF-8"?>
<menu>
<item>
<name id="A">Onion Rings</name>
<prices>.00,R45.00</prices>
<kcal>270</kcal>
</item>
<!-- Some more items -->
</menu>
以及以下对价格字符串进行标记的 XSL 文件,以便输出文件对每个价格都有一个单独的价格元素:
<xsl:output method="xml" omit-xml-declaration="no" indent="yes" media-type="text/xml" />
<xsl:template match="/">
<foods>
<xsl:apply-templates select="menu/item">
<xsl:sort select="name/@id" order="descending" />
</xsl:apply-templates>
</foods>
</xsl:template>
<xsl:template match="menu/item">
<food>
<xsl:attribute name="id">
<xsl:value-of select="name/@id" />
</xsl:attribute>
<name><xsl:value-of select="name" /></name>
<prices>
<xsl:for-each select="tokenize(prices, ',')">
<price><xsl:value-of select="." /></price>
</xsl:for-each>
</prices>
<calories><xsl:value-of select="kcal" /></calories>
</food>
</xsl:template>
这会产生我想要的输出,但有没有办法分解出 for-each 并让每个项目由模板处理?类似于:
<food>
...
<prices>
<xsl:apply-templates select="tokenize(prices, ',')" />
</prices>
...
</food>
<template match="tokenize(prices, ',')">
<price><xsl:value-of select="." /></price>
</template>
在 Exselt 或 Saxon 9.6/9.7 PE 和 EE 支持的 XSLT 3.0 中,您可以按如下方式进行操作:
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="3.0"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs">
<xsl:output method="xml" omit-xml-declaration="no" indent="yes" media-type="text/xml" />
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/">
<foods>
<xsl:apply-templates select="menu/item">
<xsl:sort select="name/@id" order="descending" />
</xsl:apply-templates>
</foods>
</xsl:template>
<xsl:template match="menu/item">
<food id="{name/@id}">
<xsl:apply-templates select="name"/>
<prices>
<xsl:apply-templates select="tokenize(prices, ',')"/>
</prices>
<xsl:apply-templates select="kcal"/>
</food>
</xsl:template>
<xsl:template match="kcal">
<calories>
<xsl:value-of select="."/>
</calories>
</xsl:template>
<xsl:template match=".[. instance of xs:string]">
<price><xsl:value-of select="." /></price>
</xsl:template>
</xsl:transform>
使用 XSLT 2.0,您只能编写匹配节点的模板,而不能编写字符串(或日期或数字)等原始值,这是从 XSLT 3.0 开始的新功能。