2012-05-19 3 views
3

Как и в этом вопросе (http://stackoverflow.com/q/1333558/948404) Я хочу использовать XPath для вычисления суммы над продуктами в структуре, подобной этой:Агрегатная функция для суммы и продукта в XPath

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

Есть ли выражение XPath, которое вычисляет сумму продуктов по каждому товару value и quantity?

Обновление: Решение должно работать с классом XSLTPпроцессора PHP, что означает, что он, вероятно, должен соответствовать требованиям XSLT 1.0. Вот почему я еще не принял два, вероятно, правильных ответа, используя XSLT 2.0. Я не мог проверить их в своей реализации PHP, ни в моем браузере, ни в Tryit Editor [1] из w3schools. Сожалею!

  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

Отсутствует "/" , См. Ответ Димитрия для исправления. –

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