我有这个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()
答案 0 :(得分:1)
首先也是最重要的:你的代码(或至少其中的大部分代码)在命令式语言中是完全正常的,但XQuery是一种函数式语言。您不会通过遍历列表并递增计数器来计算注册jack或melin的课程数。在函数式语言中,变量不可变。您创建一个表达式,在评估时,它会生成您想要的答案。以声明的方式思考。
其次,了解谓词(包含在方括号内的XPath表达式的一部分)不是记录中字段或对象成员的访问器。不要将$a/Student[name]
写在$a/Student/name
。
第三,处理语法:在FLWOR表达式中,where
子句不能跟随另一个let
子句。 for
和let
子句一起构建了一个名称/值对元组,然后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}"/>