2016-03-06 205 views
3

我有一個遵循此DTD結構的XML文件。XQuery循環條件

<!DOCTYPE report [ 
<!ELEMENT report (title,section+)> 
<!ELEMENT section (title,body?,section*)> 
<!ELEMENT title (#PCDATA)> 
<!ELEMENT body (para+)> 
<!ELEMENT para(#PCDATA)> 
<!ATTLIST book version CDATA #REQUIRED> 
<!ATTLIST section number ID CDATA #REQUIRED> 
]> 

我想用XQuery查詢以下兩件事情。
1.獲取至少出現兩次的所有標題(兩個標題相同的標題)。

for $x in /report/section/ 
for $y in /report/section/ 
where $x/@title = $y/@title 
return $x/@title 

2.獲取正文或5個嵌套節中至少有10個段落的所有節的編號和標題。

for $x in /report/section/ 
where $x/para >= 10 or count(/section) > 10 
return <large>$x/number $x/title</large> 

但我的查詢似乎並不正確。我是XQuery或XPath的初學者,有人能告訴我如何解決我的疑問嗎?

編輯:示例XML

<?xml version="1.0" encoding="UTF-8"?> 
<report version = '1'> 
    <title>Harry Potter</title> 
    <section number = '1'> 
     <title>sec1</title> 
     <body> 
      <para>1</para> 
      <para>2</para> 
      <para>3</para> 
      <para>4</para> 
      <para>5</para> 
      <para>6</para> 
      <para>7</para> 
      <para>8</para> 
      <para>9</para> 
      <para>10</para> 
      <para>11</para>   
     </body>   
    </section> 

    <section number = '2'> 
     <title>sec2</title> 
     <body><para>test</para></body> 
     <section number = '2.1'> 
      <title>sec21</title> 
      <body> 
       <para>test</para> 
       <para>test</para> 
       <para>test</para> 
       <para>test</para> 
       <para>test</para> 
       <para>test</para> 
       <para>test</para> 
       <para>test</para> 
       <para>test</para> 
       <para>test</para> 
       <para>test</para> 
      </body> 
     </section> 
     <section number = '2.2'> 
      <title>sec21</title> 
      <body><para>test</para></body> 
     </section> 
     <section number = '2.3'> 
      <title>sec23</title> 
      <body><para>test</para></body> 
     </section> 
     <section number = '2.4'> 
      <title>sec24</title> 
      <body><para>test</para></body> 
     </section> 
     <section number = '2.5'> 
      <title>sec25</title> 
      <body><para>test</para></body> 
     </section> 
     <section number = '2.6'> 
      <title>sec1</title> 
      <body><para>test</para></body> 
     </section> 
    </section>  
</report> 
+0

郵政樣本XML和相應的預期輸出請 – har07

+2

對於示例XML,部分1和2.6具有相同的標題,和2.1和2.2節具有相同的標題。對於第二個問題,1和2.1在正文中有超過10個段落,並且2個具有超過5個嵌套段。 –

回答

3

在你的第一個例子中,有兩個問題。首先,您沒有獲取嵌套部分,因爲您只是迭代報表元素的直接子元素的部分元素。其次,你在同一個內容上使用兩個循環。 $x$y都可能是相同的元素,所以where條件將爲每個部分至少匹配一次。我會寫這樣的:

for $x in distinct-values(/report//section/title) 
    where count(/report//section[title=$x]) > 1 
    return $x 

循環得到所有獨特的遊戲,並遍歷它們(注意,我們使用report//section讓所有後代部分)。然後,對於其中的每一個,我們計算它使用了多少次,以保持不止一次出現的次數。然後我們返回循環變量(綁定到標題)。

運行它,我們回去

sec1 sec21 

在第二種情況下,我們還沒有得到所有後代的同樣的問題。我們也需要重視。我會用我所選擇$x/body/para得到的部分(它們出現爲主體元素的兒童)的段落

for $x in /report//section 
    where count($x/body/para) > 9 or count($x/section) > 4 
    return <large>{$x/@number} {string($x/title)}</large> 

通知。這個計數直接後代,但可以修改,以獲得所有後代,如果有必要。還要注意在直接元素構造函數中使用大括號。當我們構造一個直接元素時,所有文本都是按字面讀取的。大括號用於評估xquery表達式而不是文本文本。

我在標題中使用了字符串函數來提取元素的文本內容。如果我們不這樣做,我們會得到一個實際的標題元素,而不是它的內容(這可能是一個期望的行爲)。當我們提取數字屬性時,它將是我們構造元素的屬性(如果我們希望它是文本,我們可以將字符串函數應用於它)。

在這種情況下,它返回

<large number="1">sec1</large> 
<large number="2">sec2</large> 
<large number="2.1">sec21</large> 

的此處示例是使用使用撒克遜-HE 9.7.0.2J的OP的提供XML(的example.xml)進行測試。只有相關部件上面出現,但完整的第一個例子跑看起來像

declare namespace output = "http://www.w3.org/2010/xslt-xquery-serialization"; 
declare option output:method "text"; 
declare context item := doc("example.xml"); 
for $x in distinct-values(/report//section/title) 
    where count(/report//section[title=$x]) > 1 
    return $x 

和完整的第二個例子看起來像

declare namespace output = "http://www.w3.org/2010/xslt-xquery-serialization"; 
declare option output:method "xml"; 
declare context item := doc("example.xml"); 
for $x in /report//section 
    where count($x/body/para) > 9 or count($x/section) > 4 
    return <large>{$x/@number} {string($x/title)}</large> 
+0

現在我回頭再比較我寫的內容,這樣做更有意義。非常感謝你! –

+0

Matthew,你使用在線的xquery工具來測試它嗎? –

+0

@TT。不,我使用** Saxon-HE 9.7 **對OP提供的xml進行了測試。 – Matthew

2

對於XQuery中3.0第一個例子,我會用

declare context item := doc("example.xml"); 
for $x in /report//section/title/data() 
group by $x 
where count($x) > 1 
return $x[1]