高级XPath查询

时间:2011-01-12 21:24:27

标签: xpath xpath-2.0

我有一个如下所示的XML文件:

<?xml version="1.0" encoding="utf-8" ?>
<PrivateSchool>

     <Teacher id="teacher1">
         <Name>
           teacher1Name
         </Name>
    </Teacher>

    <Teacher id="teacher2">
        <Name>
            teacher2Name
        </Name>
    </Teacher>

  <Student id="student1">
    <Name>
      student1Name
    </Name>
  </Student>

  <Student id="student2">
    <Name>
      student2Name
    </Name>
  </Student>

    <Lesson student="student1" teacher="teacher1"  />
    <Lesson student="student2" teacher="teacher2"  />
    <Lesson student="student3" teacher="teacher3"  />
    <Lesson student="student1" teacher="teacher2"  />
    <Lesson student="student3" teacher="teacher3"  />
    <Lesson student="student1" teacher="teacher1"  />
    <Lesson student="student2" teacher="teacher4"  />
    <Lesson student="student1" teacher="teacher1"  />

</PrivateSchool>

还有一个与此XML相关的DTD,但我认为它与我的问题没有多大关系。让我们假设所有需要的老师和学生都有明确的定义。

什么是返回教师姓名的XPath查询,至少有一名学生参加了10多个课程?

我正在查看许多XPath站点/示例。对于这类问题,似乎没有什么先进的。

4 个答案:

答案 0 :(得分:1)

在单个XPath中进行复杂的连接可能是可能的,但是你正在敲打砖墙。 XQuery或XSLT更适合这种事情。这是在XQuery中:

declare variable $doc as doc('data.xml');

declare function local:numLessons($teacher, $student) {
  return count($doc//Lesson[@teacher = $teacher and @student = $student])
};

$doc//Teacher[some $s in //Lesson/@student satisfies local:numLessons(@id, $s) gt 10]/Name

完成后,如果你真的确定你可以将它减少到XPath 2.0:

doc('data.xml')//Teacher[
   for $t in . return 
     some $s in //Lesson/@student satisfies 
       count(//Lesson[@teacher = $t and @student = $s]) gt 10] /Name

未经测试。

答案 1 :(得分:1)

这是一个XPath 2.0解决方案:

(/PrivateSchool
   /Lesson)
      [index-of(
          /PrivateSchool
            /Lesson
               /concat(@student, '|', @teacher),
          concat(@student, '|', @teacher)
       )[10]
      ]/(for $teacher in @teacher
         return /PrivateSchool
                   /Teacher[@id = $teacher]
                      /Name)

答案 2 :(得分:1)

使用此XPath 2.0表达式

for $limit in 2,
    $t in /*/Teacher,
    $id in $t/@id,
    $s in /*/Student/@id,
    $numLessons in
       count(/*/Lesson[@teacher eq $id
                     and @student eq $s])
 return
    if($numLessons gt $limit)
      then
        (string-join(($t/Name, $s, xs:string($numLessons)), ' '),
          '&#xA;'
         )
      else ()

这里我将$limit设置为2,以便在根据提供的XML文档评估此XPath表达式时

<PrivateSchool>
    <Teacher id="teacher1">
        <Name>teacher1Name</Name>
    </Teacher>
    <Teacher id="teacher2">
        <Name>teacher2Name</Name>
    </Teacher>
    <Student id="student1">
        <Name>student1Name</Name>
    </Student>
    <Student id="student2">
        <Name>student2Name</Name>
    </Student>
    <Lesson student="student1" teacher="teacher1"  />
    <Lesson student="student2" teacher="teacher2"  />
    <Lesson student="student3" teacher="teacher3"  />
    <Lesson student="student1" teacher="teacher2"  />
    <Lesson student="student3" teacher="teacher3"  />
    <Lesson student="student1" teacher="teacher1"  />
    <Lesson student="student2" teacher="teacher4"  />
    <Lesson student="student1" teacher="teacher1"  />
</PrivateSchool>

会产生正确的结果

teacher1Name student1 3 

在您的真实表达中,您将$limit设置为10并且只会返回教师的姓名

for $limit in 10,
    $t in /*/Teacher,
    $id in $t/@id,
    $s in /*/Student/@id,
    $numLessons in
        count(/*/Lesson[@teacher eq $id
                      and @student eq $s])
 return
    if($numLessons gt $limit)
      then ($t/Name, '&#xA;')
      else ()

答案 3 :(得分:0)

Michael Kay为xpath 2.0发布的解决方案是正确的,但是近似。在问题上发布的xml的精确解决方案是(没有绝对路径):

//Teacher[
           for $t in . return 
             some $s in //Student satisfies 
               count(//Lesson[@teacher = $t/@id and @student = $s/@id]) gt 1
         ]/Name

(我使用“gt 1”代替“gt 10”以获得一些结果)