使用 OPENXML
本主题中的示例说明在创建 XML 文档的行集视图时如何使用 OPENXML。有关 OPENXML 语法的信息,请参见OPENXML。除在 OPENXML 中指定元属性外,下例显示 OPENXML 的所有特征。有关在 OPENXML 中指定元属性的更多信息,请参见在 OPENXML 中指定元属性。
示例
在检索数据时,用rowpattern标识 XML 文档中决定行的节点。rowpattern用 MSXML XPath 实现中使用的 XPath 模式语言表示。例如,如果模式以元素或特性结束,则将为rowpattern选定的每个元素或特性节点创建一行。
flags值提供默认映射。在SchemaDeclaration中如果没有指定ColPattern,则使用flags参数所指定的映射。如果在SchemaDeclaration中指定了ColPattern,则忽略flags值。指定的ColPattern确定映射(attribute-centric或element-centric),还确定在处理溢出/未用完数据时的行为。
A. 执行带 OPENXML 的简单 SELECT 语句
下例中的 XML 文档由 <Customer>、<Order> 和 <OrderDetail> 元素组成。OPENXML 语句从 XML 文档中检索两列行集(CustomerID和ContactName)中的客户信息。
首先调用sp_xml_preparedocument存储过程以获得文档句柄。此文档句柄传递到 OPENXML。
在 OPENXML 语句中:
- rowpattern(/ROOT/Customer) 标识要处理的 <Customer> 节点。
- flags参数值设置为 1 表示attribute-centric映射。因此,XML 特性映射到在SchemaDeclaration中定义的行集中的列。
- 在SchemaDeclaration中(在 WITH 子句中),指定的ColName值与相应的 XML 特性名相匹配。因此,在SchemaDeclaration中不指定ColPattern参数。
最后 SELECT 语句检索 OPENXML 所提供的行集中的所有列。
DECLARE @idoc int
DECLARE @doc varchar(1000)
SET @doc ='
<ROOT>
<Customer CustomerID="VINET" ContactName="Paul Henriot">
<Order OrderID="10248" CustomerID="VINET" EmployeeID="5"
OrderDate="1996-07-04T00:00:00">
<OrderDetail ProductID="11" Quantity="12"/>
<OrderDetail ProductID="42" Quantity="10"/>
</Order>
</Customer>
<Customer CustomerID="LILAS" ContactName="Carlos Gonzlez">
<Order OrderID="10283" CustomerID="LILAS" EmployeeID="3"
OrderDate="1996-08-16T00:00:00">
<OrderDetail ProductID="72" Quantity="3"/>
</Order>
</Customer>
</ROOT>'
-- Create an internal representation of the XML document.
EXEC sp_xml_preparedocument @idoc OUTPUT, @doc
-- Execute a SELECT statement using OPENXML rowset provider.
SELECT *
FROM OPENXML (@idoc, '/ROOT/Customer',1)
WITH (CustomerID varchar(10),
ContactName varchar(20))
EXEC sp_xml_removedocument @idoc
结果如下:
CustomerID ContactName
---------- --------------------
VINET Paul Henriot
LILAS Carlos Gonzlez
如果在flags设置为2时(表示element-centric映射)执行上述 SELECT 语句,两个客户的CustomerID和ContactName值将作为 NULL 值返回,因为 <Customer> 元素没有任何子元素。
如果在 XML 文档中,<CustomerID> 和 <ContactName> 是子元素,则element-centric映射将检索值。
DECLARE @idoc int
DECLARE @doc varchar(1000)
SET @doc ='
<ROOT>
<Customer>
<CustomerID>VINET</CustomerID>
<ContactName>Paul Henriot</ContactName>
<Order OrderID="10248" CustomerID="VINET" EmployeeID="5" OrderDate="1996-07-04T00:00:00">
<OrderDetail ProductID="11" Quantity="12"/>
<OrderDetail ProductID="42" Quantity="10"/>
</Order>
</Customer>
<Customer>
<CustomerID>LILAS</CustomerID>
<ContactName>Carlos Gonzlez</ContactName>
<Order OrderID="10283" CustomerID="LILAS" EmployeeID="3" OrderDate="1996-08-16T00:00:00">
<OrderDetail ProductID="72" Quantity="3"/>
</Order>
</Customer>
</ROOT>'
-- Create an internal representation of the XML document.
EXEC sp_xml_preparedocument @idoc OUTPUT, @doc
-- Execute a SELECT statement using OPENXML rowset provider.
SELECT *
FROM OPENXML (@idoc, '/ROOT/Customer',2)
WITH (CustomerID varchar(10),
ContactName varchar(20))
EXEC sp_xml_removedocument @idoc
结果如下:
CustomerID ContactName
---------- --------------------
VINET Paul Henriot
LILAS Carlos Gonzlez
B. 为行集列和 XML 特性/元素间的映射指定ColPattern
下例说明如何用可选ColPattern参数指定 XPath 模式,以在行集列和 XML 特性(及元素)之间提供映射。
下例中的 XML 文档由 <Customer>、<Order> 和 <OrderDetail> 元素组成。OPENXML 语句从该 XML 文档中检索客户和订单信息作为行集(CustomerID、OrderDate、ProdID和Qty)。
首先调用sp_xml_preparedocument以获得文档句柄。此文档句柄传递到 OPENXML。
在 OPENXML 语句中:
- rowpattern(/ROOT/Customer/Order/OrderDetail) 标识要处理的 <OrderDetail> 节点。
- 只是为了举例说明,flags参数值设置为2表示element-centric映射。但是ColPattern参数所指定的映射重写此映射(ColPattern所指定的 XPath 模式将行集中的列映射到特性,因此产生attribute-centric映射)。
在SchemaDeclaration(在 WITH 子句内)内,也用ColName与ColType参数指定ColPattern。可选的ColPattern是指定的 XPath 模式,用以表示:
- 行集中的OrderID、CustomerID和OrderDate列映射到rowpattern所标识节点的父节点的特性,rowpattern标识 <OrderDetail> 节点。因此,CustomerID和OrderDate列映射到 <Order> 元素的CustomerID和OrderDate特性。
- 行集中的ProdID和Qty列映射到rowpattern所标识节点的ProductID和Quantity特性。
SELECT 语句于是检索 OPENXML 所提供的行集中的所有列。
DECLARE @idoc int
DECLARE @doc varchar(1000)
SET @doc ='
<ROOT>
<Customer CustomerID="VINET" ContactName="Paul Henriot">
<Order OrderID="10248" CustomerID="VINET" EmployeeID="5"
OrderDate="1996-07-04T00:00:00">
<OrderDetail ProductID="11" Quantity="12"/>
<OrderDetail ProductID="42" Quantity="10"/>
</Order>
</Customer>
<Customer CustomerID="LILAS" ContactName="Carlos Gonzlez">
<Order OrderID="10283" CustomerID="LILAS" EmployeeID="3"
OrderDate="1996-08-16T00:00:00">
<OrderDetail ProductID="72" Quantity="3"/>
</Order>
</Customer>
</ROOT>'
-- Create an internal representation of the XML document.
EXEC sp_xml_preparedocument @idoc OUTPUT, @doc
-- Execute a SELECT stmt using OPENXML rowset provider.
SELECT *
FROM OPENXML (@idoc, '/ROOT/Customer/Order/OrderDetail',2)
WITH (OrderID int '../@OrderID',
CustomerID varchar(10) '../@CustomerID',
OrderDate datetime '../@OrderDate',
ProdID int '@ProductID',
Qty int '@Quantity')
结果如下:
OrderID CustomerID OrderDate ProdID Qty
-------------------------------------------------------------
10248 VINET 1996-07-04 00:00:00.000 11 12
10248 VINET 1996-07-04 00:00:00.000 42 10
10283 LILAS 1996-08-16 00:00:00.000 72 3
还可以指定被指定为ColPattern的 XPath 模式,以将 XML 元素映射到行集列(产生element-centric映射)。在下例中,XML 文档 <CustomerID> 和 <OrderDate> 是 <Orders> 元素的子元素。因为ColPattern重写flags参数所指定的映射,所以在 OPENXML 中没有指定flags参数。
DECLARE @idoc int
DECLARE @doc varchar(1000)
SET @doc ='
<ROOT>
<Customer CustomerID="VINET" ContactName="Paul Henriot">
<Order EmployeeID="5" >
<OrderID>10248</OrderID>
<CustomerID>VINET</CustomerID>
<OrderDate>1996-07-04T00:00:00</OrderDate>
<OrderDetail ProductID="11" Quantity="12"/>
<OrderDetail ProductID="42" Quantity="10"/>
</Order>
</Customer>
<Customer CustomerID="LILAS" ContactName="Carlos Gonzlez">
<Order EmployeeID="3" >
<OrderID>10283</OrderID>
<CustomerID>LILAS</CustomerID>
<OrderDate>1996-08-16T00:00:00</OrderDate>
<OrderDetail ProductID="72" Quantity="3"/>
</Order>
</Customer>
</ROOT>'
-- Create an internal representation of the XML document.
EXEC sp_xml_preparedocument @idoc OUTPUT, @doc
-- Execute a SELECT stmt using OPENXML rowset provider.
SELECT *
FROM OPENXML (@idoc, '/ROOT/Customer/Order/OrderDetail')
WITH (CustomerID varchar(10) '../CustomerID',
OrderDate datetime '../OrderDate',
ProdID int '@ProductID',
Qty int '@Quantity')
EXEC sp_xml_removedocument @idoc
组合 attribute-centric 映射和 element-centric 映射
在下例中,flags 参数设置为3表示应使用attribute-centric映射和element-centric映射。在这种情况下,首先应用attribute-centric映射,然后对所有未处理的列应用element-centric映射。
DECLARE @idoc int
DECLARE @doc varchar(1000)
SET @doc ='
<ROOT>
<Customer CustomerID="VINET" >
<ContactName>Paul Henriot</ContactName>
<Order OrderID="10248" CustomerID="VINET" EmployeeID="5"
OrderDate="1996-07-04T00:00:00">
<OrderDetail ProductID="11" Quantity="12"/>
<OrderDetail ProductID="42" Quantity="10"/>
</Order>
</Customer>
<Customer CustomerID="LILAS" >
<ContactName>Carlos Gonzlez</ContactName>
<Order OrderID="10283" CustomerID="LILAS" EmployeeID="3"
OrderDate="1996-08-16T00:00:00">
<OrderDetail ProductID="72" Quantity="3"/>
</Order>
</Customer>
</ROOT>'
-- Create an internal representation of the XML document.
EXEC sp_xml_preparedocument @idoc OUTPUT, @doc
-- Execute a SELECT statement using OPENXML rowset provider.
SELECT *
FROM OPENXML (@idoc, '/ROOT/Customer',3)
WITH (CustomerID varchar(10),
ContactName varchar(20))
EXEC sp_xml_removedocument @idoc
下面是查询结果。
CustomerID ContactName
---------- --------------------
VINET Paul Henriot
LILAS Carlos Gonzlez
attribute-centric映射应用于CustomerID。在 <Customers> 元素内没有ContactName特性;因此,应用element-centric映射。
D. 指定 text() XPath 函数作为 ColPattern
下例中的 XML 文档由 <Customer> 和 <Order> 元素组成。OPENXML 语句从 <Order> 元素、节点的(rowpattern所标识的)父节点 ID 和元素内容的叶值字符串中检索由oid特性组成的行集。
首先调用sp_xml_preparedocument以获得文档句柄。此文档句柄传递到 OPENXML。
在 OPENXML 语句中:
- rowpattern(/root/Customer/Order) 标识要处理的 <Order> 节点。
- flags参数值设置为1表示attribute-centric映射。因此,XML 特性映射到SchemaDeclaration中定义的行集列。
- 在SchemaDeclaration中(在 WITH 子句中),行集列名、oid和amount与相应的 XML 特性名相匹配。因此,没有指定ColPattern参数。对于行集中的comment列,将 XPath 函数 (text()) 指定为ColPattern。这将重写在flags参数中指定的attribute-centric映射,而且列将包含元素内容的叶值字符串。
SELECT 语句于是检索 OPENXML 所提供的行集中的所有列。
DECLARE @idoc int
DECLARE @doc varchar(1000)
--sample XML document
SET @doc ='
<root>
<Customer cid= "C1" name="Janine" city="Issaquah">
<Order oid="O1" date="1/20/1996" amount="3.5" />
<Order oid="O2" date="4/30/1997" amount="13.4">Customer was very satisfied
</Order>
</Customer>
<Customer cid="C2" name="Ursula" city="Oelde" >
<Order oid="O3" date="7/14/1999" amount="100" note="Wrap it blue
white red">
<Urgency>Important</Urgency>
Happy Customer.
</Order>
<Order oid="O4" date="1/20/1996" amount="10000"/>
</Customer>
</root>
'
-- Create an internal representation of the XML document.
EXEC sp_xml_preparedocument @idoc OUTPUT, @doc
-- Execute a SELECT statement using OPENXML rowset provider.
SELECT *
FROM OPENXML (@idoc, '/root/Customer/Order', 1)
WITH (oid char(5),
amount float,
comment ntext 'text()')
EXEC sp_xml_removedocument @idoc
结果如下:
oid amount comment
----- ----------- -----------------------------
O1 3.5 NULL
O2 13.4 Customer was very satisfied
O3 100.0 Happy Customer.
O4 10000.0 NULL
E. 在 WITH 子句中指定 TableName
下例在 WITH 子句中指定TableName,而不在 WITH 子句中指定SchemaDeclaration。这在表具有希望的结构且不需要列模式(ColPattern参数)时很有用。
下例中的 XML 文档由 <Customer> 和 <Order> 元素组成。OPENXML 语句从 XML 文档中检索三列行集(oid、date和amount)中的订单信息。
首先调用sp_xml_preparedocument以获得文档句柄。此文档句柄传递到 OPENXML。
在 OPENXML 语句中:
- rowpattern(/root/Customer/Order) 标识要处理的 <Order> 节点。
- 在 WITH 子句中没有SchemaDeclaration。相反,指定了一个表名。因此,表架构用作行集架构。
- flags参数值设置为1表示attribute-centric映射。因此,rowpattern所标识的元素特性映射到具有相同名称的行集列。
SELECT 语句于是检索 OPENXML 所提供的行集中的所有列。
-- Create a test table. This table schema is used by OPENXML as the
-- rowset schema.
CREATE TABLE T1(oid char(5), date datetime, amount float)
DECLARE @idoc int
DECLARE @doc varchar(1000)
-- Sample XML document
SET @doc ='
<root>
<Customer cid= "C1" name="Janine" city="Issaquah">
<Order oid="O1" date="1/20/1996" amount="3.5" />
<Order oid="O2" date="4/30/1997" amount="13.4">Customer was very
satisfied</Order>
</Customer>
<Customer cid="C2" name="Ursula" city="Oelde" >
<Order oid="O3" date="7/14/1999" amount="100" note="Wrap it blue
white red">
<Urgency>Important</Urgency>
</Order>
<Order oid="O4" date="1/20/1996" amount="10000"/>
</Customer>
</root>
'
--Create an internal representation of the XML document.
EXEC sp_xml_preparedocument @idoc OUTPUT, @doc
-- Execute a SELECT statement using OPENXML rowset provider.
SELECT *
FROM OPENXML (@idoc, '/root/Customer/Order', 1)
WITH T1
EXEC sp_xml_removedocument @idoc
结果如下:
oid date amount
----- --------------------------- ----------
O1 1996-01-20 00:00:00.000 3.5
O2 1997-04-30 00:00:00.000 13.4
O3 1999-07-14 00:00:00.000 100.0
O4 1996-01-20 00:00:00.000 10000.0
F. 获得边缘表格式的结果
在下例中,在 OPENXML 语句中未指定 WITH 子句。因此,OPENXML 所生成的行集具有边缘表格式。SELECT 语句返回边缘表中的所有列。
下例中的示例 XML 文档由 <Customer>、<Order> 和 <OrderDetail> 元素组成。
首先调用sp_xml_preparedocument以获得文档句柄。此文档句柄传递到 OPENXML。
在 OPENXML 语句中:
- rowpattern(/ROOT/Customer) 标识要处理的 <Customer> 节点。
- 没有提供 WITH 子句,因此 OPENXML 返回边缘表格式的行集。
SELECT 语句于是检索边缘表中的所有列。
DECLARE @idoc int
DECLARE @doc varchar(1000)
SET @doc ='
<ROOT>
<Customer CustomerID="VINET" ContactName="Paul Henriot">
<Order CustomerID="VINET" EmployeeID="5" OrderDate=
"1996-07-04T00:00:00">
<OrderDetail OrderID="10248" ProductID="11" Quantity="12"/>
<OrderDetail OrderID="10248" ProductID="42" Quantity="10"/>
</Order>
</Customer>
<Customer CustomerID="LILAS" ContactName="Carlos Gonzlez">
<Order CustomerID="LILAS" EmployeeID="3" OrderDate=
"1996-08-16T00:00:00">
<OrderDetail OrderID="10283" ProductID="72" Quantity="3"/>
</Order>
</Customer>
</ROOT>'
--Create an internal representation of the XML document.
EXEC sp_xml_preparedocument @idoc OUTPUT, @doc
-- Execute a SELECT statement using OPENXML rowset provider.
SELECT *
FROM OPENXML (@idoc, '/ROOT/Customer')
EXEC sp_xml_removedocument @idoc
结果作为边缘表返回。可以对边缘表编写查询以获得信息。
- 下面的查询返回文档中的Customer节点数。因为未指定 WITH 子句,所以 OPENXML 返回边缘表。SELECT 语句查询此边缘表。
SELECT count(*)
FROM OPENXML(@idoc, '/')
WHERE localname = 'Customer'
- 下面的查询返回元素类型的 XML 节点的本地名称。
SELECT distinct localname
FROM OPENXML(@idoc, '/')
WHERE nodetype = 1
ORDER BY localname
G. 指定以特性结束的rowpattern
下例中的 XML 文档由 <Customer>、<Order> 和 <OrderDetail> 元素组成。OPENXML 语句从 XML 文档中检索三列行集(ProductIDProductID、Quantity和OrderID)中的订单详情。
首先调用sp_xml_preparedocument以获得文档句柄。此文档句柄传递到 OPENXML。
在 OPENXML 语句中:
- rowpattern(/ROOT/Customer/Order/OrderDetail/@ProductID) 以 XML 特性 (ProductID) 结束。在所得到的行集中,为在 XML 文档中选定的每个特性节点都创建一行。
- 在下例中未指定flags参数。相反,由ColPattern参数指定映射。
在SchemaDeclaration(在 WITH 子句内)中,也用ColName和ColType参数指定ColPattern。可选的ColPattern是指定的 XPath 模式,用以表示:
- 在行集中为ProdID列指定的ColPattern的 XPath 模式 (.) 标识上下文节点(当前节点)。按照指定的rowpattern,它是 <OrderDetail> 元素的ProductID特性。
- 在行集中为Qty列指定的ColPattern,../@Quantity标识上下文节点 (<ProductID>) 的父节点 (<OrderDetail>) 的Quantity特性。
- 同样,在行集中为OID列指定的ColPattern,../../@OrderID标识上下文节点 (<OrderDetail>) 的父节点 (<Order>) 的OrderID特性。
然后 SELECT 语句检索 OPENXML 所提供的行集中的所有列。
DECLARE @idoc int
DECLARE @doc varchar(1000)
--Sample XML document
SET @doc ='
<ROOT>
<Customer CustomerID="VINET" ContactName="Paul Henriot">
<Order OrderID="10248" CustomerID="VINET" EmployeeID="5" OrderDate=
"1996-07-04T00:00:00">
<OrderDetail ProductID="11" Quantity="12"/>
<OrderDetail ProductID="42" Quantity="10"/>
</Order>
</Customer>
<Customer CustomerID="LILAS" ContactName="Carlos Gonzlez">
<Order OrderID="10283" CustomerID="LILAS" EmployeeID="3" OrderDate=
"1996-08-16T00:00:00">
<OrderDetail ProductID="72" Quantity="3"/>
</Order>
</Customer>
</ROOT>'
-- Create an internal representation of the XML document.
EXEC sp_xml_preparedocument @idoc OUTPUT, @doc
-- Execute a SELECT stmt using OPENXML rowset provider.
SELECT *
FROM OPENXML (@idoc, '/ROOT/Customer/Order/OrderDetail/@ProductID')
WITH ( ProdID int '.',
Qty int '../@Quantity',
OID int '../../@OrderID')
EXEC sp_xml_removedocument @idoc
结果如下:
ProdID Qty OID
----------- ----------- -------
11 12 10248
42 10 10248
72 3 10283
H. 指定有多个文本节点的 XML 文档
如果在 XML 文档中有多个文本节点,则含有ColPattern(text()) 的 SELECT 语句只返回第一个文本节点,而不是返回所有节点。例如:
DECLARE @h int
EXEC sp_xml_preparedocument @h OUTPUT,
N'
<root xmlns:a="urn:1">
<a:Elem abar="asdf">
T<a>a</a>U
</a:Elem>
</root>',
'<ns xmlns:b="urn:1" />'
SELECT * FROM openxml(@h, '/root/b:Elem')
WITH (Col1 varchar(20) 'text()')
SELECT 语句返回T作为结果(不是TaU)。
I. 从多值特性中检索单值
XML 文档会含有多值特性。例如IDREFS可为多值特性。在 XML 文档内,多值特性值被指定为由用空格隔开的值组成的字符串。在下列 XML 文档内,<Student> 元素的attends特性与 <Class> 的attendedBy特性都是多值特性。从多值 XML 属性中检索单值并将每个值存储到数据库中的不同行中,这要求额外的工作。下例显示了此过程。
该 XML 示例文档由以下元素组成:
<Student> 内的attends特性和 <Class> 内的attendedBy特性表示Student表与Class表之间的一种m:n关系。一个学生可在很多班上课,而一个班也可有很多学生。
假设希望拆分该文档,并将它以下列形式保存到数据库中:
- 将 <Student> 数据保存到Students表中。
- 将 <Class> 数据保存到Courses表中。
- 将m:n关系数据(在 Student 与 Class之间)保存到CourseAttendence表中。析取这些值需要做额外的工作。若要检索该信息并将其存储到表中,请使用下列存储过程:
以下是具体步骤:
- 创建下表:
DROP TABLE CourseAttendance
DROP TABLE Students
DROP TABLE Courses
GO
CREATE TABLE Students(
id varchar(5) primary key,
name varchar(30)
)
GO
CREATE TABLE Courses(
id varchar(5) primary key,
name varchar(30),
taughtBy varchar(5)
)
GO
CREATE TABLE CourseAttendance(
id varchar(5) references Courses(id),
attendedBy varchar(5) references Students(id),
constraint CourseAttendance_PK primary key (id, attendedBy)
)
go
- 创建下列存储过程:
DROP PROCEDURE f_idrefs
GO
CREATE PROCEDURE f_idrefs
@t varchar(500),
@idtab varchar(50),
@id varchar(5)
AS
DECLARE @sp int
DECLARE @att varchar(5)
SET @sp = 0
WHILE (LEN(@t) > 0)
BEGIN
SET @sp = CHARINDEX(' ', @t+ ' ')
SET @att = LEFT(@t, @sp-1)
EXEC('INSERT INTO '+@idtab+' VALUES ('''+@id+''', '''+@att+''')')
SET @t = SUBSTRING(@t+ ' ', @sp+1, LEN(@t)+1-@sp)
END
Go
DROP PROCEDURE fill_idrefs
GO
CREATE PROCEDURE fill_idrefs
@xmldoc int,
@xpath varchar(100),
@from varchar(50),
@to varchar(50),
@idtable varchar(100)
AS
DECLARE @t varchar(500)
DECLARE @id varchar(5)
/* Temporary Edge table */
SELECT *
INTO #TempEdge
FROM OPENXML(@xmldoc, @xpath)
DECLARE fillidrefs_cursor CURSOR FOR
SELECT CAST(iv.text AS nvarchar(200)) AS id,
CAST(av.text AS nvarchar(4000)) AS refs
FROM #TempEdge c, #TempEdge i,
#TempEdge iv, #TempEdge a, #TempEdge av
WHERE c.id = i.parentid
AND UPPER(i.localname) = UPPER(@from)
AND i.id = iv.parentid
AND c.id = a.parentid
AND UPPER(a.localname) = UPPER(@to)
AND a.id = av.parentid
OPEN fillidrefs_cursor
FETCH NEXT FROM fillidrefs_cursor INTO @id, @t
WHILE (@@FETCH_STATUS <> -1)
BEGIN
IF (@@FETCH_STATUS <> -2)
BEGIN
execute f_idrefs @t, @idtable, @id
END
FETCH NEXT FROM fillidrefs_cursor INTO @id, @t
END
CLOSE fillidrefs_cursor
DEALLOCATE fillidrefs_cursor
Go
- 这是已拆分的示例文档,已将数据存储到前面提到的表中。
DECLARE @h int
EXECUTE sp_xml_preparedocument @h OUTPUT, '
<Data>
<Student id = "s1" name = "Student1" attends = "c1 c3 c6" />
<Student id = "s2" name = "Student2" attends = "c2 c4" />
<Student id = "s3" name = "Student3" attends = "c2 c4 c6" />
<Student id = "s4" name = "Student4" attends = "c1 c3 c5" />
<Student id = "s5" name = "Student5" attends = "c1 c3 c5 c6" />
<Student id = "s6" name = "Student6" />
<Class id = "c1" name = "Intro to Programming"
attendedBy = "s1 s4 s5" />
<Class id = "c2" name = "Databases"
attendedBy = "s2 s3" />
<Class id = "c3" name = "Operating Systems"
attendedBy = "s1 s4 s5" />
<Class id = "c4" name = "Networks" attendedBy = "s2 s3" />
<Class id = "c5" name = "Algorithms and Graphs"
attendedBy = "s4 s5"/>
<Class id = "c6" name = "Power and Pragmatism"
attendedBy = "s1 s3 s5" />
</Data>'
INSERT INTO Students SELECT * FROM OPENXML(@h, '//Student') WITH Students
INSERT INTO Courses SELECT * FROM OPENXML(@h, '//Class') WITH Courses
/* Using the edge table */
EXECUTE fill_idrefs @h, '//Class', 'id', 'attendedby', 'CourseAttendance'
SELECT * FROM Students
SELECT * FROM Courses
SELECT * FROM CourseAttendance
EXECUTE sp_xml_removedocument @h