2010-06-09 3 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.> 

Я хочу, чтобы получить (например) капитал старейшего государства (т.е. «Dover»). мне удалось получить это далеко:

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

, но не могу понять, как сказать «DATEOFSTATEHOOD = {самый ранний DATEOFSTATEHOOD}».

Может кто-нибудь указать мне в правильном направлении, пожалуйста?

РЕШЕНИЕ: Решение Мэтта находится на более или менее месте. Мне пришлось переформатировать даты (я использовал YYYYMMDDD), потому что, как было указано, Xpath 1.0 не поддерживает формат даты, который я использовал. Кроме того, XML-библиотека Microsoft (4.0 и 6.0) вернула весь список узлов с выражением Мэтта. Реверсирование теста устраняет эту проблему, заставляя ее возвращать только самый ранний узел.

Итак:

//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

+0

Я обнаружил, что ваше выражение работает в онлайн-тестере выражений, но не в XML-библиотеке Microsoft. Однако, изменив его на // STATES/STATE [(DATEOFSTATEHOOD gkrogers

1

Вы можете переформатировать их быть хз: даты?

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 и использовать мин(), чтобы найти самую раннюю дату:

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