2011-01-12 144 views
2

我有一个看起来像这样的XML文件:高级XPath查询

<?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网站/示例。这种问题似乎没有什么进展。

+0

那声音就像你通常会从一个**数据库中回答的问题** - 不是一个冷酷的XML文件... – 2011-01-12 21:27:41

+0

我认为与教师名字的“联系”让你想到了一个数据库......如果是这样,让我们​​放下这个要求是为了讨论。所以,老师的ID就足够了。你现在怎么实现这个? – alex 2011-01-12 21:57:31

回答

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

这是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) 
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() 
0

解决方案迈克尔凯为xpath 2.0张贴是正确的,但aproximate。对于张贴在问题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”为了得到一些结果)