0

I was browsing trough the available answers, but couldn't find one that I understand nor could apply to my case, so I'll try it with this question.

I have a Document that is build up like this

/
<quantity>5900</quantity>
<paper_detail_summary>
    <pd_sheets_std>9853</pd_sheets_std>
</paper_detail_summary>
<route_detail>
    <no_up>1<no_up>
</route_detail>
<route_detail>
    <no_up>2<no_up>
</route_detail>

The sum is "paper_detail_summary/pd_sheets_std - (quantity div route_detail/no_up)" where the (quantity div route_detail/no_up) must apply for each occurrence of a route_detail and be substracted from what's left of paper_detail_summary/pd_sheets_std

9853 - (5900 div 1) = 3953

3953 - (5900 div 2) = 1003

Thus resulting in the desired value of 1003

Note that the no_up is not an auto increasing value, it could have been 2 and 4 for example, it's the number of products per sheet.

Many thanks in advance.

Ignotus
  • 301
  • 1
  • 10

2 Answers2

0

Here's one way you could look at it:

Given a well-formed input:

<root>
   <quantity>5900</quantity>
   <paper_detail_summary>
      <pd_sheets_std>9853</pd_sheets_std>
   </paper_detail_summary>
   <route_detail>
      <no_up>1</no_up>
   </route_detail>
   <route_detail>
      <no_up>2</no_up>
   </route_detail>
</root>

the following stylesheet:

XSLT 1.0

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:exsl="http://exslt.org/common"
extension-element-prefixes="exsl">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>

<xsl:template match="/root">
    <xsl:variable name="quotients">
        <xsl:for-each select="route_detail">
            <quotient>
                <xsl:value-of select="../quantity div no_up"/>
            </quotient>
        </xsl:for-each>
    </xsl:variable>
    <result>
        <xsl:value-of select="paper_detail_summary - sum(exsl:node-set($quotients)/quotient)"/>
    </result>
</xsl:template>

</xsl:stylesheet>

will return:

<?xml version="1.0" encoding="UTF-8"?>
<result>1003</result>
michael.hor257k
  • 113,275
  • 6
  • 33
  • 51
  • Hi Micheal.hor257k, I cannot implement above solution, since the program processing the XML does only accept XSLT 1.0 and no other processors. Tried it, but it returns an error it cannot bind the var quotients. Thanks for your input tho. greets, Ignotus – Ignotus Oct 08 '14 at 08:14
  • For people who can use exsl, the result part should be paper_detail_summary/pd_sheets_std - sum(...) greets, Ignotus – Ignotus Oct 08 '14 at 08:54
  • @Ignotus Are you sure about this? Which processor are you using? – michael.hor257k Oct 08 '14 at 10:02
  • it's a processor that came with this software package we use for data collection on our machines. Is there a way I can check this. the error I received was the same as with the other solution btw: "A reference to variable or parameter 'sum' cannot be resolved. The variable or parameter may not be defined, or it may not be in scope", but then with your parameter name. what I want to achieve is to use the output of the variable somewhere in my template root in a table, calling preferably with – Ignotus Oct 08 '14 at 11:00
  • @Ignotus To identify your processor: http://stackoverflow.com/questions/25244370/how-can-we-check-that-which-xslt-processor-uses-as-default-in-solr/25245033#25245033 – michael.hor257k Oct 08 '14 at 11:03
  • I just figured out what I was doing wrong. now I get the correct error, which is: "Error whilst transforming XML. The error message was: Namespace 'http://exslt.org/common' does not contain any functions." The version and processor are: Microsoft, version 1. – Ignotus Oct 08 '14 at 14:44
  • You should try using the same function from MS namespace: http://msdn.microsoft.com/en-us/library/hz88kef0%28v=vs.110%29.aspx If that doesn't work, you will need to use a recursive template instead of the function. – michael.hor257k Oct 08 '14 at 15:04
  • Thanks Michael.hor257k, I have chosen the other as correct answer because no exsl is needed. This answer is correct too, for people who are using exsl. – Ignotus Oct 09 '14 at 07:48
0

Here is a solution using recursive templates. It calculates the final sum and stores it in the variable $finalSum. You can try it out here.

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

<xsl:template match="/root">
    <xsl:variable name="finalSum">
        <xsl:call-template name="processSum">
            <xsl:with-param name="sheets" select="number(paper_detail_summary/pd_sheets_std/text())" />
            <xsl:with-param name="quantity" select="number(quantity/text())" />
            <xsl:with-param name="routeDetail" select="route_detail" />
        </xsl:call-template>
    </xsl:variable>

    <xsl:value-of select="$finalSum" />

</xsl:template>

<xsl:template name="processSum">
    <xsl:param name="currPos" select="'1'" />
    <xsl:param name="sheets" />
    <xsl:param name="quantity" />
    <xsl:param name="routeDetail" />
    <xsl:if test="$currPos &lt;= count($routeDetail)">
        <xsl:variable name="sum" select="$sheets - ($quantity div number($routeDetail[$currPos]/no_up))" />
        <xsl:if test="$currPos = count($routeDetail)">
            <xsl:value-of select="$sum" />
        </xsl:if>
        <xsl:call-template name="processSum">
            <xsl:with-param name="currPos" select="$currPos + 1" />
            <xsl:with-param name="sheets" select="$sum" />
            <xsl:with-param name="quantity" select="$quantity" />
            <xsl:with-param name="routeDetail" select="$routeDetail" />
        </xsl:call-template>
    </xsl:if>
</xsl:template>

</xsl:stylesheet>
GentlePurpleRain
  • 529
  • 1
  • 5
  • 24
  • Hi GentlePurpleRain, Thanks for your answer. I tried implementing it, placed the template match root part in the current root part of the document. placed the template processSum within the /stylesheet, but outside the template root, like above. If I use the variable $sum with xsl:value-of-select in the template root, it does not recognize the variable sum is the error returned. greets, ignotus – Ignotus Oct 08 '14 at 08:46
  • And I do not understand one part, the xsl:if, does it loop too, or is this because "while" is not an option with xsl? Thanks in advance. greets Ignotus – Ignotus Oct 08 '14 at 08:56
  • the complete error is: Error whilst transforming XML. The error message was: A reference to variable or parameter 'sum' cannot be resolved. The variable or parameter may not be defined, or it may not be in scope. – Ignotus Oct 08 '14 at 09:40
  • I also figured out what I was doing wrong with this setup. The first part is displaying the values, e.g. 3953 and 1003 with no space between. How would I get it to display only the 1003 number? – Ignotus Oct 08 '14 at 14:47
  • @Ignotus: I have updated the answer to hopefully address your questions. You couldn't use the variable `$sum` in the main template, because it wasn't defined there. It was only defined in the recursive template. I have made the result of the recursive call be assigned to a new variable `$finalSum`, which is then printed out. Does this do what you want? – GentlePurpleRain Oct 08 '14 at 15:41
  • With regards to the `xsl:if`, you are correct that it is being used because there is no `while`. Instead of a `while` loop, we recursively call the same template, until we've called it the same number of times as the number of `route_detail` nodes. – GentlePurpleRain Oct 08 '14 at 15:43
  • Thanks GentlePurpleRain, now I understand a whole lot more about variables and templates. I choose this answer above the other one, because no additional exslt is needed with this solution. Muchos Gracias! – Ignotus Oct 09 '14 at 07:46