XSL sum()和变量/循环

时间:2012-05-10 08:37:29

标签: xslt sum matching addition

我一直试图弄清楚为什么我的变量赋值和不起作用,我的表输出也只重复整个表中的第一个元素。我想要获得此代码的目的是获取第一列中打印的每个学生的studentID,第二列中该ID的学生姓名,然后分配一个变量,其中包含3个评估的学生总分已完成在第三列中打印其总标记,然后根据其总标记分配HD,D,C,P或F,例如HD为85加,D为75 +但不高于84等。

有人能告诉我哪里出错了吗?我还是XML / XSL的新手,所以欢迎批评。

grade.xsl

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

<xsl:template match="/">

    <xsl:variable name="StudentAmount" select="count(document('AssessmentItems.xml')/assessmentList/unit/studentList/student)"/>
    <xsl:variable name="totalmark" select="sum(document('AssessmentItems.xml')/assessmentList/unit/*
    [//assessmentList/unit/assessmentItems/assessment/@studId = //assessmentList/unit/studentList/student/@sid])"/>

  <html>
  <body>
    <h2>Grade Report for <xsl:value-of select="assessmentList/unit/@unitId"/> - <xsl:value-of select="assessmentList/unit/unitName"/></h2>
    <p>Number of students in this unit: <xsl:value-of select="$StudentAmount"/></p>

    <table border="1">
      <tr>
        <th>ID</th>
        <th>Name</th>
        <th>Total Mark</th>
        <th>Grade</th>
      </tr>
      <xsl:for-each select="assessmentList/unit/studentList/student">
      <tr>
        <td><xsl:value-of select="document('AssessmentItems.xml')/assessmentList/unit/studentList/student/@sid"/></td>
        <td><xsl:value-of select="document('AssessmentItems.xml')/assessmentList/unit/studentList/student"/></td>
        <td><xsl:value-of select="document('AssessmentItems.xml')/assessmentList/unit/assessmentItems/assessment/mark"/></td>

        <xsl:choose>
        <xsl:when test="$totalmark &gt; 85">
        <td color="blue">HD</td>
        </xsl:when>

        <xsl:when test="$totalmark &gt; 75">
        <td color="black">D</td>
        </xsl:when>

        <xsl:when test="$totalmark &gt; 65">
        <td color="black">C</td>
        </xsl:when>

        <xsl:when test="$totalmark &gt; 50">
        <td color="black">P</td>
        </xsl:when>

        <xsl:otherwise>
        <td color="red">F</td>
        </xsl:otherwise>
        </xsl:choose>

      </tr>
      </xsl:for-each>
    </table>

    </body>
  </html>
</xsl:template>
</xsl:stylesheet>

这是文件AssessmentItems.xml

<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="grade.xsl"?>
<assessmentList>
    <unit unitId="3311">
        <unitName>Learn To Read</unitName>
        <studentList>
            <student sid="1001">Lisa Simpson</student>
            <student sid="1002">Barney Rubble</student>
            <student sid="1003">Donald Duck</student>
        </studentList>
        <assessmentItems>
            <assessment name="Assignment 1" weight="20">
                <mark studId="1001">12</mark>
                <mark studId="1002">18</mark>
                <mark studId="1003">9</mark>
            </assessment>
            <assessment name="Assignment 2" weight="25">
                <mark studId="1001">23</mark>
                <mark studId="1002">14</mark>
                <mark studId="1003">12.5</mark>
            </assessment>
            <assessment name="Quiz" weight="15">
                <mark studId="1001">13</mark>
                <mark studId="1002">9</mark>
                <mark studId="1003">6</mark>
            </assessment>
            <assessment name="Final Exam" weight="40">
                <mark studId="1001">38</mark>
                <mark studId="1002">21</mark>
                <mark studId="1003">20.5</mark>
            </assessment>
        </assessmentItems>
    </unit>
</assessmentList>

2 个答案:

答案 0 :(得分:0)

首先,因为您只处理单个XML文档,所以根本不需要对文档('AssessmentItems.xml')的常量引用。所以,例如

<xsl:value-of 
   select="document('AssessmentItems.xml')/assessmentList/unit/studentList/student/@sid"/>

可以用

替换
<xsl:value-of select="/assessmentList/unit/studentList/student/@sid"/>

这引出了第二个问题。上面的xpath是相对于XML的document元素的,它将返回它找到的第一个学生的@sid,而不是你当前所在学生的@sid。您只需在您的情况下执行此操作

<xsl:value-of select="@sid"/>

另一个问题是您在XSLT顶部定义变量 totalmarks ,实际上它应该在 xsl:for-each 的范围内定义因此它特定于当前学生

<xsl:variable name="totalmark" select="sum(../../assessmentItems/assessment/mark[@studId = current()/@sid])" />

实际上,最好在这里使用密钥来查找结果

<xsl:key name="marks" match="mark" use="@studId" />

获得学生的总成绩......

 <xsl:variable name="totalmark" select="sum(key('marks', @sid))" />

最后一条评论虽然不是问题,但通常最好使用 xsl:apply-templates 而不是 xsl:for-each ,因为这可以避免过度缩进,并允许更好的代码重用。

尝试以下XSLT

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
   <xsl:key name="marks" match="mark" use="@studId"/>

   <xsl:template match="/">
      <xsl:variable name="StudentAmount" select="count(/assessmentList/unit/studentList/student)"/>
      <html>
         <body>
            <h2>Grade Report for 
               <xsl:value-of select="assessmentList/unit/@unitId"/>- 
               <xsl:value-of select="assessmentList/unit/unitName"/>
            </h2>
            <p>Number of students in this unit: 
               <xsl:value-of select="$StudentAmount"/></p>
            <table border="1">
               <tr>
                  <th>ID</th>
                  <th>Name</th>
                  <th>Total Mark</th>
                  <th>Grade</th>
               </tr>
               <xsl:apply-templates select="assessmentList/unit/studentList/student"/>
            </table>
         </body>
      </html>
   </xsl:template>

   <xsl:template match="student">
      <xsl:variable name="totalmark" select="sum(key('marks', @sid))"/>
      <tr>
         <td>
            <xsl:value-of select="@sid"/>
         </td>
         <td>
            <xsl:value-of select="."/>
         </td>
         <td>
            <xsl:value-of select="$totalmark"/>
         </td>
         <xsl:choose>
            <xsl:when test="$totalmark &gt; 85">
               <td color="blue">HD</td>
            </xsl:when>
            <xsl:when test="$totalmark &gt; 75">
               <td color="black">D</td>
            </xsl:when>
            <xsl:when test="$totalmark &gt; 65">
               <td color="black">C</td>
            </xsl:when>
            <xsl:when test="$totalmark &gt; 50">
               <td color="black">P</td>
            </xsl:when>
            <xsl:otherwise>
               <td color="red">F</td>
            </xsl:otherwise>
         </xsl:choose>
      </tr>
   </xsl:template>
</xsl:stylesheet>

应用于XML时,输出以下HTML

<html>
   <body>
      <h2>Grade Report for 3311- Learn To Read</h2>
      <p>Number of students in this unit: 3</p>
      <table border="1">
         <tr>
            <th>ID</th>
            <th>Name</th>
            <th>Total Mark</th>
            <th>Grade</th>
         </tr>
         <tr>
            <td>1001</td>
            <td>Lisa Simpson</td>
            <td>86</td>
            <td color="blue">HD</td>
         </tr>
         <tr>
            <td>1002</td>
            <td>Barney Rubble</td>
            <td>62</td>
            <td color="black">P</td>
         </tr>
         <tr>
            <td>1003</td>
            <td>Donald Duck</td>
            <td>48</td>
            <td color="red">F</td>
         </tr>
      </table>
   </body>
</html>

请注意,这假设您的XML中只有一个 unit 元素。如果您的实际XML有多个单元,并且您希望每个单元都有一个单独的表,那么这不是问题,您只需要确保单元ID是 xsl:key 的一部分,这样您就可以了可以查找给定单位中给定学生的结果。

答案 1 :(得分:0)

快速浏览一下代码就会发现谓词

[//assessmentList/unit/assessmentItems/assessment/@studId = //assessmentList/unit/studentList/student/@sid]

显然是错误的,因为它对源文档中的每个元素都具有相同的值(true或false)。

纠正它需要比我有时间更多地研究问题。但你似乎成了“如果它不起作用然后把'//'放在前面”谬误的受害者。