2011-01-12 181 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」爲了得到一些結果)