2012-05-19 89 views
3

與此問題類似(http://stackoverflow.com/q/1333558/948404)我想使用XPath計算以下結構中的產品總和:XPath中sum和product的總和函數

<items> 
    <item> 
     <value>1.0</value> 
     <quantity>3</quantity> 
    </item> 
    <item> 
     <value>2.5</value> 
     <quantity>2</quantity> 
    </item> 
    <!-- ... --> 
</items> 

是否有XPath表達式計算每個項目valuequantity的乘積之和?

更新:該解決方案必須與PHP的XSLTProcessor類一起工作,這意味着它可能必須符合XSLT 1.0。這就是爲什麼我還沒有接受使用XSLT 2.0的兩個可能正確的答案。我既不能在我的PHP實現中,也不能在我的瀏覽器中測試它們,也不能在w3schools的Tryit編輯器[1]中測試它們。抱歉!

  1. http://w3schools.com/xsl/tryxslt.asp?xmlfile=cdcatalog&xsltfile=cdcatalog
+0

可能重複的[XSLT總結兩個屬性的產物](http://stackoverflow.com/questions/1333558/xslt-to-sum-product-of-two-attributes) – PeerBr

回答

4

使用這個XPath 2.0表達式

sum(/items/item/(value * quantity)) 

下面是一個XSLT 2.0轉化,如驗證

<xsl:stylesheet version="2.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:output method="text"/> 

    <xsl:template match="/"> 
     <xsl:sequence select="sum(/items/item/(value * quantity))"/> 
    </xsl:template> 
</xsl:stylesheet> 

當這個變換所提供的XML文檔應用:

<items> 
    <item> 
     <value>1.0</value> 
     <quantity>3</quantity> 
    </item> 
    <item> 
     <value>2.5</value> 
     <quantity>2</quantity> 
    </item> 
    <!-- ... --> 
</items> 

XPath表達式求值和該評價的結果是輸出:

8 

說明

在XPath 2.0它是合法的一個位置的步驟是

/(expression)

甚至

/someFunction(argumentList)


II。 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:template match="/*"> 
    <xsl:call-template name="sumProducts"> 
    <xsl:with-param name="pNodes" select="item"/> 
    </xsl:call-template> 
</xsl:template> 

<xsl:template name="sumProducts"> 
    <xsl:param name="pNodes" select="/.."/> 
    <xsl:param name="pAccum" select="0"/> 

    <xsl:choose> 
    <xsl:when test="not($pNodes)"> 
    <xsl:value-of select="$pAccum"/> 
    </xsl:when> 
    <xsl:otherwise> 
    <xsl:call-template name="sumProducts"> 
     <xsl:with-param name="pNodes" select="$pNodes[position() >1]"/> 
     <xsl:with-param name="pAccum" select= 
     "$pAccum + $pNodes[1]/value * $pNodes[1]/quantity"/> 
    </xsl:call-template> 
    </xsl:otherwise> 
    </xsl:choose> 
</xsl:template> 
</xsl:stylesheet> 

當這個變換所提供的XML文檔(上文)施加,再次有用,正確的結果產生

8 

待辦事項:這種使用FXSL library很容易解決一些問題。要調用的模板是transform-and-sum

+0

就像我在其他答案中評論的那樣,這看起來對我很有前途,但我無法讓它與PHP一起工作。這是PHP僅支持XSLT 1.0/XPath 1.0的問題,還是我沒有正確調整它?版本1.0是否有類似的解決方案? – hielsnoppe

+0

@hielsnoppe:AFAIK PHP使用libxml/libxslt,它只實現XPath 1.0/XSLT 1.0。僅使用單個XPath 1.0表達式計算所需值是不可能的。如果您對XSLT 1.0解決方案感興趣,請確認,我會提供這樣的解決方案。 –

+0

感謝您對此澄清!我現在想出了一個解決方案,發佈爲答案。 – hielsnoppe

1

嘗試這種情況:

<xsl:stylesheet version="2.0"xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:output method="text"/> 
    <xsl:template match="/"> 
     <xsl:sequence select="sum(/items/item/(value * quantity))"/> 
    </xsl:template> 
</xsl:stylesheet> 
+1

缺少 「/」 。請參閱Dimitre的更正答案。 –

+0

看起來很有希望,但無法讓它與PHP XSLTProcessor一起工作。這是PHP的問題還是我沒有正確調整它? – hielsnoppe

+0

從內存中寫東西的麻煩 –

1

在此基礎上建議https://stackoverflow.com/a/1334165/948404我想出了一個解決方案符合XSLT 1.0和XPath 1.0,其通過的libxml /實現的libxslt,通過脈動熱管實現XSLTProcessor的(感謝@Dimitre Novatchev確認)使用。的

<?xml version="1.0" encoding="UTF-8"?> 
<xsl:transform version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 

    <xsl:template match="/items"> 
     <xsl:call-template name="recursivesum"> 
      <xsl:with-param name="items" select="*" /> 
     </xsl:call-template> 
    </xsl:template> 

    <xsl:template name="recursivesum"> 
     <xsl:param name="items" /> 
     <xsl:param name="sum" select="0" /> 
     <xsl:variable name="head" select="$items[1]" /> 
     <xsl:variable name="tail" select="$items[position()>1]" /> 
     <xsl:variable name="thissum" select="$head/value * $head/quantity" /> 
     <xsl:choose> 
      <xsl:when test="not($tail)"> 
       <xsl:value-of select="$sum+$thissum" /> 
      </xsl:when> 
      <xsl:otherwise> 
       <xsl:call-template name="recursivesum"> 
        <xsl:with-param name="sum" select="$sum+$thissum" /> 
        <xsl:with-param name="items" select="$tail" /> 
       </xsl:call-template> 
      </xsl:otherwise> 
     </xsl:choose> 
    </xsl:template> 

</xsl:transform>