如何比较 xml 文件中的两个元素?

How to compare two elements in an xml file?

所以我有以下 xml 文件:

<!DOCTYPE music SYSTEM "music.dtd">
<music>
 <songs>
   <song sid = "s1" time = "2:04" year = "1994">
     <title>Thriller </title>
     <artist>Michael </artist>
       <composers>
          <composer>Michael</composer> 
       </composers>
     <album> Thriller album</album>
    </song>
   <song sid = "s2" time = "2:00" year = "1999">
     <title> Billy </title>
     <artist> Thomas </artist>
     <composers>
       <composer> Rick </composer> 
     </composers>
     <album> The one </album>
    </song>
    <song sid = "s3" time = "1:50" year = "2000">
      <title> Down </title>
      <artist> PJ </artist>
      <composers>
        <composer>Jerry </composer>
      </composers>
      <album>Forty </album>
    </song>
 </songs>
 <playlists>
   <playlist pid = "p1" creator = "Tom">
     <track sid = "s1"/>
   </playlist>
 </playlists>


</music>

我想做的是从不在播放列表中的歌曲中获取所有 sid 所以在这个 xml 文件中,我想查询 return 是 sid: s2 和 s3 因为这两个都不在播放列表中并且因为 s1 在播放列表中,所以它不应该是 return编辑。

我正在尝试使用此查询:

for $x in doc("music.xml")/music/songs/song/@sid
  return <sid>{data($x)}</sid>

我试图将结果存储在一个变量中,这样我以后可以将它与另一个遍历播放列表的查询进行比较,但我对如何将查询结果存储到变量中有点迷茫.有什么帮助吗?谢谢。

您可以使用 let 子句在查询中绑定变量。这是一个包含几个中间变量的示例:

let $doc := doc("music.xml")/music
let $in-pl := $doc/playlists/playlist/track
let $not-in-pl := $doc/songs/song[fn:not(@sid = $in-pl/@sid)]
for $x in $not-in-pl/@sid
return <sid>{data($x)}</sid>

这里的关键表达式是$doc/songs/song[fn:not(@sid = $in-pl/@sid)]。这使用一般的相等比较操作 =,它可以比较序列(0 个或多个项目)。 fn:not() 函数否定比较结果,因此此表达式选择所有 song 元素,其中 @sid 不等于任何播放列表轨道的 @sid 属性。

如果您想跨多个查询存储中间结果,您将需要不同的方法,具体取决于您的 XQuery processor/environment。一些 XML 数据库允许您存储 server/session 字段,这些字段在查询中保持不变。对于其他人,您需要将中间结果存储在文档中。您使用的是什么 XQuery 处理器?

更新:

在 XQuery 中有多种构造元素的方法。您可以使用元素文字,转义其中的 XQuery 表达式:

return
  <noplaylist>
  {
    for $x in $not-in-pl/@sid
    return
      <sid sid="{ data($x) }"/>
  }
  </noplaylist>

或者您可以使用 XQuery element/attribute 构造函数:

return
  element noplaylist {
    for $x in $not-in-pl/@sid
    return
      element sid {
        attribute sid { data($x) }
      }
  }

嗯..所以我试过了:

 for $x in doc("music.xml")/music/songs/song/@sid
  where $x != doc("music.xml")//playlists/playlist/track/@sid
  return <sid>{data($x)}</sid>

我不确定这是不是巧合,但现在有道理了..