2010-06-09 93 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