I'm learning XML/XSLT/XPATH and have something working a particular way but want to make it more efficient by removing repeat code.
XML Sample
<student>
<scores>
<score scoreID="1" weight="10" mandatory="false">7</score>
<score scoreID="2" weight="10" mandatory="false">9</score>
<score scoreID="3" weight="30" mandatory="true">13</score>
</scores>
</student>
<student>
<scores>
<score scoreID="1" weight="10" mandatory="false">8</score>
<score scoreID="2" weight="10" mandatory="false">4</score>
<score scoreID="3" weight="30" mandatory="true">25</score>
</scores>
</student>
So basically I had some XSL which checks
- if the sum of scores is greater than 25 (i.e half of total weight)
- if mandatory element is true then divide the score by the weight.
- if the result is greater than 0.5; print appropriate result
This was done with the expression below
XSL
<xsl:when test="sum(scores/score) > 25 and scores/score[@mandatory='True' and .div @weight < 0.5]">
This was all well and good except I have many students and many scores and it isn't very efficient as I'm writing the weight and mandatory values under each score.
What I would like to do is declare another structure which has the weight and mandatory attributes and then reference them to each score with keys.
So instead my XML would like more like this (basically without weight and mandatory attributes under each score)
<quizDetails>
<quiz quizID="1" weight="10" mandatory="false" />
<quiz quizID="2" weight="10" mandatory="false" />
<quiz quizID="3" weight="30" mandatory="true" />
</quizDetails>
<student>
<scores>
<score scoreID="1">7</score>
<score scoreID="2">9</score>
<score scoreID="3">13</score>
</scores>
</student>
<student>
<scores>
<score scoreID="1">8</score>
<score scoreID="2">4</score>
<score scoreID="3">25</score>
</scores>
</student>
What follows is my attempt at doing this
Defining the keys
<xsl:key name ="quizKey" match="quizDetails" use="@quizID" />
<xsl:key name ="weightKey" match="quizDetails" use="@weight" />
<xsl:key name ="mandatoryKey" match="quizDetails" use="@mandatory" />
<xsl:key name ="scoreKey" match="scores" use="@scoreID" />
The conditional test
<xsl:when test="sum(scores/score) > 25 and (key('quizKey', '@quizID') = key('scoreKey', '@scoreID')) and (key('mandatoryKey', 'true') .div (key('weightKey', '@weight') <0.5;">
The conditional test is quite a bit off
- I've tried removing the single quotes around the attributes
- I've tried doing a comparison like scoreKey = quizKey
- I've tried simplifying the conditional expression by adding one condition at a time
- I've read and re-read the section on xsl:key in the W3C XSLT2.0 reference
Using the key function is basically my main problem. I want to replicate the behaviour I had with the my previous xml and xsl but without the repeat code.