The openxml procedure is used in the FROM clause of a query to generate a result set from an XML document. openxml uses a subset of the XPath query language to select nodes from an XML document.
When you use openxml, the XML document is parsed and the result is modeled as a tree. The tree is made up of nodes. XPath expressions are used to select nodes in the tree. The following list describes some commonly-used XPath expressions:
/ indicates the root node of the XML document
// indicates all descendants of the root, including the root node
. (single period) indicates the current node of the XML document
.// indicates all descendants of the current node, including the current node
.. indicates the parent node of the current node
./@attributename indicates the attribute of the current node having the name attributename
./childname indicates the children of the current node that are elements having the name childname
Consider the following XML document:
<inventory> <product ID="301" size="Medium">Tee Shirt <quantity>54</quantity> </product> <product ID="302" size="One Size fits all">Tee Shirt <quantity>75</quantity> </product> <product ID="400" size="One Size fits all">Baseball Cap <quantity>112</quantity> </product> </inventory> |
The <inventory> element is the root node. You can refer to it using the following XPath expression:
/inventory |
Suppose that the current node is a <quantity> element. You can refer to this node using the following XPath expression:
. |
To find all the <product> elements that are children of the <inventory> element, use the following XPath expression:
/inventory/product |
If the current node is a <product> element and you want to refer to the size attribute, use the following XPath expression:
./@size |
For information about the XPath query language, see http://www.w3.org/TR/xpath.
Each match for the first xpath-query argument to openxml generates one row in the result set. The WITH clause specifies the schema of the result set and how the value is found for each column in the result set. For example, consider the following query:
SELECT * FROM openxml( '<inventory> <product>Tee Shirt <quantity>54</quantity> <color>Orange</color> </product> <product>Baseball Cap <quantity>112</quantity> <color>Black</color> </product> </inventory>', '/inventory/product' ) WITH ( Name CHAR (25) './text()', Quantity CHAR(3) 'quantity', Color CHAR(20) 'color'); |
The first xpath-query argument is /inventory/product, and there are two <product> elements in the XML, so two rows are generated by this query.
The WITH clause specifies that there are three columns: Name, Quantity, and Color. The values for these columns are taken from the <product>, <quantity> and <color> elements. The query above generates the following result:
Name | Quantity | Color |
---|---|---|
Tee Shirt | 54 | Orange |
Baseball Cap | 112 | Black |
The openxml procedure can be used to generate an edge table, a table that contains a row for every element in the XML document. You may want to generate an edge table so that you can query the data in the result set using SQL.
The following SQL statements create a table that contains a single XML document. The XML generated by the query has a root element called <root>, which is generated using the XMLELEMENT function, and elements are generated for each specified column in the Employees, SalesOrders, and Customers tables using FOR XML AUTO with the ELEMENTS modifier.
CREATE TABLE IF NOT EXISTS xmldata (xmldoc XML); INSERT INTO xmldata WITH AUTO NAME SELECT XMLELEMENT( NAME root, (SELECT EmployeeID, Employees.GivenName, Employees.Surname, Customers.ID, Customers.GivenName, Customers.Surname, Customers.Phone, CompanyName, SalesOrders.ID, OrderDate, Region FROM Employees KEY JOIN SalesOrders KEY JOIN Customers ORDER BY EmployeeID, Customers.ID, SalesOrders.ID FOR XML AUTO, ELEMENTS)) AS xmldoc; SELECT xmldoc FROM xmldata; |
The generated XML looks as follows (the result has been formatted to make it easier to read—the result returned by the query is one continuous string):
<root> <Employees> <EmployeeID>129</EmployeeID> <GivenName>Philip</GivenName> <Surname>Chin</Surname> <Customers> <ID>101</ID> <GivenName>Michaels</GivenName> <Surname>Devlin</Surname> <Phone>2015558966</Phone> <CompanyName>The Power Group</CompanyName> <SalesOrders> <ID>2560</ID> <OrderDate>2001-03-16</OrderDate> <Region>Eastern</Region> </SalesOrders> </Customers> <Customers> <ID>103</ID> <GivenName>Erin</GivenName> <Surname>Niedringhaus</Surname> <Phone>2155556513</Phone> <CompanyName>Darling Associates</CompanyName> <SalesOrders> <ID>2451</ID> <OrderDate>2000-12-15</OrderDate> <Region>Eastern</Region> </SalesOrders> </Customers> <Customers> <ID>104</ID> <GivenName>Meghan</GivenName> <Surname>Mason</Surname> <Phone>6155555463</Phone> <CompanyName>P.S.C.</CompanyName> <SalesOrders> <ID>2331</ID> <OrderDate>2000-09-17</OrderDate> <Region>South</Region> </SalesOrders> <SalesOrders> <ID>2342</ID> <OrderDate>2000-09-28</OrderDate> <Region>South</Region> </SalesOrders> </Customers> ... </Employees> ... <Employees> ... </Employees> </root> |
The following query uses the descendant-or-self (//*) XPath expression to match every element in the above XML document, and for each element the id metaproperty is used to obtain an ID for the node, and the parent (../) XPath expression is used with the ID metaproperty to get the parent node. The localname metaproperty is used to obtain the name of each element. Metaproperty names are case sensitive, so ID or LOCALNAME cannot be used as metaproperty names.
CREATE OR REPLACE VARIABLE x XML; SELECT xmldoc INTO x FROM xmldata; SELECT * FROM openxml( x, '//*' ) WITH (ID INT '@mp:id', parent INT '../@mp:id', name CHAR(25) '@mp:localname', text LONG VARCHAR 'text()' ) ORDER BY ID; |
The result set generated by this query shows the ID of each node, the ID of the parent node, and the name and content for each element in the XML document.
ID | parent | name | text |
---|---|---|---|
5 | (NULL) | root | (NULL) |
16 | 5 | Employees | (NULL) |
28 | 16 | EmployeeID | 129 |
55 | 16 | GivenName | Phillip |
82 | 16 | Surname | Chin |
... | ... | ... | ... |
So far, XML that was generated with a procedure like XMLELEMENT has been used. You can also read XML from a file and parse it using the xp_read_file procedure. Suppose the file c:\temp\inventory.xml was written using the query below.
SELECT xp_write_file( 'c:\\temp\\inventory.xml', '<inventory> <product>Tee Shirt <quantity>54</quantity> <color>Orange</color> </product> <product>Baseball Cap <quantity>112</quantity> <color>Black</color> </product> </inventory>' ); |
You can use the following statement to read and parse the XML in the file:
SELECT * FROM openxml( xp_read_file( 'c:\\temp\\inventory.xml' ), '//*' ) WITH (ID INT '@mp:id', parent INT '../@mp:id', name CHAR(128) '@mp:localname', text LONG VARCHAR 'text()' ) ORDER BY ID; |
If you have a table with a column that contains XML, you can use openxml to query all the XML values in the column at once. This can be done using a lateral derived table.
The following statements create a table with two columns, ManagerID and Reports. The Reports column contains XML data generated from the Employees table.
CREATE TABLE IF NOT EXISTS xmltest (ManagerID INT, Reports XML); INSERT INTO xmltest SELECT ManagerID, XMLELEMENT( NAME reports, XMLAGG( XMLELEMENT( NAME e, EmployeeID))) FROM Employees GROUP BY ManagerID; |
Execute the following query to view the data in the test table:
SELECT * FROM xmltest ORDER BY ManagerID; |
This query produces the following result:
ManagerID | Reports | ||
---|---|---|---|
501 |
|
||
703 |
|
||
902 |
|
||
1293 |
|
||
... | ... |
The following query uses a lateral derived table to generate a result set with two columns: one that lists the ID for each manager, and one that lists the ID for each employee that reports to that manager:
SELECT ManagerID, EmployeeID FROM xmltest, LATERAL( openxml( xmltest.Reports, '//e' ) WITH (EmployeeID INT '.') ) DerivedTable ORDER BY ManagerID, EmployeeID; |
This query generates the following result:
ManagerID | EmployeeID |
---|---|
501 | 102 |
501 | 105 |
501 | 160 |
501 | 243 |
... | ... |
Discuss this page in DocCommentXchange.
|
Copyright © 2012, iAnywhere Solutions, Inc. - SQL Anywhere 12.0.1 |