Explicit
The EXPLICIT directive of the FOR XML
clause is the most powerful of the directives and provides the most
control over the resulting structure of the XML. It is, however, the
most difficult to figure out and understand simply because it is so
complicated.
The EXPLICIT directive requires two columns in each row: Tag and Parent. The resulting data should be structured in a way that represents a hierarchical relationship between the Tag rows and the Parent rows.
Because of the complexity of the EXPLICIT directive, SQL Server 2005 introduced the PATH directive, which provides the same control over resulting XML without the headache of the syntax. Thus, you can bypass the EXPLICIT directive and go straight to the PATH directive. If you would like more information using the EXPLICIT directive, you can find information at http://msdn.microsoft.com/en-us/library/ms189068.aspx.
Path
The PATH directive was introduced in SQL Server 2005 as an alternative over the EXPLICIT directive. The PATH directive is just as powerful as the EXPLICIT directive, but it is as simple to use as the AUTO and RAW directives.
On the surface, the PATH
directive may not seem powerful, but it shines and shows its supremacy
when dealing with more complex XML structures, such as in working with
a multilevel hierarchy.
The following is an example of how easy the PATH directive is used with several levels of hierarchy.
SELECT
o.OrderNumber AS ‘@OrderNumber',
c.Name AS ‘Customer/@Name',
i.ItemNumber AS ‘LineItems/Item/@ItemNo',
od.Quantity AS ‘LineItems/Item/@Qty'
FROM Orders o
INNER JOIN Customer c on o.customerID = c.customerid
INNER JOIN OrderDetail od on od.OrderID = o.OrderID
INNER JOIN Item i on i.ItemID = od.ItemID
FOR XML PATH('Order'), ROOT('Orders')
You can see in the query how easy it is to
specify the values are attributes while including multiple joins and
the resulting XML.
/*
<Orders>
<Order OrderNumber="10001">
<Customer Name="Scott" />
<LineItems>
<Item ItemNo="V001" Qty="1" />
</LineItems>
</Order>
<Order OrderNumber="10002">
<Customer Name="Adam" />
<LineItems>
<Item ItemNo="A017" Qty="1" />
</LineItems>
</Order>
<Order OrderNumber="10001">
<Customer Name="Scott" />
<LineItems>
<Item ItemNo="V001" Qty="5" />
</LineItems>
</Order>
<Order OrderNumber="10002">
<Customer Name="Adam" />
<LineItems>
<Item ItemNo="P002" Qty="2" />
</LineItems> </Order>
</Orders>
/*
To produce these same results using the EXPLICIT directive would have taken three times the amount of code. The power of the PATH directive comes from the ability to generate deep hierarchies based on simply the column name. For example, the column name LineItems/Item/@Qty creates an Item element with a Qty attribute under the LineItems element.
The PATH
directive also supports a number of special characters to produce
different XML formatting requirements. For example, you can create
elements that have a text value as well as attributes simply by naming
a column with an asterisk (*):
SELECT CustomerID AS ‘@customerid', OrderNumber AS ‘*'
FROM Orders
FOR XML PATH('Order'), ROOT('Orders')
/*
<Orders>
<Order customerid="1">10001</Order>
<Order customerid="2">10002</Order>
<Order customerid="1">10003</Order>
<Order customerid="2">10004</Order>
</Orders>
*/
Similar results can be achieved by using special column name indicators such as data() and text(). For example, you can use the data() indicator to create a list of values separated by spaces. They key here is to make the PATH name empty.
SELECT ItemNumber AS ‘data()'
FROM Item
FOR XML PATH(''), ROOT('Items')
/*
<Items>V001 A017 P002</Items>
*/
The text() indicator can produce a similar string but without spaces (also using an empty PATH name).
SELECT ItemNumber AS ‘text()'
FROM Item
FOR XML PATH(''), ROOT('Items')
/*
<Items>V001A017P002</Items>
*/
Lastly, you can add comments to your XML by applying the comments() indicator; although you still need to use the FOR XML PATH directive:
SELECT ‘Order Number' AS ‘comment()',
OrderNumber,
'CustomerID' AS ‘comment()',
CustomerID
FROM Orders WHERE OrderID = 1
FOR XML PATH(''), ROOT
/*
<Items>V001A017P002</Items>
<root>
<!--Order Number-->
<OrderNumber>10001</OrderNumber>
<!--CustomerID-->
<CustomerID>1</CustomerID>
</root>
*/