跳转到内容

XQuery/拆分文件

来自维基教科书,开放的书籍,开放的世界

您有一个包含许多一致记录的大型 XML 文档。 您希望将其拆分成多个较小的文档,以便每个文档都可以由不同的用户编辑。 拆分大型文件有很多很好的理由。 有些与您一次要加载到编辑器中的数据量有关,或者与您如何将单个文件发布到远程站点有关。

eXist 和许多其他系统都进行版本控制并为每个文件保留日期/时间戳。 使用较小的文件,这些功能可能更容易执行。

我们将创建一个 XQuery,它将遍历文档中的所有记录。 对于每条记录,我们将使用 XQuery 函数将文档存储在集合中。 此函数的格式为

xmldb:store($collection, $filename, $data)

其中

  • $collection 是一个字符串,保存我们将存储每条记录数据的集合的路径。 例如 '/db/test/data'
  • $filename 是文件名称。 该名称可以从数据中推导出来,也可以由拆分查询中的序列计数器生成。 例如 'Hello.xml" 或 "1.xml"。
  • $data 是我们将存储到文件中的数据

示例输入 XML 文档

[编辑 | 编辑源代码]

一种入门方法是将您的数据(如商业术语)放入电子表格并将其转换为 XML。 oXygen XML 编辑器提供了一些非常好的工具,用于将电子表格转换为 XML 格式。 确保您将“术语”和“定义”放在第一行,并使用此行定义元素名称。

<root>
   <row>
      <Term>Hi</Term>
      <Definition>An informal short greeting.</Definition>
   </row>
   <row>
      <Term>Hello</Term>
      <Definition>A more formal greeting.</Definition>
   </row>
</root>

示例 XQuery

[编辑 | 编辑源代码]
xquery version "1.0";

let $input-document := '/db/test/input.xml'
let $collection := '/db/test/terms'

(: the login used must have write access to the collection :)
let $output-collection := xmldb:login($collection, 'my-login', 'my-password')

return
<SplitResults>{
     for $term-data in doc($input-document)/root/row
        (: For brevity we will create a file name with the term name.  Change this to be an ID function if you want :)
        let $term-name := $term-data/Term/text()
        let $documentname := concat($term-name, '.xml')
        let $store-return := xmldb:store($collection, $documentname, $term-data)
     return
        <store-result>
           <store>{$term-name}</store>
           <documentname>{$documentname}</documentname>
        </store-result>
}</SplitResults>

使用序列计数器生成人工键

[编辑 | 编辑源代码]

有时,导入记录中没有可以作为唯一键使用的元素,或者不适合用作人工键。 在这种情况下,您将需要使用计数器来创建包含唯一编号的 XML 文档。 生成的序列号称为“人工键”,因为它与记录中的任何数据元素没有直接关系。

您可以通过在 for 循环中添加“at counter”来实现此目的。 为此,只需在 for 变量之后添加字符串 at $count,如下所示

for $term-data at $count in $input-file/row

然后,store 函数可以使用 $count 变量来创建包含此编号的文件名

let $filename := concat($count, '.xml')

使用 XQuery 更新操作符为每个项目添加 ID

[编辑 | 编辑源代码]

将数据插入集合后,您将需要为每个项目分配一个唯一的 ID。 由于它是通过人工导入过程创建的,并且与项目内部的数据无关,因此这被称为人工键。 人工键通常由存储数据的计算机系统分配,但不是从数据中推导出来的。

<item>
   <person-name>John Doe</person-name>
   ...
</item>

您还可以通过执行以下操作来自动为每个项目添加 ID

  for $item at $count in $items
  return
     update insert <id>{$count}</id> preceding $item/person-name

更新后,新的 ID 元素将插入 person-name 元素之前

<item>
   <id>47</id>
   <person-name>John Doe</person-name>
   ...
</item>

最佳做法是确保项目还没有 ID 元素。

  for $item at $count in $items[not(id)]
  return
     update insert <id>{$count}</id> preceding $item/person-name

这可以防止脚本运行两次时添加重复的 id。 您也可以对其进行修改,使其从集合中最大 id 的下一个数字开始计数。

  (: get the largest ID in the collection :)
  let $largest-id := max(  collection($my-collection)/*/id/text() )
  let $offset := $largest-id + 1
  for $item at $count in $items[not(id)]
  return
     update insert <id>{$count + $offset}</id> preceding $item/person-name

参考资料

[编辑 | 编辑源代码]

拆分模式记录在企业模式集成网站上。 请注意,尽管 URL 中的名称为“Sequencer”,但该模式称为“Splitter”。

另外请注意,您选择加载到客户端的文件大小会对并发编辑的执行方式产生很大影响。 这对需要锁定哪些数据进行编辑有很大影响。 有关更多信息,请参见XRX 锁定粒度设计

华夏公益教科书