sql OPENXML()在SQL Server中粉碎XML的方法
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了sql OPENXML()在SQL Server中粉碎XML的方法相关的知识,希望对你有一定的参考价值。
/*
The OPENXML function allows you to shred XML and return it as scalar (relational) data.
It allows you to start with XML like this:
<?xml version="1.0" encoding="ISO-8859-1"?>
<order id="123456" date="2015-01-01">
<salesperson id="123">
<name>Naomi Sharp</name>
</salesperson>
<customer id="921">
<name>Dan Drayton</name>
</customer>
<items>
<item id="268" quantity="2"/>
<item id="561" quantity="1"/>
<item id="127" quantity="2"/>
</items>
</order>
and query the XML to end up with scalar (relational) data like this:
orderid id quantity
123456 268 2
123456 561 1
123456 127 2
The format is OPENXML(handle created by sp_xml_preparedocument, the conext node, and the flag), such as OPENXML(@docHandle, 'order', 1).
Details of the OPENXML arguments:
- the handle is a variable that you create as an output element using sp_xml_prepare document
- the context node is the node (located by the XPath) that the function will start from when querying
- the flag is a number that tells it what you're querying for (apparently you can query outside of the scope flag if you specific a different XPath). The values:
0: attribute-centric (I want to query attributes)
1: attribute-centric (I want to query attributes)
2: element-centric (I want to query elements)
3 (1+2): attributes and elements (I want to query attributes and elements)
There are four steps to using OPENXML to shred XML in SQL Server:
1. start by declaring a VARCHAR variable (not an XML variable) and place the XML code into the variable as a VARCHAR string
2. use sp_xml_preparedocument to create a handle for the in-memory node-tree that the XML will be loaded into. The handle will be called @docHandle
3. use OPENXML() to tell it what you want to query into scalar data
4. use sp_xml_removedocument to release the node tree from memory
*/
-- An example of OPENXML in use
SELECT * FROM OPENXML(@docHandle, 'order', 1)
WITH (id INT,
date DATE,
customer varchar(25) 'customer/name');
-- DETAIL of the OPENXML example
-- SELECT * FROM OPENXML, with the arguments @docHandle (the handle of the node in the form of a variable), 'order' (start querying from the order element), and flag = 1 (I want to query attributes)
SELECT * FROM OPENXML(@docHandle, 'order', 1)
-- WITH tells it what columns you want to return
WITH (
-- id will pull the id attribute from the order element, and return it as an integer
id INT,
-- date will pull the date attribute from the order element, and return it as a date
date DATE,
-- customer will pull the name element as located in the XPath 'order/customer/name' - note two things: the XPath is only needed if you're going outside of the context node (order is the context node, but from there you're going down one element level to customer, and then down another element level to name), and you're pulling an element even though you set the flag to 1 (I want attributes) - you're apparently allowed to go outside of the scope of the flag if you explicitly spell it out in the XPath
customer varchar(25) 'customer/name'
);
-----------------------------------------------------------------
-- EXAMPLE OF ENTIRE PROCESS (all processed in a single batch) --
-----------------------------------------------------------------
-- 1. start by declaring a VARCHAR variable (not an XML variable) and place the following XML into the variable.
DECLARE @x VARCHAR(max);
SET @x = '<?xml version="1.0" encoding="ISO-8859-1"?>
<order id="123456" date="2015-01-01">
<salesperson id="123">
<name>Naomi Sharp</name>
</salesperson>
<customer id="921">
<name>Dan Drayton</name>
</customer>
<items>
<item id="268" quantity="2"/>
<item id="561" quantity="1"/>
<item id="127" quantity="2"/>
</items>
</order>';
-- 2. use sp_xml_preparedocument to create a handle for the in-memory node-tree that the XML will be loaded into. The handle will be called @docHandle
DECLARE @docHandle INT;
EXEC sp_xml_preparedocument @docHandle OUTPUT, @x;
-- 3A. Query example A - query @docHandle using OPENXML function, starting at 'order' node, looking for just attributes of 'order' node. The three columns we return will be the id attribute, the date attribute, and the customer element (using the XPath 'customer/name' you tell it to grab the element)
SELECT * FROM OPENXML(@docHandle, 'order', 1)
WITH (id INT,
date DATE,
customer varchar(25) 'customer/name');
/* Result from query example A:
id date customer
1234562 015-01-01 Dan Drayton
*/
-- 3B. Query example B - query @docHandle using OPENXML function, starting at 'order/items/item' node, looking for just attributes of 'order' node. The orderid column actually goes two level back up from the context node 'order/items/item', as indicated by the '../..'. it then pulls the id attribute and quantity attribute from the context node 'order/items/item'.
SELECT * FROM OPENXML(@docHandle, 'order/items/item', 1)
WITH (orderid INT '../../@id',
id INT,
quantity INT);
/*Result from query example B:
orderid id quantity
123456 268 2
123456 561 1
123456 127 2
*/
-- 3C. Query example C - query @docHandle using OPENXML function, starting at 'order/salesperson' node, looking for both attributes and elements as indicated by the 3. The columns pulled will be the id attribute as well as the name element
SELECT * FROM OPENXML(@docHandle, 'order/salesperson', 3)
WITH (id INT,
name VARCHAR(25));
/*Result from query example C:
orderid id quantity
123456 268 2
123456 561 1
123456 127 2
*/
-- 4. use sp_xml_removedocument to release the node tree from memory
EXEC sp_xml_removedocument @docHandle;
--------------------------------------
-- Using OPENXML() with a namespace --
--------------------------------------
-- if your XML document uses a namespace, you can include that with OPENXML()
-- you can specify a namespace and prefix in sp_xml_preparedocument
EXEC sp_xml_preparedocument @docHandle OUTPUT, @xml,
'root xmlns:asw="http://aw/order"/>';
-- you can also prefix a namespace in row and column patterns
SELECT * FROM OPENXML(@docHandle, 'awo:order', 1)
WITH (id INT,
date DATE,
customer VARCHAR(25) 'awo:customer/awo:name');
-- entire procedure using a namespace
DECLARE @x VARCHAR(max);
SET @x = '<?xml version="1.0" encoding="ISO-8859-1"?>
<!-- root order attribute has namespace aw/order -->
<order xmlns="http://aw/order" id="123456" date="2015-01-01">
<salesperson id="123">
<name>Naomi Sharp</name>
</salesperson>
<customer id="921">
<name>Dan Drayton</name>
</customer>
<items>
<item id="268" quantity="2"/>
<item id="561" quantity="1"/>
<item id="127" quantity="2"/>
</items>
</order>';
--how to specify the namespace in sp_xml_preparedocument
DECLARE @docHandle INT;
-- root is an arbitraty element name, and putting awo in front of the namespace gives it an alias, a way to reduce having to spell out the entire namespace each time
EXEC sp_xml_preparedocument @docHandle OUTPUT, @x, '<root xmlns:awo="http://aw/order"/>'
-- use OPENXML with the namespace. In this case, 'awo' tells it to use the order element from the awo aliased namespace used in sp_xml_preparedocument, which in this case was "http://aw/order"
SELECT * FROM OPENXML(@docHandle, '
awo:order', 1)
WITH (id INT,
date DATE,
-- specifies specific path, in this case, go to 'awo' customer element, then down to 'awo' name element
customer VARCHAR(25) 'awo:customer/awo:name');
-- remove the node from memory
EXEC sp_xml_removedocument @docHandle;
-------------------------------------------------------------
-- CREATING AN EDGE TABLE SHOWING METADATA ABOUT XML NODES --
-------------------------------------------------------------
-- by using OPENXML without a flag (the number as the last argument), you can bring back a so-called edge table, which is tabular representation of the node tree and the metadata represented within the data - this shows the structure of the XML data, as well as the data contained within it.
SELECT * FROM OPENXML(@docHandle, 'order');
-- full example of getting an edge table by omitting the flag argument and the WITH clause
DECLARE @x VARCHAR(max);
SET @x = '<?xml version="1.0" encoding="ISO-8859-1"?>
<order id="123456" date="2015-01-01">
<salesperson id="123">
<name>Naomi Sharp</name>
</salesperson>
<customer id="921">
<name>Dan Drayton</name>
</customer>
<items>
<item id="268" quantity="2"/>
<item id="561" quantity="1"/>
<item id="127" quantity="2"/>
</items>
</order>';
DECLARE @docHandle INT;
EXEC sp_xml_preparedocument @docHandle OUTPUT, @x;
-- note how there's no flag number or a WITH clause
SELECT * FROM OPENXML(@docHandle, 'order')
/* Resulting edge table of metadata:
id parentid nodetype localname prefix namespaceuri datatype prev text
0 NULL 1 order NULL NULL NULL 1 NULL
5 0 2 id NULL NULL NULL NULL NULL
23 5 3 #text NULL NULL NULL NULL 123456
6 0 2 date NULL NULL NULL NULL NULL
24 6 3 #text NULL NULL NULL NULL 2015-01-01
7 0 1 salesperson NULL NULL NULL NULL NULL
8 7 2 id NULL NULL NULL NULL NULL
25 8 3 #text NULL NULL NULL NULL 123
9 7 1 name NULL NULL NULL NULL NULL
26 9 3 #text NULL NULL NULL NULL Naomi Sharp
10 0 1 customer NULL NULL NULL 7 NULL
11 10 2 id NULL NULL NULL NULL NULL
27 11 3 #text NULL NULL NULL NULL 921
12 10 1 name NULL NULL NULL NULL NULL
28 12 3 #text NULL NULL NULL NULL Dan Drayton
13 0 1 items NULL NULL NULL 10 NULL
14 13 1 item NULL NULL NULL NULL NULL
15 14 2 id NULL NULL NULL NULL NULL
29 15 3 #text NULL NULL NULL NULL 268
16 14 2 quantity NULL NULL NULL NULL NULL
30 16 3 #text NULL NULL NULL NULL 2
17 13 1 item NULL NULL NULL 14 NULL
18 17 2 id NULL NULL NULL NULL NULL
31 18 3 #text NULL NULL NULL NULL 561
19 17 2 quantity NULL NULL NULL NULL NULL
32 19 3 #text NULL NULL NULL NULL 1
20 13 1 item NULL NULL NULL 17 NULL
21 20 2 id NULL NULL NULL NULL NULL
33 21 3 #text NULL NULL NULL NULL 127
22 20 2 quantity NULL NULL NULL NULL NULL
34 22 3 #text NULL NULL NULL NULL 2
*/
以上是关于sql OPENXML()在SQL Server中粉碎XML的方法的主要内容,如果未能解决你的问题,请参考以下文章