组合和分组来自两个XML文件的数据

时间:2014-05-20 03:35:35

标签: xquery

我有一个XML文件 bands.xml ,如下所示:

<?xml version="1.0" encoding="ISO-8859-1"?>
<bands>
  <band>
    <name>Metallica</name>
    <nationality>American</nationality>
  </band>
  <band>
    <name>Marilyn Manson</name>
    <nationality>American</nationality>
  </band>
</bands>

以及另一个列出其相册 albums.xml 的文件,如下所示:

<?xml version="1.0" encoding="ISO-8859-1"?>
<albums>
  <album>
    <title>Master of Puppets</title>
    <band>Metallica</band>
    <date>1986</date>
    <genre>rock</genre>
  </album>
  <album>
    <title>St. Anger</title>
    <band>Metallica</band>
    <date>2003</date>
    <genre>rock</genre>
  </album>
  <album>
    <title>The Golden Age of Grotesque</title>
    <band>Marilyn Manson</band>
    <date>2004</date>
    <genre>rock</genre>
  </album>
  <album>
    <title>Mechanical Animals</title>
    <band>Marilyn Manson</band>
    <date>1998</date>
    <genre>pop</genre>
  </album>
</albums>

我希望将这两个XML文件合并到另一个处理过的XML文件中。 Xquery将列出所有乐队,并在其中列出与该特定乐队相关的所有专辑,按专辑类型对其进行分组(按字母顺序排序)。这在下面的XML文件中进一步说明:

<?xml version="1.0" encoding="ISO-8859-1" ?>
<bands>
  <band>
    <name>Metallica</name>
    <nationality>American</nationality>
    <albums genre="rock">
      <album date="1986">
        <title>Master of Puppets</title>
      </album>
      <album date="2003">
        <title>St. Anger</title>
      </album>
    </albums>
  </band>
  <band>
    <name>Marilyn Manson</name>
    <nationality>American</nationality>
    <albums genre="pop">
      <album date="1998">
        <title>Mechanical Animals</title>
      </album>
    </albums>
    <albums genre="rock">
      <album date="2004">
        <title>The Golden Age of Grotesque</title>
      </album>
    </albums>
  </band>
</bands>

我设法做的是获取所有乐队的详细信息,并列出该乐队制作的所有相关专辑。但是,由于我使用的是Xquery 1.0,根据类型对专辑进行分组真的很令人沮丧!

2 个答案:

答案 0 :(得分:1)

以下应该可以使用纯XQuery 1.0:

declare variable $bandsxml  := doc("bands.xml");
declare variable $albumsxml := doc("albums.xml");
<bands>
{
  for $findband in $bandsxml/bands/band
  return 
    <band>
    {
      $findband/name, 
      $findband/nationality, 
      let $albums-per-band := $albumsxml/albums/album[band = $findband/name]
      for $genre in distinct-values($albums-per-band/genre)
      order by $genre
      let $albums := $albums-per-band[genre = $genre]

      return element {"albums"} {
        attribute {"genre"} {$genre},
        attribute {"active"} {string-join((xs:string(min($albums/date)), "-", xs:string(max($albums/date))), "")},
        attribute {"count"} {count($albums)},
        for $album in $albums
        return element {"album"} {
          attribute {"date"} {$album/date},
          $album/title
        }
      }
    }
    </band>
}
</bands>

在第一个for循环中,它获得每个波段的所有不同类型。然后它使用此信息,$albums是具有特定类型的特定乐队的一系列专辑。

答案 1 :(得分:0)

以下是在XQuery 3.0中执行此操作的一种方法:

xquery version "3.0";

let $bands := <bands>
  <band>
    <name>Metallica</name>
    <nationality>American</nationality>
  </band>
  <band>
    <name>Marilyn Manson</name>
    <nationality>American</nationality>
  </band>
</bands>

let $albums := <albums>
  <album>
    <title>Master of Puppets</title>
    <band>Metallica</band>
    <date>1986</date>
    <genre>rock</genre>
  </album>
  <album>
    <title>St. Anger</title>
    <band>Metallica</band>
    <date>2003</date>
    <genre>rock</genre>
  </album>
  <album>
    <title>The Golden Age of Grotesque</title>
    <band>Marilyn Manson</band>
    <date>2004</date>
    <genre>rock</genre>
  </album>
  <album>
    <title>Mechanical Animals</title>
    <band>Marilyn Manson</band>
    <date>1998</date>
    <genre>pop</genre>
  </album>
</albums>

return 
element { 'bands' } {
    for $findband in $bands//band
    return 
    element { 'band' } {
        $findband/name, 
        $findband/nationality, 
        for $findalbum in $albums//album
        let $genre := $findalbum/genre/text()
        where $findalbum/band = $findband/name
        group by $genre
        order by $genre
        return 
        element { 'albums' } {
            attribute { 'genre' } { $genre },
            attribute { 'active' } { fn:min($findalbum/date/text()) ||'-' || fn:max($findalbum/date/text()) }, 
            attribute { 'count' } { fn:count($findalbum) }, 
            for $album in $findalbum
            return
            element { 'album' } {
                attribute { 'date' } { $album/date/text()},
                $album/title
            }
        }
    }
}