XQuery 是 W3C 针对查询语言开发的一个标准,用于从 XML 文件提取信息。它允许我们访问物理 XML 文档或者通过 XML 视图虚拟化为 XML 文档的关系数据。使用的表达式可以是简单的查询或较大查询的一部分,而且可以包括标准函数,例如,日期/时间、算术或字符串函数以及用户定义的函数。 XQuery 是 Oracle 数据库 10g 第 2 版中的新特性,并受 XMLQuery() 和 XMLTable() 函数支持。使用这两个函数的示例稍后在“XMLQuery() 和 XMLTable()”部分中有述。
XQuery 使用 XPath 表达式(如下所述)定位 XML 文档中的详细项。可将其看作是 Oracle 数据库 10g 第 2 版中引入的 XMLQuery() 和 XMLTable() 函数的基础,本文稍后有述。
以下将介绍一些更重要的 XQuery 表达式(包括 XPath、XMLSequence 和 FLWOR)。
XPath。 XPath 提供使用定址技术在 XML 文档中定位项的方式,而且它通过一个文档结构使用逻辑路径处理这些项。它允许程序员在较高的抽象级别处理文档,方法是通过文档指定路由而非指向特定元素。 XPath 使用节点概念定义路径在何处开始,然后定义一个“逻辑树”,该树包括诸如 attribute、self、parent、child 和 ancestor 等关系。换言之,XPath 会将 XML 文档建模为节点树。节点类型分为若干种,例如,元素节点、属性节点和文本节点。XPath 可以确定一个方式来为每个节点计算字符串值。
凭借 XPath 表达式,您可使用基于标准的方式查询和更新 XML 文档。我们将使用 extract、extractValue、existsNode 和 XMLSequence 函数来演示 XPath 功能,期间将用到我们已创建的 invoicexml_tbl 文档以及插入到其中的数据。
查询要在 XPath 示例中使用的文档。 让我们看一下如何使用 XPath 函数通过 SQL 搜索 XML (XMLType) 数据。为此,来看一下要使用 object_value pseudocolumn 从 XMLType 表检索 XML 文档时涉及的文档。
SQL> select object_value from invoicexml_tbl;
OBJECT_VALUE
<Invoice>
<MailAddressTo id="PA">
<Person>Joe Smith</Person>
<Street>10 Apple Tree Lane</Street>
<City>New York</City>
<State>NY</State>
<Zipcode>12345</Zipcode>
</MailAddressTo>
<MailAddressFrom id="PA">
<Person>Ed Jones</Person>
<Street>11 Cherry Lane</Street>
<City>Newark</City>
<State>NJ</State>
<Zipcode>67890</Zipcode>
</MailAddressFrom>
<Details id="2006Sept1to30PA">
<FromTo>Sept 1, 2006 to Sept 30, 2006</FromTo>
<Hours>70</Hours>
<Rate>30</Rate>
<Taxes>210</Taxes>
<TotalDue>2310</TotalDue>
<InvDate>Oct 1, 2006</InvDate>
<Contractor>Ed Jones</Contractor>
</Details>
</Invoice>
使用 extract。 使用 extract 时,通过将 extract 与 object_value 合并,可从文档选择单个节点及其叶节点。换言之,我们可以查看存储为 XMLType 的 XML 文档。无论我们使用的是结构化数据还是非结构化数据以及数据是否基于模式,情况都是如此。开始提取 MailAddressTo 节点及其叶节点。
select extract(object_value, '/Invoice/MailAddressTo') from invoicexml_tbl;
EXTRACT(OBJECT_VALUE,'/INVOICE/MAILADDRESSTO')
<MailAddressTo id="PA"><Person>Joe Smith</Person><Street>10
Apple Tree Lane</Street><City>New York</City><State>NY</Stat
e><Zipcode>12345</Zipcode></MailAddressTo>
如您所见,该输出包括文档的 MailAddressTo 部分,不适合打印(格式化)。此外,用于实现它的语法非常简单。重要的是,我们能够在无需转储整个内容的情况下查看文档。
使用 extractValue。 叶节点中存在的数据值可以使用 extractValue 提取。较高级的节点(例如 MailAddressTo)无法使用该函数提取。请注意,它的输出不是 XML 语法格式,其中只包含该数据值。
select extractValue(object_value, '/Invoice/MailAddressTo/Person')
Person from invoicexml_tbl;
PERSON
Joe Smith
使用 existsNode。 ExistsNode 以类似的方式使用,以便在节点级(只能在节点级)搜索文档的特定值。它返回一个 True 或 False 标志来指定搜索是否成功。= 1 谓词不是次数,表示的是 True 条件,而 = 0 表示 False。
Select count(*) from invoicexml_tbl
where existsNode(
object_value, '/Invoice/MailAddressTo[Person="Joe Smith"]') = 1;
COUNT(*)
1
使用 XMLSequence。 与 extractValue(只可从单个节点提取的值)不同,XMLSequence 可用于查看文档的多个节点或某个片段。它通过创建包含 XMLType 对象的虚拟表来完成此操作。让我们使用 MailAddressTo 分支节点来对 extractValue 和 XMLSequence 进行比较。
select extractValue(object_value, '/Invoice/MailAddressTo') from invoicexml_tbl; from invoicexml_tbl * ERROR at line 2: ORA-19025: EXTRACTVALUE returns value of only one node
该 ORA-19025 消息具有自我说明性。幸运的是,我们可以通过重构该查询并使用 XMLSequence 解决该问题,如下所示:
select value(addr)
from invoicexml_tbl i,
table(XMLSequence(
extract(i.object_value, '/Invoice/MailAddressTo'))) addr
where existsNode(i.object_value, '/Invoice/Details[@id="2006Sept1to30PA"]') = 1;
VALUE(ADDR)
<MailAddressTo id="PA"><Person>Joe Smith</Person><Street>10
Apple Tree Lane</Street><City>New York</City><State>NY</Stat
e><Zipcode>12345</Zipcode></MailAddressTo>
由于 XMLSequence 创建一个虚拟表,我们也可以在叶节点上使用该函数。
select value(person)
from invoicexml_tbl i,
table(XMLSequence(
extract(i.object_value, '/Invoice/MailAddressTo/Person'))) person
where existsnode(i.object_value, '/Invoice/Details[@id="2006Sept1to30PA"]') = 1;
VALUE(PERSON)
<Person>Joe Smith</Person>
FLWOR。 FOR、LET、WHERE、ORDER BY 和 RETURN(FLWOR;发音为“flower”)是 XQuery 语法中最重要且最强大的表达式之一。FOR 或 LET 必须存在,WHERE 和 ORDER BY 是可选的,而 RETURN 是必需的。 FLWOR 本身就是一个有待介绍的大主题。本节将为您简要介绍一下该语句的强大功能。
FOR 通过迭代方式以变量的列出顺序绑定一个或多个变量。前面列出的值之后可用在一组后续的值中。这种工作方式也类似于 SQL From 子句。前面列出的值之后可用在一组后续的值中,如下所示:
For $var in (1,2,3) , $varPlus5 in (5+$var, 5+$var, 5+$var)
这三个迭代将 $var 和 $varPlus5 分别设置为 1,6;2,7 和 3,8。
LET(类似于 FOR)以迭代方式绑定变量,可以使用以前计算的值来计算值。与使用 FOR 一样,可将 LET 看作 SQL FROM 字句。LET 也可以用于执行连接。
WHERE 过滤数据的方式与 SQL WHERE 子句相同。
ORDER BY 可以随意对数据进行排序。
RETURN 从过滤和排序后的 FLWOR 表达式返回最终结果集。
FLWOR 与 XMLQuery() 协作。 以下是查询和连接两个文档的示例:用 Party 键将 partys.xml 连接到 orders.xml 文档。该 XML 数据位于 Oracle XML DB 信息库中。为此,我们将使用 XMLQuery();FLWOR;以及 XQuery 函数 doc、count、avg 和 integer。它们位于内置 XQuery 函数的命名空间中,http://www.w3.org/2003/11/xpath_functions。
以下查询读取结果如下所示:使用函数 fn:doc,对于 (FOR) partys.xml 中的所有 partyno 属性,连接 (LET) orders.xml 中匹配 partyno 的所有定单元素(变量 $p 绑定在 FOR 语句中)。这将生成一个项流($p 和 $o),其中 $p 表示一方的编号,而 $o 表示该方的一组定单。获取其中 (WHERE) 有多个定单的项。使用命名空间 fn 中的 XQuery 函数 avg 对平均数 amt 进行降序排序 (ORDER BY)。 Amt 附加到定单元素 $o。返回该方的编号(绑定到 $p)和子元素定单计数。
SELECT XMLQuery()('for
$p in fn:doc
("/public/partys.xml")/partys/party/@partyno
let
$o := fn:doc
("/public/orders.xml")/orders/order[@partyno = $p]
where
fn:count($o) > 1
order by
fn:avg($o/@amt) descending
return
<big-party>{$p,
<ordercount>{fn:count($o)}</ordercount>,
<avgamt>{xs:integer(fn:avg($o/@amt))}</avgamt>}
</big-party>'
RETURNING CONTENT) ORDERS FROM DUAL;
ORDERS
<big-party>1111<ordercount>2</ordercount><avgamt>3500</avgamt></big-party>
是的,该查询正在进行大量工作并在 XML 文档上显示使用 FLWOR 表达式时可能出现的结果。
Oracle XML DB 提供五个 开发人员可以使用 的 XQuery 函数。它们在 http://xmlns.oracle.com/xdb 命名空间中实现,该命名空间使用前缀 ora:。除此之外还有另外两个 XPath 函数。它们仍然不是 SQL/XML 标准的一部分,但预期将来会是。该 ora:view 函数是一个特别有价值的函数,可用于将关系数据转换为 XML 格式。下面将对所有这些函数进行介绍。
ora:view XQuery 函数。 这是在关系表上创建视图的有用函数。这可以使它们看起来像 XML 文档。
Syntax: ora:view ([db-schema STRING, ] db_table STRING) RETURNS document-node (element())
本文稍后将给出使用 ora:view 的示例。
ora:contains XQuery 函数。 命名空间前缀“ora:”和名称“contains”一起使用可创建 XPath 函数,该函数可用作 SQL/XML existsNode、extract 和 extractValue 函数的 XPath 参数。这使您能够使用文本谓词执行结构搜索。
如果 text_query 与 input_text 匹配,该函数将返回一个正数。如果它们不匹配,则返回 0。当它们与 existsNode、extract 或 extractValue 一起使用时,您需要包括命名空间映射参数 xmlns:ora="http://xmlns.oracle.com/xdb"。ora:contains 的语法如下所示。当未定义 policy_owner 时,所有者是当前用户。policy_name 是要应用的匹配规则的名称。默认的匹配规则由 ctxsys.default_policy_oracontains 定义。
Syntax: ora:contains (input_text , text_query [, policy_name ] [, policy_owner ])
下面的示例显示了如何使用 ora:contains 作为 existsNode 的参数。
SELECT count(*) FROM invoicexml_tbl
WHERE existsNode(object_value, '/Invoice/MailAddressTo/Person
[ora:contains(text(), "Joe Smith") > 0]',
'xmlns:ora="http://xmlns.oracle.com/xdb"') = 1;
COUNT(*)
1
ora:matches XQuery 函数。 该函数使用正则表达式匹配文本。这类似于 SQL REGEXP_LIKE 条件,但是它使用 XQuery 参数而非 SQL 数据类型。如果 target_string 匹配正则表达式 match_pattern,则返回 True;否则,返回 False 。正如您在下面语法中所见,可以添加 match_parameter 以指定在搜索中使用的附加标准。以下示例是提供区分大小写。
Syntax: ora:matches (target_string , match_pattern [, match_parameter ])
ora:replace XQuery 函数。 该函数在满足 match_pattern 的情况下 (True) 使用 replace_string 替换 target_string,这是对 ora:matches 函数的扩展。与使用 ora:matches 一样,使用正则表达式来匹配文本。
Syntax: ora:replace (target_string , match_pattern , replace_string [, match_parameter ])
ora:sqrt XQuery 函数。 顾名思义,该函数返回提供数字的平方根值。
Syntax: ora:sqrt (number)
XPath 扩展函数:ora:instanceof 和 ora:instanceof-only。 当知道属 性和元素的数据类型时,Oracle XML DB 可以支持基于模式的数据。由于 XPath 1.0 不知道数据类型信息,因此在命名空间 http://xmlns.oracle.com/xdb 中有 XML DB 扩展函数,它们使您能够将 XML 文档节点限制为特定数据类型。函数 ora:instanceof 可用于将节点限制为数据类型或子类型,而 ora:instanceof-only 只将节点限制为数据类型。子类型是用于扩展或限制类型的特性。
Syntax: ora:instanceof(nodeset-expr, typename [, schema-url]) Syntax: ora:instanceof-only(nodeset-expr, typename [, schema-url])
在上面的语法中,nodeset-expr 通常是一个相关的 XPath 表达式。如果任何节点的数据类型与类型名匹配,则该函数返回 True,否则返回 False。类型名可使用命名空间前缀限定。
对于非基于模式的数据,这些函数将返回 False,因为这些数据没有与元素和属性相关的数据类型。