2

我有一个 XML 片段,所以:

<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 不支持我使用的日期格式。此外,Microsoft 的 XML 库(4.0 和 6.0)返回了带有 Matt 表达式的整个节点列表。逆向测试解决了该问题,使其仅返回最早的节点。

所以:

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

3 回答 3

3

XPATH 1.0 不支持您提供的格式的日期。如果您能够使用这些日期的数字表示,例如 17871207,那么您可以轻松地这样做:

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

如果这不可行,那么可能值得尝试将DATEOFSTATEHOOD节点格式化为 anxs:date并执行相同的操作:

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

语法可能不完全正确,但希望它能帮助您入门。

于 2010-06-09T18:07:51.377 回答
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 沙箱中执行此操作

于 2010-06-11T05:56:25.900 回答
1

您可以将它们重新格式化为 xs:dates 吗?

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 Server 中完成,但我认为这都是标准的东西。

于 2010-06-09T17:58:41.000 回答