通过继续异构XML树输出xQuery

时间:2012-12-28 19:36:30

标签: xml xquery

我尝试使用xQuery处理多个XML文件(到目前为止经验非常有限)。 XML的重要部分可以这样呈现:

<?xml version="1.0" encoding="UTF-8"?>
<ZOO xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">

<Mammals>
<marsupials>
    <zoo>
        <kangaroo>
        <number>25</number>
            <red_kangaroo>
                <number>1</number>
            </red_kangaroo>
        </kangaroo>
    </zoo>
</marsupials>

<ruminants>
    <giraffe>
        <number>10</number>
        <comments>Comment Text.</comments>
    </giraffe>
    <antelope>
        <number>20</number>
        <comments>Comment Text.</comments>
    </antelope>
    <elk>
        <number>2</number>
        <comments>Comment Text.</comments>
    </elk>
    <mouflon>
        <number>3</number>
        <comments>Comment Text.</comments>
    </mouflon>
    <ibex>
        <number>2</number>
        <comments>Comment Text.</comments>
    </ibex>
    <ox>
        <number>5</number>
        <comments>Comment Text.</comments>
    </ox>
    <other_ruminants>
        <other_ruminant>
            <name>bison</name>
            <number>1</number>
            <comments>Comment Text.</comments>
        </other_ruminant>
        <other_ruminant>
            <name>musk ox</name>
            <number>2</number>
            <comments>Comment Text.</comments>
        </other_ruminant>
    </other_ruminants>
</ruminants>

<rodents>
    <rodent>
        <name>hamster</name>
        <number>10</number>
    </rodent>
    <rodent>
        <name>squirrel</name>
        <number>15</number>
        <comments>Comment Text.</comments>
    </rodent>
    <rodent>
        <other_rodent>
            <other_rodent_name>porcupine</other_rodent_name>
            <comment>Comment Text.</comment>
        </other_rodent>
        <number>1</number>
    </rodent>
    <rodent>
        <other_rodent>
            <other_rodent_name>beaver</other_rodent_name>
            <comment>Comment Text.</comment>
        </other_rodent>
        <number>2</number>
    </rodent>
</rodents>
</Mammals>

</ZOO>

如您所见,有袋动物和大多数反刍动物都有自己的标签。然而,啮齿动物只有标签<rodent>,它们用标签<name>命名,每个文件中都有不同的啮齿动物。

我对文件进行审核的尝试看起来像这样(我使用的是BaseX 7.5):

for $z in /ZOO, $m in $z/Mammals
return
<count>
<!-- file_id comes here later -->
<kangaroo>'{$z//kangaroo/number/text()}'</kangaroo>
<giraffe>'{$z//giraffe/number/text()}'</giraffe>
</count>

...但我当然不能用啮齿动物来做,因为不同的啮齿动物的数量和它们的名字在不同的文件中是不同的。 所需的输出将是(对于显示的文件片段):

<count>
 <!-- file_id comes here later -->
 <kangaroo>'25'</kangaroo>
 <giraffe>'10'</giraffe>
 <!-- other animals with own tags come here - antelope, mouflon etc. -->
 <!-- the problems begins here: how to output the rodents in the same way: -->
 <hamster>'10'</hamster>
 <squirrel>'15'</squirrel>
 <!-- the "other rodents" is the next story, but perhaps the solution could be similar? -->
</count>

有可能吗?非常感谢您的帮助!

更新:换句话说:我怎么能输出没有自己标签的物品(啮齿动物不会,例如大部分反刍动物都这样做)并且在不同文件中的数量不同?

更新2:我在此期间继续自己尝试,这就是我现在所拥有的:

查询(只有袋鼠,长颈鹿和啮齿动物很有趣):

for $z in /ZOO, $m in $z/Mammals
return
<count>
<!-- file_id comes here later -->
<kangaroo>{$z//kangaroo/number/text()}</kangaroo>
<giraffe>{$z//giraffe/number/text()}</giraffe>
 { for $r in $m//rodent
  return 
  if ( $r//name/text() ) then
  <sp>{$r//name/text()};{$r//number/text()}</sp>
    else 
  <sp>{$r//other_rodent_name/text()};{$r//number/text()}</sp>
 }
</count>

实际输出:

 <count>
  <!-- file_id comes here later -->
  <kangaroo>25</kangaroo>
  <giraffe>10</giraffe>
  <sp>hamster;10</sp>
  <sp>squirrel;15</sp>
  <sp>porcupine;1</sp>
  <sp>beaver;2</sp>
 </count>

也就是说,我可以以某种方式输出啮齿动物(仓鼠,松鼠,豪猪和海狸)以及相应的数字作为解决方法,我可以稍后编辑输出。 .. 但是我希望在啮齿动物之后动态命名标记,例如这样:

 <count>
  <!-- file_id comes here later -->
  <kangaroo>25</kangaroo>
  <giraffe>10</giraffe>
  <hamster>10</hamster>
  <squirrel>15</squirrel>
  <porcupine>1</porcupine>
  <beaver>2</beaver>
 </count>

或者(不太优选)以这种方式输出:

 <count>
  <!-- file_id comes here later -->
  <kangaroo>25</kangaroo>
  <giraffe>10</giraffe>
    <sp>
     <name>hamster</name>
     <number>10</number>
    </sp>
    <sp>
      <name>squirrel</name>
      <number>15</number>
    </sp>
    <sp>
      <name>porcupine</name>
      <number>1</number>
    </sp>
    <sp>    
      <name>beaver</name>
      <number>2</number>
    </sp>
 </count>

我怎样才能用xQuery实现这个目标?

更新3 (以及今晚的最新更新:-)): 如果我脱离xml输出并使用csv输出,我现在似乎已经有了解决方案。

查询:

 let $nl := "&#10;"
 for $z in /ZOO, $m in $z/Mammals
 return
 (
  string(
   concat
   (
     'kangaroo', ';', $m//kangaroo/number/text(),$nl,
     'giraffe', ';', $m//giraffe/number/text(), $nl
  )),

 for $r in $m//rodent
 return
 ( 
 if ( $r//name/text() ) then
 string( concat( $r//name/text(), ';', $r//number/text(), $nl ) )
 else
 string( concat( $r//other_rodent_name/text(), ';', $r//number/text(), $nl ) )
 )
 )

和输出:

 kangaroo;25
 giraffe;10
  hamster;10
  squirrel;15
  porcupine;1
  beaver;2

可以轻松进一步处理。

这是一个新的小问题:从哪里来的缩进?非常感谢你的时间。

1 个答案:

答案 0 :(得分:1)

在XML中识别“动物”的唯一方法是存在数字元素。

/ZOO//*[number]

一旦我们选择了动物,我们就可以使用这种方法获得它的名字:

if (fn:exists($animal/name))
then $animal/name/fn:string(.)
else
  if (fn:exists($animal/other_rodent))
  then $animal/other_rodent/other_rodent_name/fn:string(.)
  else fn:local-name($animal)

添加元素构造函数并使用union和sequence操作替换嵌套条件为我们提供了一个完整的示例:

element count {
  for $animal in /ZOO//*[number]
  let $name :=
    ( $animal/(name|other_rodent/other_rodent_name)/text(),
      fn:local-name($animal) )[1]
  let $number := $animal/number/fn:string(.)
  return
    element { fn:replace($name, " ", "_") } {
      fn:concat("'", fn:concat($number, "'"))
    }
}