编写xquery函数

时间:2013-12-05 07:44:47

标签: xml xquery

我正在尝试编写一个包含两部分的Xquery:

  1. 第一部分是Xquery中的一个函数,用于计算每个类元素的学生数。函数的输入应该是一个类元素,输出是获取该类的学生数。
  2. 在第二部分,我想要至少有一名学生的课程清单(为了找到每门课程的学生人数,我必须使用第一部分的功能)。
  3. 这是输入xml文件的样子:在输入文件中,我们有3个不同的元素:Student,Class和Course,它们是相关的。

    <?xml version="1.0" ?>
    <Report Date="1999-12-02">
     <Students>
     <Student StudId="s11">
     <Name><First>John</First><Last>Doe</Last></Name>
     <Status>U2</Status>
     <CrsTaken CrsCode="CS308" Semester="F1997"/> 
     <CrsTaken CrsCode="MAT123" Semester="F1997"/> 
     </Student>
     <Student StudId="s66">
     <Name><First>Joe</First><Last>Public</Last></Name>
     <Status>U2</Status> 
     <CrsTaken CrsCode="MAT123" Semester="F1997"/> 
     </Student>
     </Students>
     <Classes>
     <Class>
     <CrsCode>CS308</CrsCode><Semester>F1997</Semester>
     <ClassRoster Members="s11"/>
     </Class>
     <Class>
     <CrsCode>MAT123</CrsCode><Semester>F1997</Semester>
     <ClassRoster Members="s11 s66"/>
     </Class>
    </Classes>
     <Courses>
     <Course CrsCode="CS308">
     <CrsName>Software Engineering</CrsName>
     </Course> 
     <Course CrsCode="MAT123">
     <CrsName>ALgebra</CrsName>
     </Course>
     </Courses>
    </Report>
    

    这就是我所做的代码。我写了一个函数,它有一个元素作为输入,并将返回一个整数作为学生数。我也尝试将函数调用为第二部分。但我的查询有问题。

    declare function local:numstudents($e as element())as xs:integer
    {for $s in doc('test')//Student
     let $T:=$e[CrsCode/text()=$s/CrsTaken/@CrsCode and Semester/text()=$s/CrsTaken/@Semester]
     where not(fn:empty($T))
     return count($s) };
    
    <Courses>
     {for $co in doc('test')//Course,
        $c in doc('test')//Class
       where $co/@CrsCode=$c/CrsCode/text() and local:numstudents($c)>1
     return <course CrsCode="{$co/@CrsCode}" num="{$co/CrsName/text()}" />}
    </Courses> 
    

    问题是函数部分返回序列而不是整数。这是错误:(Single item expected, (1, 1) found)。我正在使用http://basex.org/products/live-demo/来测试我的xquery。有什么帮助吗?请尽可能纠正我的代码而不是编写新代码:)。它应该是一个简单的查询,但我不知道如何解决它:)

1 个答案:

答案 0 :(得分:0)

问题出在这个函数中,你为每个学生调用count而不是全部计算。

declare function local:numstudents($e as element())as xs:integer
{
  count(
    for $s in doc('test')//Student
    let $T:=$e[CrsCode/text()=$s/CrsTaken/@CrsCode and Semester/text()=$s/CrsTaken/@Semester]
    where not(fn:empty($T))
    return $s
  )
};

更多提示:

  • 您应该可以删除大多数text(...)来电。大多数时候,他们不必要甚至是错误的。对于比较和其他调用,XQuery将自动获取元素的数据值,否则最好使用data(...)
  • not(fn:empty($T))如果它被评估为布尔值,则与$T相同。
  • 更好地与函数调用保持一致并使用fn:前缀。
  • 很难理解那些非常短的变量名称会发生​​什么。为什么不使用$course$class$student