2

我有一个如下所示的 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

4 回答 4

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

未测试。

于 2011-01-12T22:34:50.477 回答
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)
于 2011-01-12T22:46:14.417 回答
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,这样当这个 XPath 表达式针对提供的 XML 文档进行评估时

<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 ()
于 2011-01-13T03:34:34.870 回答
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”来获得一些结果)

于 2014-05-27T08:57:19.933 回答