2010-06-09 81 views
2

我有一個XML片段,所以:XPath表達式來檢索最舊的/最早節點

<STATES> 
    <STATE> 
    <NAME>Alabama</NAME> 
    <ABBREVIATION>AL</ABBREVIATION> 
    <CAPITAL>Montgomery</CAPITAL> 
    <POPULATION>4661900</POPULATION> 
    <AREA>52419</AREA> 
    <DATEOFSTATEHOOD>14 December 1819</DATEOFSTATEHOOD> 
    </STATE> 
    <STATE> 
    <NAME>Alaska</NAME> 
    <ABBREVIATION>AK</ABBREVIATION> 
    <CAPITAL>Juneau</CAPITAL> 
    <POPULATION>698473</POPULATION> 
    <AREA>663268</AREA> 
    <DATEOFSTATEHOOD>1 January 1959</DATEOFSTATEHOOD> 
    </STATE> 
    <STATE> 
    <NAME>Delaware</NAME> 
    <ABBREVIATION>DE</ABBREVIATION> 
    <CAPITAL>Dover</CAPITAL> 
    <POPULATION>885122</POPULATION> 
    <AREA>2490</AREA> 
    <DATEOFSTATEHOOD>7 December 1787</DATEOFSTATEHOOD> 
    </STATE> 
</STATES> 
<etc, etc.> 

我想檢索(例如)最老的狀態(即「多佛」)的資本。 我已經設法搞到這個地步:

//STATES/STATE[DATEOFSTATEHOOD='7 December 1787']/CAPITAL/text()

但無法弄清楚如何說「DATEOFSTATEHOOD = {最早DATEOFSTATEHOOD}」。

請問有人可以指點我正確的方向嗎?

解決方案:馬特的解決方案或多或少是現貨。我不得不重新格式化日期(我使用YYYYMMDDD),因爲正如所指出的那樣,Xpath 1.0不支持我使用的日期格式。另外,微軟的XML庫(4.0和6.0)用Matt的表達式返回了整個節點列表。反轉測試解決了這個問題,使得它只返回最早的節點。

所以:

//STATES/STATE[(DATEOFSTATEHOOD < //STATES/STATE/DATEOFSTATEHOOD)]/CAPITAL/text() 

回答

3

XPATH 1.0不支持您提供格式的日期。如果你能夠利用這些日期如17871207的數字表示,那麼你可以很容易地做到這一點,像這樣:

//STATES/STATE[not(DATEOFSTATEHOOD > //STATES/STATE/DATEOFSTATEHOOD)]/CAPITAL/text() 

如果這是不可行的,那麼它可能是值得嘗試的DATEOFSTATEHOOD節點格式作爲xs:date並執行相同的:

//STATES/STATE[not(xs:date(DATEOFSTATEHOOD) > xs:date(//STATES/STATE/DATEOFSTATEHOOD))]/CAPITAL/text() 

的語法不一定完全正確的,但希望它會讓你開始。

+0

我有日期格式的控制執行這一點,所以我會試試,謝謝。 – gkrogers 2010-06-10 09:20:50

+0

我發現您的表達式在聯機表達式測試器中工作,但不在Microsoft的XML庫中。但是,將其更改爲//州/州[(DATEOFSTATEHOOD gkrogers 2010-06-10 14:56:59

1

你能重新格式化爲XS:日期?

let $dates := (xs:date('2000-10-23'), xs:date('1999-12-26')) 
let $min := fn:min($dates) 
let $max := fn:max($dates) 
return $min 

做在MarkLogic服務器,但我認爲這都是標準的東西。

1

您可以重新使用XQuery日期和使用min()來定位的最早日期:

declare variable $monthnames := ("January","February","March","April","May","June","July","August","September","October","November","December"); 

declare function local:pad-zero($s as xs:string) as xs:string { 
    if (string-length($s) = 1) then concat("0",$s) else $s 
}; 

declare function local:df ($d as xs:string) as xs:date { 
    let $dp := tokenize($d," ") 
    let $year := $dp[3] 
    let $month := local:pad-zero(string(index-of($monthnames,$dp[2]))) 
    let $day := local:pad-zero($dp[1]) 
    return 
    concat($year,"-",$month,"-",$day) 


}; 

let $states := 
<STATES> 
    <STATE> 
    <NAME>Alabama</NAME> 
    <ABBREVIATION>AL</ABBREVIATION> 
    <CAPITAL>Montgomery</CAPITAL> 
    <POPULATION>4661900</POPULATION> 
    <AREA>52419</AREA> 
    <DATEOFSTATEHOOD>14 December 1819</DATEOFSTATEHOOD> 
    </STATE> 
    <STATE> 
    <NAME>Alaska</NAME> 
    <ABBREVIATION>AK</ABBREVIATION> 
    <CAPITAL>Juneau</CAPITAL> 
    <POPULATION>698473</POPULATION> 
    <AREA>663268</AREA> 
    <DATEOFSTATEHOOD>1 January 1959</DATEOFSTATEHOOD> 
    </STATE> 
    <STATE> 
    <NAME>Delaware</NAME> 
    <ABBREVIATION>DE</ABBREVIATION> 
    <CAPITAL>Dover</CAPITAL> 
    <POPULATION>885122</POPULATION> 
    <AREA>2490</AREA> 
    <DATEOFSTATEHOOD>7 December 1787</DATEOFSTATEHOOD> 
    </STATE> 
</STATES> 


return 
    $states//STATE 
    [local:df(DATEOFSTATEHOOD) = 
     min($states//STATE/local:df(DATEOFSTATEHOOD)) 
    ] 

您可以在eXist sandbox