XSLT:按 2 个值中较低的值排序
我有一些格式如下的 XML:
I have some XML that is formatted as follows:
<products>
<product>
<name>Product 1</name>
<price>
<orig>15</orig>
<offer>10</offer>
</price>
</product>
<product>
<name>Product 2</name>
<price>
<orig>13</orig>
<offer>12</offer>
</price>
</product>
<product>
<name>Product 3</name>
<price>
<orig>11</orig>
</price>
</product>
</products>
我需要根据当前价格使用 XSLT 1.0(升序或降序)对产品进行排序.我的困难在于我需要对两个可能的价格值
和
if 中的较低者进行排序> 它们都存在.
I need to sort the products using XSLT 1.0 (in either ascending or descending order) based on their current price. My difficulty lies in the fact that I need to sort on the lower of the two possible price values <orig>
and <offer>
if they both exist.
对于上面的例子,正确的顺序是:
For the above example the correct ordering would be:
- 产品 1(最低值 = 10)
- 产品 3(最低值 = 11)
- 产品 2(最低值 = 12)
任何帮助将不胜感激,因为我似乎无法通过搜索找到类似的问题.
Any help would be much appreciated, as I can't seem to find a similar question through the search.
I.有一个通用的纯 XSLT 1.0 解决方案——就这么简单:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/*">
<products>
<xsl:apply-templates select="*">
<xsl:sort data-type="number" select=
"price/*[not(../* < .)]"/>
</xsl:apply-templates>
</products>
</xsl:template>
</xsl:stylesheet>
二.如果 price
除了 offer
和 orig
之外还有其他子节点——在这种情况下,一般的解决方案 I强>.以上(以及此问题的其他两个答案)无法正常工作.
II. If price
has other children in addition to offer
and orig
-- in this case the general solution I. above (as well as the other two answers to this question) doesn't work correctly.
对于这种情况,这是一个正确的解决方案:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/*">
<products>
<xsl:apply-templates select="*">
<xsl:sort data-type="number" select=
"sum(price/orig[not(../offer <= .)])
+
sum(price/offer[not(../orig < .)])
"/>
</xsl:apply-templates>
</products>
</xsl:template>
</xsl:stylesheet>
三.如果我们知道 offer
永远不会超过 orig
:
III. If we know that offer
never exceeds orig
:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/*">
<products>
<xsl:apply-templates select="*">
<xsl:sort data-type="number"
select="price/offer | price/orig[not(../offer)]"/>
</xsl:apply-templates>
</products>
</xsl:template>
</xsl:stylesheet>
四.验证:
当应用于提供的 XML 文档时,上述所有三个转换:
All three transformations above, when applied to the provided XML document:
<products>
<product>
<name>Product 1</name>
<price>
<orig>15</orig>
<offer>10</offer>
</price>
</product>
<product>
<name>Product 2</name>
<price>
<orig>13</orig>
<offer>12</offer>
</price>
</product>
<product>
<name>Product 3</name>
<price>
<orig>11</orig>
</price>
</product>
</products>
产生想要的、正确的结果:
<products>
<product>
<name>Product 1</name>
<price>
<orig>15</orig>
<offer>10</offer>
</price>
</product>
<product>
<name>Product 3</name>
<price>
<orig>11</orig>
</price>
</product>
<product>
<name>Product 2</name>
<price>
<orig>13</orig>
<offer>12</offer>
</price>
</product>
</products>
解决方案 II 是三个中唯一在应用于此 XML 文档时仍能产生正确结果的方法(在 price
):
<products>
<product>
<name>Product 1</name>
<price>
<orig>15</orig>
<offer>10</offer>
<minAcceptable>8</minAcceptable>
</price>
</product>
<product>
<name>Product 2</name>
<price>
<orig>13</orig>
<offer>12</offer>
<minAcceptable>6</minAcceptable>
</price>
</product>
<product>
<name>Product 3</name>
<price>
<orig>11</orig>
<minAcceptable>7</minAcceptable>
</price>
</product>
</products>
请注意其他答案均未正确处理此 XML 文档.
Do note that none of the other answers processes this XML document correctly.