I've decided to kick this blog off with a double-feature. In the last post I gave an example of shredding XML query plans with the nodes() method. In this one we'll discuss the nodes() method in a little more detail.
In a previous post on the Pseudo-Random blog, I recommended that everyone who's still using OPENXML should switch over to the xml data type's nodes() method. The problems I mentioned included:
I don't want to use up this entire blog entry complaining about OPENXML, so I'll cut it short here. From the above you get the idea that OPENXML is an inferior method of shredding XML data. So what's the alternative? Glad you asked. The xml data type includes several built-in methods, including one method designed just for shredding XML data: the nodes() method. Basically this method works like this:
The sample query below demonstrates the nodes() method. In the sample we shred the XML document into relational rows, and query the context node ('.') to return each relational row.
DECLARE @xml XML;-- Character representation of the XMLSET @xml = '<capitals> <state name="Alabama" abbreviation="AL" capital="Montgomery" /> <state name="Alaska" abbreviation="AK" capital="Juneau" /> <state name="Arizona" abbreviation="AZ" capital="Phoenix" /></capitals>';-- Retrieve each individual node from the relational result setSELECT Node.query('.')FROM @xml.nodes('/capitals/state') TempXML (Node);
Once the xml data type instance is shredded into relational rows of the xml data type, you can use the other xml data type methods like query() and value() to extract nodes and scalar values from the rows. As I previously said, the xml rows returned by the nodes() method are restricted in their functionality. You can't cast them to other data types; you can only use the xml data type methods on them to extract their contents. We can use the value() method in our example to extract each state's name, abbreviation, and capital from the nodes() result set, as shown below.
DECLARE @xml XML;-- Character representation of the XMLSET @xml = '<capitals> <state name="Alabama" abbreviation="AL" capital="Montgomery" /> <state name="Alaska" abbreviation="AK" capital="Juneau" /> <state name="Arizona" abbreviation="AZ" capital="Phoenix" /></capitals>';-- Retrieve scalar values from the relational result setSELECT Node.value('@name', 'varchar(100)') AS Name, Node.value('@abbreviation', 'varchar(2)') AS Abbreviation, Node.value('@capital', 'varchar(100)') AS CapitalFROM @xml.nodes('/capitals/state') TempXML (Node);
As you can see, this syntax is fairly intuitive, especially when compared to the equivalent OPENXML syntax. The results are shown below.
In the next post we'll talk about loading XML data from files from the file system directly into SQL Server.