Oracle XQuery查询、构建和转换XML(1)
在 Oracle 数据库
本文提供的示例不仅演示了在什么场合下以及如何使用 XQuery 查询、构建和转换 XML,而且还演示了如何监控和分析 XQuery 表达式的性能执行,从而找到更高效的方法来处理同一工作负载。
基于关系数据构建 XML
在需要的情况下(例如,向 Web 服务发送结果),您可能要基于关系数据构建 XML。要在 Oracle 数据库 10g 第 2 版之前的版本中完成此任务,通常需要使用 SQL/XML 生成函数,如 XMLElement、XMLForest 和 XMLAgg()。在 Oracle 数据库 10 g 第 2 版中,XQuery 将比这些函数更为高效。具体而言,在 XQuery 表达式内部使用 ora:view XQuery 函数,您可以查询现有的关系表或视图以及即时构建 XML,从而不必通过关系数据显式创建 XML 视图。列表 1 中的 PL/SQL 代码演示了如何使用 ora:view 基于示例数据库模式 HR 的默认员工关系表中存储的数据构建 XML 文档。
列表 1:使用 ora:view 基于关系数据创建 XML
BEGIN DECLARE |
在列表 1 中的第一个 PL/SQL 过程中,您只是在 XML 信息库中创建了一个新文件夹。在该信息库文件夹中,您随后将存储此处显示的第二个 PL/SQL 过程中创建的 XML 文档。第二个 PL/SQL 过程首先发出 SELECT 语句,该语句使用 XMLQuery SQL 函数基于关系数据构建 XML。对于 XQuery 表达式(XMLQuery 在此处将其用作参数)而言,请注意嵌套的 FLWOR 表达式中使用的 ora:view XQuery 函数。在该示例中,ora:view 获取两个输入参数,即“HR”和“employees”,它们指示该函数查询属于 HR 数据库模式的员工表。因此,ora:view 将返回一个表示 HR.employees 表行的员工 XML 文档序列。但为了节省结果文档中的空间,只将前三个员工记录传递给结果序列。这是通过在 FLWOR 表达式的 where 子句中指定 $i/EMPLOYEE_ID <= 102 而实现的。请注意 FLWOR 表达式的 return 子句中使用的 xs:string() 和 xs:integer() XQuery 类型表达式。实际上,此处使用的这两个 XQuery 表达式不仅将 XML 节点值转换为相应的类型,而且还将提取这些节点值。随后,生成的员工 XML 文档作为 employees.xml 保存到之前在列表 1 中另一个 PL/SQL 过程中创建的 /public/employees XML 信息库文件夹。要确保此操作已完成,可执行以下查询:
SELECT XMLQuery('for $i in fn:doc("/public/employees/employees.xml") |
该查询应生成以下输出:
100 |
在以上 XQuery 中,fn:doc XQuery 函数用于访问 Oracle XML DB 信息库中存储的单个 XML 文档。但如果要处理一些具有相同或相似结构的 XML 文档(存储在同一 XML 信息库文件夹中),应该怎么做?这种情况下,另一个用于处理 XML 信息库资源的 XQuery 函数(即 fn:collection)可能会派上用场。本文稍后将介绍几个有关如何使用 fn:collection XQuery 函数的示例。
查询 XMLType 数据
XQuery 使您可以操作基于 XML 模式以及非基于模式的数据。以下示例演示了如何使用 XMLTable 函数从 OE 演示数据库模式中查询基于 PurchaseOrder XML 模式的 XMLType 表。
SELECT ttab.COLUMN_VALUE AS OrderTotal FROM purchaseorder, |
在以上示例中,您在 XMLTable 函数的 PASSING 子句中使用 OBJECT_VALUE 虚拟列将 purchaseorder 表作为上下文项传递给此处使用的 XQuery 表达式。XQuery 表达式计算用户 EABEL 请求的每个购买订单的总计,并为处理的每个订单生成一个 OrderTotal XML 元素。要访问生成的 XML,请使用 SELECT 列表中的 COLUMN_VALUE 虚拟列。最终的输出应如下所示:
ORDERTOTAL |
要获得相同的最终结果,可以改用 XMLQuery 函数。但如果将上一个示例中使用的 XQuery 表达式参数传递给 XMLQuery(如下所示):
SELECT XMLQuery('for $i in /PurchaseOrder PASSING OBJECT_VALUE |
则 XQuery 表达式返回的空序列将与 purchaseorder 表联接,从而包含在查询总结果集中。实际上,这意味着输出将不仅包含为用户 EABEL 请求的订单生成的 OrderTotal 元素,而且还包含为 purchaseorder 表中存储的所有其他订单生成的空行(默认情况下,purchaseorder 表包含 132 行)。从结果集中排除空行的方法之一是在 SELECT 语句的 WHERE 子句中使用 existsNode SQL 函数,而不是在 XQuery 表达式中使用 WHERE 子句,如下所示:
SELECT XMLQuery('for $i in /PurchaseOrder |
以上查询与本部分开头的 XMLTable 示例生成相同的输出。
Oracle XQuery查询、构建和转换XML(2)
查询 Oracle XML DB 信息库中的 XML 数据
为访问 Oracle XML DB 信息库中存储的 XML 数据,Oracle XQuery 引入了 fn:doc 和 fn:collection XQuery 函数。使用 fn:doc,您可以查询 XML 信息库中存储的单个 XML 文档,而 fn:collection 使您可以访问同一信息库文件夹中存储的多个 XML 文档。
正如本文之前(参阅使用关系数据构建 XML部分)介绍的示例所演示,使用 fn:doc 非常简单直接。它获取表示信息库文件资源 (URI) 的字符串并返回该 URI 指向的文档。要了解 fn:collection XQuery 函数的作用,同一文件夹中至少应有两个信息库文件。如果已经运行了列表 1 中的代码,则已经创建了 /public/employees 信息库文件夹并在其中存储了 employees.xml 文件。因此,您将需要在该文件夹中至少再创建一个 XML 文件,然后才能试用 fn:collection。列表 2 中的 PL/SQL 代码基于 SCOTT/TIGER 演示数据库模式的 dept 和 emp 表存储的关系数据构建 XML,然后将生成的 XML 文档作为 acc_dept.xml 保存到 /public/employees 信息库文件夹。要运行列表 2 中的 PL/SQL 过程,请确保以 SCOTT/TIGER 的身份登录。
列表 2:基于关系数据构建 XML 并将其保存到 XML 信息库
DECLARE |
此时,/public/employees 信息库文件夹应包含两个文件:acc_dept.xml(由列表 2 中的 PL/SQL 代码生成)和 employees.xml 文件(由列表 1 中的代码生成)。由于这些 XML 文档存储在同一信息库文件夹中,因此可以使用 fn:collection 函数访问两个 XML 文档中存储的员工信息。然而,尽管这些 XML 文档均包含员工 XML 元素(这些元素实际上具有相同结构),但 XML 文档本身的结构迥然不同。在 employees.xml 中,文档根元素为 EMPLOYEES,而 acc_dept.xml 将 DEPARTMENT 用作根元素。要解决此问题,可以通过 XQuery 使用 XPath // 构造,从而导航到 XML 文档中的某个节点,而不必指定该节点的确切路径。以下示例演示了如何在 XQuery 表达式中使用 XPath // 构造:
SELECT XMLQuery( |
该构造应生成以下输出:
102 |
您可以看到,以上输出包含从 employees.xml 和 acc_dept.xml 中获取的员工 XML 元素,这些元素表示薪酬大于或等于 5,000 美元的员工。
将 XML 分解为关系数据
如果应用程序处理关系数据而非 XML,而您需要访问的数据以 XML 格式存储,则将 XML 分解为关系数据可能会非常有用。继续进行上一部分的示例,您可以使用 SQL 函数 XMLTable 将员工 XML 元素分解为虚拟表的单个列,如下所示:
SELECT emps.empno,emps.ename, emps.sal FROM |
该查询将生成以下输出:
EMPNO ENAME SAL |