OPENXML(Transact-SQL 关键字)提供与表或视图类似的内存中 XML 文档的行集。 OPENXML 允许访问 XML 数据,就像它是关系行集一样。 它通过提供 XML 文档的内部表示形式的行集视图来执行此作。 行集中的记录可以存储在数据库表中。
SELECT 和 SELECT INTO 语句中,当行集提供程序、视图或 OPENROWSET 可以作为源出现时,可以使用 OPENXML。 有关 OPENXML 语法的信息,请参阅 OPENXML(Transact-SQL)。
若要使用 OPENXML 针对 XML 文档编写查询,必须首先调用 sp_xml_preparedocument。 这会分析 XML 文档,并返回已分析的文档的句柄,该句柄可供使用。 分析的文档是 XML 文档中各种节点的文档对象模型 (DOM) 树表示形式。 文档句柄将传递给 OPENXML。 然后,OPENXML 根据传递给文档的参数提供文档的行集视图。
注释
sp_xml_preparedocument 使用 MSXML 分析程序(Msxmlsql.dll)的 SQL 更新版本。 此版本的 MSXML 分析器旨在支持 SQL Server,并与 MSXML 版本 2.6 保持向后兼容。
必须通过调用 sp_xml_removedocument 系统存储过程来释放内存来从内存中删除 XML 文档的内部表示形式。
下图显示了此流程。
请注意,若要了解 OPENXML,需要熟悉 XPath 查询和了解 XML。 有关 SQL Server 中 XPath 支持的详细信息,请参阅 在 SQLXML 4.0 中使用 XPath 查询。
注释
OpenXML 允许将行和列 XPath 模式参数化为变量。 如果程序员向外部用户公开参数化(例如,如果参数通过外部调用的存储过程提供),则此类参数化可能会导致 XPath 表达式注入。 为了避免此类潜在的安全问题,建议永远不要向外部调用方公开 XPath 参数。
示例:
下面的示例显示了在INSERT语句和SELECT语句中OPENXML的用法。 示例 XML 文档包含 <Customers> 和 <Orders> 元素。
首先, sp_xml_preparedocument 存储过程分析 XML 文档。 分析的文档是 XML 文档中节点(元素、属性、文本和注释)的树表示形式。
OPENXML 然后引用此分析的 XML 文档,并提供此 XML 文档的所有或部分的行集视图。
INSERT使用语句OPENXML可以将此类行集中的数据插入数据库表中。 多个 OPENXML 调用可用于提供 XML 文档的各个部分的行集视图,并处理它们,例如,将行集视图插入到不同的表中。 此过程也称为将 XML 切碎到表中。
在下面的示例中,XML 文档被分解为使得<Customers>元素存储在Customers表中,而<Orders>元素存储在Orders表中,通过使用两个INSERT语句。 该示例还显示了一个带有OPENXML的SELECT语句,该语句从 XML 文档检索CustomerID和OrderDate。 该过程的最后一步是调用 sp_xml_removedocument。 这样做是为了释放分配的内存,以包含分析阶段创建的内部 XML 树表示形式。
-- Create tables for later population using OPENXML.
CREATE TABLE Customers (CustomerID varchar(20) primary key,
ContactName varchar(20),
CompanyName varchar(20));
GO
CREATE TABLE Orders( CustomerID varchar(20), OrderDate datetime);
GO
DECLARE @docHandle int;
DECLARE @xmlDocument nvarchar(max); -- or xml type
SET @xmlDocument = N'<ROOT>
<Customers CustomerID="XYZAA" ContactName="Joe" CompanyName="Company1">
<Orders CustomerID="XYZAA" OrderDate="2000-08-25T00:00:00"/>
<Orders CustomerID="XYZAA" OrderDate="2000-10-03T00:00:00"/>
</Customers>
<Customers CustomerID="XYZBB" ContactName="Steve"
CompanyName="Company2">No Orders yet!
</Customers>
</ROOT>';
EXEC sp_xml_preparedocument @docHandle OUTPUT, @xmlDocument;
-- Use OPENXML to provide rowset consisting of customer data.
INSERT Customers
SELECT *
FROM OPENXML(@docHandle, N'/ROOT/Customers')
WITH Customers;
-- Use OPENXML to provide rowset consisting of order data.
INSERT Orders
SELECT *
FROM OPENXML(@docHandle, N'//Orders')
WITH Orders;
-- Using OPENXML in a SELECT statement.
SELECT * FROM OPENXML(@docHandle, N'/ROOT/Customers/Orders') WITH (CustomerID nchar(5) '../@CustomerID', OrderDate datetime);
-- Remove the internal representation of the XML document.
EXEC sp_xml_removedocument @docHandle;
下图显示了使用 sp_xml_preparedocument 创建的上一个 XML 文档的已分析 XML 树。
OPENXML 参数
OPENXML 的参数包括:
XML 文档句柄 (idoc)
用于标识要映射到行的节点的 XPath 表达式(rowpattern)
要生成的行集的说明
行集列与 XML 节点之间的映射
XML 文档句柄 (idoc)
文档句柄由 sp_xml_preparedocument 存储过程返回。
用于标识要处理的节点的 XPath 表达式(rowpattern)
指定为 rowpattern 的 XPath 表达式标识 XML 文档中的一组节点。 由 rowpattern 标识的每个节点对应于由 OPENXML 生成的行集中的单个行。
XPath 表达式标识的节点可以是 XML 文档中的任何 XML 节点。 如果 rowpattern 标识 XML 文档中的一组元素,则标识的每个元素节点的行集中有一行。 例如,如果 rowpattern 以属性结尾,则会为 行模式选择的每个属性节点创建一行。
要生成的行集的说明
OPENXML 使用行集架构生成生成的行集。 指定行集架构时,可以使用以下选项。
使用 Edge 表格式
应使用边缘表格式来指定行集架构。 请勿使用 WITH 子句。
执行此作时,OPENXML 返回边缘表格式的行集。 这称为边缘表,因为已分析的 XML 文档树中的每个边缘都映射到行集中的行。
边缘表在单个表中表示细化 XML 文档结构。 此结构包括元素和属性名称、文档层次结构、命名空间和处理指令。 边缘表格式允许你获取未通过元属性公开的其他信息。 有关元属性的详细信息,请参阅 在 OPENXML 中指定元属性。
边缘表提供的其他信息允许存储和查询元素和属性的数据类型,以及节点类型,以及存储和查询有关 XML 文档结构的信息。 通过此附加信息,还可以生成自己的 XML 文档管理系统。
通过使用边缘表,可以编写将 XML 文档作为二进制大型对象(BLOB)输入的存储过程,生成边缘表,然后在更详细的级别提取和分析文档。 此详细级别可能包括查找文档层次结构、元素和属性名称、命名空间和处理指令。
边缘表还可以作为 XML 文档的存储格式,当映射到其他关系格式不合理,且 ntext 字段无法提供足够的结构信息时。
如果可以使用 XML 分析程序检查 XML 文档,则可以改用边缘表来获取相同的信息。
下表描述了边缘表的结构。
| 列名称 | 数据类型 | DESCRIPTION |
|---|---|---|
| id | bigint | 文档节点的唯一 ID。 根元素的 ID 值为 0。 保留负 ID 值。 |
| parentid | bigint | 标识节点的父级。 此 ID 标识的父元素不一定是父元素。 但是,这取决于其父级由此 ID 标识的节点类型。 例如,如果节点是文本节点,则其父节点可能是属性节点。 如果节点位于 XML 文档中的顶层,则其 ParentID 为 NULL。 |
| 节点类型 | int | 标识节点类型,并且是对应于 XML 对象模型(DOM)节点类型编号的整数。 下面是可在此列中显示以指示节点类型的值: 1 = 元素节点 2 = 属性节点 3 = 文本节点 4 = CDATA 节节点 5 = 实体引用节点 6 = 实体节点 7 = 处理指令节点 8 = 注释节点 9 = 文档节点 10 = 文档类型节点 11 = 文档片段节点 12 = 表示法节点 有关详细信息,请参阅 Microsoft XML (MSXML) SDK 中的“nodeType 属性”主题。 |
| localname | nvarchar(max) | 提供元素或属性的本地名称。 如果 DOM 对象没有名称,则为 NULL。 |
| 前缀 | nvarchar(max) | 节点名称的命名空间前缀。 |
| namespaceuri | nvarchar(max) | 节点的命名空间 URI。 如果值为 NULL,则不存在命名空间。 |
| 数据类型 | nvarchar(max) | 元素或属性行的实际数据类型,否则为 NULL。 数据类型是从内联 DTD 或内联架构推断的。 |
| 昨日 | bigint | 前一个兄弟元素的 XML ID。 如果没有直接前一个同级,则为 NULL。 |
| 文本 | ntext | 包含文本形式的属性值或元素内容。 或者,如果边缘表项不需要值,则为 NULL。 |
使用 WITH 子句指定现有表
可以使用 WITH 子句指定现有表的名称。 为此,只需指定一个现有表名,OPENXML 可以使用其架构生成行集。
使用 WITH 子句指定架构
可以使用 WITH 子句指定完整的架构。 在指定行集架构时,可以指定列名、其数据类型及其映射到 XML 文档。
可以使用 SchemaDeclaration 中的 ColPattern 参数指定列模式。 指定的列模式用于将行集列映射到由行模式标识的 XML 节点,还用于确定映射的类型。
如果未为某列指定 ColPattern,则基于标志参数指定的映射,行集列将映射到具有相同名称的 XML 节点。 但是,如果在 WITH 子句中将 ColPattern 指定为架构规范的一部分,则会覆盖 标志 参数中指定的映射。
行集列与 XML 节点之间的映射
在 OPENXML 语句中,可以选择指定行集列与 行模式标识的 XML 节点之间的映射类型,例如以属性为中心的或以元素为中心的映射类型。 此信息用于 XML 节点和行集列之间的转换。
可以通过两种方式指定映射,并且可以同时指定这两种方式:
使用 flags 参数
标志参数指定的映射假定 XML 节点与具有相同名称的相应行集列之间存在名称匹配。
使用 ColPattern 参数
XPath 表达式 ColPattern 在 WITH 子句中指定为 SchemaDeclaration 的一部分。 ColPattern 中指定的映射将覆盖标志参数指定的映射。
ColPattern 可用于指定映射的类型,例如以属性为中心的或以元素为中心的映射,这些映射覆盖或增强 标志指示的默认映射。
在以下情况下指定 ColPattern:
行集中的列名称与映射到的元素或属性名称不同。 在这种情况下, ColPattern 用于标识行集列映射到的 XML 元素和属性名称。
你想要将元属性映射到列。 在这种情况下, ColPattern 用于标识行集列映射到的元属性。 有关如何使用元属性的详细信息,请参阅 OPENXML 中的指定元属性。
标志和 ColPattern 参数都是可选的。 如果未指定映射,则假定采用以属性为中心的映射。 以属性为中心的映射是 标志 参数的默认值。
以属性为中心的映射
将 OPENXML 中的 标志 参数设置为 1(XML_ATTRIBUTES)指定 以属性为中心的 映射。 如果 标志 包含XML_ ATTRIBUTES,则公开的行集提供或使用每个 XML 元素表示为行的行。 XML 属性根据名称对应映射到 SchemaDeclaration 中定义的属性或由 WITH 子句的 Tablename 提供的属性。 名称对应意味着特定名称的 XML 属性存储在行集中具有相同名称的列中。
如果列名与映射到的属性名称不同,则必须指定 ColPattern 。
如果 XML 属性具有命名空间限定符,则行集中的列名还必须具有限定符。
以元素为中心的映射
将 OPENXML 中的 标志 参数设置为 2(XML_ELEMENTS)指定 以元素为中心的 映射。 它类似于 以属性为中心的 映射,但存在以下差异:
映射实例的名称对应中,如果列与具有相同名称的 XML 元素进行映射,则会选择非复杂子元素,除非指定了列级模式。 在检索过程中,如果子元素很复杂,因为它包含其他子元素,则该列将设置为 NULL。 然后忽略子元素的属性值。
对于同名的多个子元素,将返回第一个节点。
另请参阅
sp_xml_preparedocument(Transact-SQL)sp_xml_removedocument(Transact-SQL)OPENXML(Transact-SQL)XML 数据(SQL Server)