【问题标题】:XSL sum() and variable/loopXSL sum() 和变量/循环
【发布时间】:2012-05-10 08:37:29
【问题描述】:

我一直试图弄清楚为什么我的变量分配总和不起作用,而且我的表格输出在整个表格中只重复第一个元素。我试图让这段代码做的是让每个学生的学生 ID 打印在第一列中,该 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>

【问题讨论】:

    标签: xslt sum matching addition


    【解决方案1】:

    首先,因为您只处理单个 XML 文档,所以根本不需要对 document('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 的文档元素的,它将返回它找到的第一个学生的 @sid,而不是您当前所在的学生的 @sid。你可以简单地在你的情况下这样做

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

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

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

    其实这里最好用一个key来查找结果

    <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 的一部分,这样您可以在给定单元中查找给定学生的结果。

    【讨论】:

    • 我看到了错误!非常感谢您的帮助 Tim C!是的,我现在要尝试的是让这段代码的应用模板版本工作,我喜欢让一组代码工作,然后再尝试制作具有更好功能的新版本,只是为了我自己知识的缘故。除了 apply-templates 上的 w3 school xsl 部分之外,您是否更喜欢其他文档?
    【解决方案2】:

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

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

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

    纠正它需要比我有更多时间研究的问题。但是您似乎已成为“如果不起作用,则将'//'放在最前面”的谬论的受害者。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-04-09
      • 1970-01-01
      • 1970-01-01
      • 2014-11-09
      • 2015-04-30
      • 2013-06-12
      相关资源
      最近更新 更多