2012-09-05 31 views
8

我有些被格式化爲XML如下:XSLT:按下的2個值

<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(升序或降序)的產品進行排序價錢。我的困難在於我需要在兩個可能的價格值<orig><offer>中的較低者排序,如果它們都存在

對於上述示例的正確排序將是:

  • 產品1(最低值= 10)
  • 產品3(最低值= 11)
  • 產品2(最低值= 12)

任何幫助將不勝感激,因爲我似乎無法通過搜索找到類似的問題。

回答

5

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(../* &lt; .)]"/> 
    </xsl:apply-templates> 
    </products> 
</xsl:template> 
</xsl:stylesheet> 

二,如果priceofferorig之外還有其他子項 - 在這種情況下,通用解決方案I。上面(以及這個問題的另外兩個答案)不能正常工作。

下面是這種情況下一個正確的解決方案:

<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 &lt;= .)]) 
    + 
    sum(price/offer[not(../orig &lt; .)]) 
    "/> 
    </xsl:apply-templates> 
    </products> 
</xsl:template> 
</xsl:stylesheet> 

III。如果我們知道offer不超過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> 

IV。驗證

上述所有三個轉變,當應用於提供的XML文檔:

<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文檔時仍然產生正確結果的三個(將minAcceptable子添加到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文檔。

+0

+1非常高雅 - 不錯的作品,@DimitreNovatchev。然而,我認爲解決方案II不適用於這個問題(因爲它解決了OP沒有描述的情況),因此不應該被用作其他答案中不足的證據。 :) – ABach

+0

@ABach,不客氣。至於相關性,解決方案1.和3.完全遵循OP的XML文檔。當其他解決方案不起作用時,解決方案2使我們知道在稍微不同的情況下要做什麼。知識就是力量,難道你不是這樣嗎? –

+0

我會買它。 :) – ABach

6

(回答更新,包括兩個XSLT 1.0和2.0的想法)

一XSLT 1.0:

注意,XSLT 1.0沒有內置相當於min();假設您的解析器支持EXSLT,則可以使用它的math:min()函數來實現與以下XSLT 2.0變體非常相似的解決方案。


二, XSLT 2.0:

這是一個使用XPath 2.0聚合函數min()的解決方案。

當該XSLT 2.0溶液:

<?xml version="1.0" encoding="UTF-8"?> 
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0"> 
    <xsl:output omit-xml-declaration="no" 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"> 
    <products> 
     <xsl:apply-templates select="product"> 
     <xsl:sort select="min(price/offer|price/orig)" 
      data-type="number" order="ascending" /> 
     </xsl:apply-templates> 
    </products> 
    </xsl:template> 

</xsl:stylesheet> 

..是施加到所提供的XML:

<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> 

..the希望產生結果:

<?xml version="1.0" encoding="UTF-8"?> 
<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> 
+0

@MarkS - 我已經更新了我的答案,以提供可能的XSLT 1.0解決方案。你知道嗎:你的XSLT解析器是否實現了EXSLT擴展函數(或者特別是這些函數的'數學'子集)? – ABach

+0

它的確如此。看起來這可能是解決方案。在我給出任何反饋意見之前,我會有一個遊戲。非常感謝! – MarkS

+0

@MarkS - 聽起來不錯;保持我們的發佈! – ABach

5

的XSLT 1.0溶液,其不需要EXSLT:

<?xml version="1.0" encoding="UTF-8"?> 
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> 
    <xsl:output omit-xml-declaration="no" 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"> 
     <products> 
      <xsl:apply-templates select="product"> 
       <xsl:sort select="(price/*[not(. > ../*)])[1]" 
        data-type="number" order="ascending" /> 
      </xsl:apply-templates> 
     </products> 
    </xsl:template> 

</xsl:stylesheet> 
+0

+1偉大的解決方案。 – ABach