xquery -nested for with variable

时间:2013-11-29 18:45:12

标签: xquery

我有这个xml

<Edu>
<Department>
 <Student>
  <name>jack</name>
  <Std_ID>12345678</Std_ID>
  <Degree>MS</Degree>
   </Student>
   <Student>
  <name>melin</name>
  <Std_ID>56784921</Std_ID>
  <Degree>PHD</Degree>
   </Student>

    <Student>
  <name>sali</name>
  <Std_ID>54673821</Std_ID>
  <Degree>MS</Degree>
   </Student>
   <Student>
  <name>parisa</name>
  <Std_id>54321876</Std_id>
  <Degree>BS</Degree>
  </Student> 

  <Student>
   <name>caty</name>
   <Std_ID>87654321</Std_ID>
   <Degree>MS</Degree>
  </Student> 


</Department>
<Course>
<name>programing</name>
<Student>
<name>jack</name>
<Std_ID>12345678</Std_ID>
<Degree>MS</Degree>
 </Student>
 <Student>
  <name>sali</name>
  <Std_ID>54673821</Std_ID>
  <Degree>MS</Degree>
   </Student>

<Student>
<name>parisa</name>
<Std_id>54321876</Std_id>
<Degree>BS</Degree>
</Student> 
</Course>
<Course>
<name>network</name>
 <Student>
 <name>jack</name>
 <Std_ID>12345678</Std_ID>
 <Degree>MS</Degree>
 </Student>
 </Course>
 <Course>
 <name>Database</name>

 <Student>
  <name>jack</name>
  <Std_ID>12345678</Std_ID>
  <Degree>MS</Degree>
 </Student>

 <Student>
  <name>caty</name>
  <Std_ID>87654321</Std_ID>
  <Degree>MS</Degree>
 </Student> 
 </Course>
  <Course>

  <Student>
  <name>jack</name>
  <Std_ID>12345678</Std_ID>
  <Degree>MS</Degree>
   </Student>

  <Student>
   <name>caty</name>
   <Std_ID>87654321</Std_ID>
   <Degree>MS</Degree>
  </Student>   
  </Course>
  </Edu>

我希望列出具有2个以上课程的MS学位的学生,或者具有多个课程的BS学生。我的意思是我想要具有超过2门课程的学位或具有超过一门课程的学士学位的学生的名字。我想要这两个列表。 这是我的xquery:但它不起作用:

for $i in doc("XMLFile_Q2.xml")/Edu/Department/Student[Degree="MS" or Degree="BS"]
let $counter :=0
for $a in doc("XMLFile_Q2.xml")/Edu/Course
where $a/Student[name]=$i[name] 
 let $counter := $counter+1
  return if($a/Student[Degree]="MS" and $counter gt 2 )
    then  $a/Student/name
    else if($a/Student[Degree]="BS" and $counter gt 1)
    then $a/Student/name/text()
    else()

1 个答案:

答案 0 :(得分:1)

首先也是最重要的:你的代码(或至少其中的大部分代码)在命令式语言中是完全正常的,但XQuery是一种函数式语言。您不会通过遍历列表并递增计数器来计算注册jack或melin的课程数。在函数式语言中,变量不可变。您创建一个表达式,在评估时,它会生成您想要的答案。以声明的方式思考。

其次,了解谓词(包含在方括号内的XPath表达式的一部分)不是记录中字段或对象成员的访问器。不要将$a/Student[name]写在$a/Student/name

第三,处理语法:在FLWOR表达式中,where子句不能跟随另一个let子句。 forlet子句一起构建了一个名称/值对元组,然后where子句进行过滤。

您需要符合某些条件的所有MS和BS学生的列表。首先列出MS和BS学生名单:

for $student in doc(...)/Edu/Department
                /Student[Degree = ('MS', 'BS')]
return $student/name

接下来,您要过滤该列表以包含具有两个以上课程的MS学生或具有多个课程的BS学生,并排除其他人。所以你想要的东西看起来大致如下:

for $student in doc(...)/Edu/Department
                /Student[Degree = ('MS', 'BS')]
...
where ($student/Degree = 'MS' and count($courses) gt 2)
      or 
      ($student/Degree = 'BS' and count($courses) gt 1)
return $student/name (: or perhaps just $student :)

所以现在骨架有......我们需要将变量$ courses绑定到当前$ student注册的课程集。以下let表达式将执行此操作:

let $course := doc(...)/Edu/Course[Student/name = $student/name]

由此产生的查询有点笨拙和重复,所以在现实生活中我会考虑更多常见的表达式并产生这样的结果:

for $student in $doc/Department/Student
let $degree := $student/Degree/string(),
    $name := $student/name,
    $courses := $doc/Course[Student/name = $name],
    $coursecount := count($courses)
where ($degree = 'MS' and $coursecount gt 2)
      or 
      ($degree = 'BS' and $coursecount gt 1)
return <student name="{$name}" 
                degree="{$degree}" 
                courses="{$coursecount}"/>