XML RAW, ELEMENTS and ROOT – Basic Examples

29 Apr

Introduction

Most systems that I have worked with make use of the XML data type. I don’t find it to be the most intuitive data type to work with but most aspects of it can be built upon from a few basic examples. This will be part of a developing series that will cover XML and JSON.

Background

The eXtensible Markup Language (XML) is a way of defining data and the relationship with other data in one ‘document’. The XML data type was introduced into SQL Server with version 2005. Prior to that, the VARCHAR or TEXT data types were used for storing such data and it wasn’t a friendly process.

With the advent of the XML data type a slew of properties and functions were introduced and developed over the following years, to help with the generation and manipulation of such data.

One of the more basic ways of generating XML from SQL Server data is by using XML RAW.

Test Environment

Create a simple test database with data.

Listing 1: Create Initial Test Database and Data

CREATE DATABASE XML_Sandpit;
GO

USE XML_Sandpit;
GO

CREATE TABLE dbo.Region(
ID INT NOT NULL,
Area VARCHAR(20) NOT NULL,
Notes VARCHAR(50) NULL
);
GO

INSERT INTO dbo.Region(ID, Area, Notes)
VALUES(1, 'North', 'Northern Area'),
(2, 'South', 'Southern Area'),
(3, 'East', 'Eastern Area'),
(4, 'West', 'Western Area');
GO

CREATE TABLE dbo.Warehouse(
ID INT NOT NULL,
Region INT NOT NULL,
[Name] VARCHAR(50) NOT NULL
);
GO

INSERT INTO dbo.Warehouse(ID, Region, [Name])
VALUES(1, 1, 'North Warehouse 1'),
(2, 1, 'North Warehouse 2'),
(3, 2, 'South Warehouse 1'),
(4, 2, 'South Warehouse 2'),
(5, 3, 'East Warehouse 1'),
(6, 3, 'East Warehouse 2'),
(7, 4, 'West Warehouse 1'),
(8, 4, 'West Warehouse 2');
GO

CREATE TABLE dbo.Products(
ID INT NOT NULL,
--Locations INT NULL,
[Name] VARCHAR(50) NOT NULL,
[Description] VARCHAR(100) NULL
);
GO

INSERT INTO dbo.Products(ID, [Name], [Description])
VALUES (1, 'Grommet 1A', 'Steel 5mm'),
(2, 'Widget 12', 'A new gadget'),
(3, 'Oddment 6', 'A thing');
GO

CREATE TABLE dbo.ProductWarehouse(
ID INT NOT NULL,
ProductID INT NOT NULL,
WarehouseID INT NOT NULL
);
GO

INSERT INTO dbo.ProductWarehouse(Id, ProductID, WarehouseID)
VALUES (1, 1, 1),
(2, 1, 2),
(3, 1, 3),
(4, 1, 4),
(5, 2, 1),
(6, 2, 2),
(7, 3, 3),
(8, 3, 4);
GO

Querying the Data

A simple SELECT statement shows various details about warehouse locations and products.

Listing 2: Basic Query

    SELECT Region.Area,
	   Warehouse.[Name],
	   Products.[Name],
	   Products.[Description]
   FROM dbo.Region Region 
   LEFT OUTER JOIN dbo.Warehouse Warehouse ON Warehouse.Region = Region.ID
   LEFT OUTER JOIN dbo.ProductWarehouse pw ON pw.Warehouseid = Warehouse.ID
   INNER JOIN dbo.Products Products ON Products.ID = pw.ProductID
   ORDER BY Region.Area,
	    Warehouse.[Name],
	    Products.[Name];

Figure 1: Result from Listing 2

Result from Query 2

XML RAW

The most basic XML formatting is XML RAW. The output from a query is converted to one XML field, where each row of data returned is with a <row> element.

Listing 3: Query with XML RAW

    SELECT Region.Area,
	   Warehouse.[Name],
	   Products.[Description]
    FROM dbo.Region Region 
    LEFT OUTER JOIN dbo.Warehouse Warehouse ON Warehouse.Region = Region.ID
    LEFT OUTER JOIN dbo.ProductWarehouse pw ON pw.Warehouseid = Warehouse.ID
    INNER JOIN dbo.Products Products ON Products.ID = pw.ProductID
    ORDER BY Region.Area,
	     Warehouse.[Name],
	     Products.[Name]
    FOR XML RAW;

Figure 2: Result from Listing 3

XML Returned from the RAW query

Click on this XML row and another tab will be opened, showing the detail within this row:

Figure 3: Clicking on the XML shows this

One ‘row’ element for each SQL row returned

If the element name of ‘row’ isn’t suitable, another name can be specified.

Listing 4: Change the name of <row>

SELECT Region.Area,
       Warehouse.[Name],
       Products.[Description]
FROM dbo.Region Region
LEFT OUTER JOIN dbo.Warehouse Warehouse ON Warehouse.Region = Region.ID
LEFT OUTER JOIN dbo.ProductWarehouse pw ON pw.Warehouseid = Warehouse.ID
INNER JOIN dbo.Products Products ON Products.ID = pw.ProductID
ORDER BY Region.Area,
         Warehouse.[Name],
         Products.[Name]
FOR XML RAW('Warehouse');

Figure 4: Result from Listing 4

‘row’ is now ‘Warehouae’

Duplicate Column Names in XML RAW
Notice that in Listing 2 there were two columns named ‘Name’, whereas in listing 3 and 4 I only specified the one. This is because XML RAW, in its most basic form, cannot have duplicated names within each <row> element.

In the following listing, the row ‘Name’ is selected from both the Warehouse and Products tables.

Listing 5: SELECT XML RAW with duplicate column names

    SELECT Region.Area,
	   Warehouse.[Name],
	   Products.[Name],
	   Products.[Description]
    FROM dbo.Region Region 
    LEFT OUTER JOIN dbo.Warehouse Warehouse ON Warehouse.Region = Region.ID
    LEFT OUTER JOIN dbo.ProductWarehouse pw ON pw.Warehouseid = Warehouse.ID
    INNER JOIN dbo.Products Products ON Products.ID = pw.ProductID
    ORDER BY Region.Area,
	     Warehouse.[Name],
	     Products.[Name]
    FOR XML RAW;

The result of this query is:
Column name ‘Name’ is repeated. The same attribute cannot be generated more than once on the same XML tag.

This is because the XML RAW in this example is attempting to show two attributes called ‘Name’ within one element – ‘<row>’. Duplicate attributes are not allowed within the same element.

To get around this, specifying ELEMENTS will output each column as a separate element within <row>, which will allow such a result.

Listing 6: SELECT XML RAW with ELEMENTS specified

    SELECT Region.Area,
	   Warehouse.[Name],
	   Products.[Name],
	   Products.[Description]
    FROM dbo.Region Region 
    LEFT OUTER JOIN dbo.Warehouse Warehouse ON Warehouse.Region = Region.ID
    LEFT OUTER JOIN dbo.ProductWarehouse pw ON pw.Warehouseid = Warehouse.ID
    INNER JOIN dbo.Products Products ON Products.ID = pw.ProductID
    ORDER BY Region.Area,
	     Warehouse.[Name],
	     Products.[Name]
    FOR XML RAW, ELEMENTS

Figure 5: Result from Listing 6

Partial Result using ELEMENTS

 ROOT

In Figure 4, notice that the second ‘<row>’ element has a red underline, signifying an error of some type. If you move the mouse to this field, a help-text will show more information.

Figure 6: Error Message

You can’t have multiple root levels

The message ‘XML document cannot contain multiple root level elements’ means that there should be one unique XML ‘tag’ that surrounds the entire document.

To create this XML with one root-level element, the option ROOT can be used.

Listing 7: Specifying ROOT

    SELECT Region.Area,
	   Warehouse.[Name],
	   Products.[Name],
	   Products.[Description]
    FROM dbo.Region Region 
    LEFT OUTER JOIN dbo.Warehouse Warehouse ON Warehouse.Region = Region.ID
    LEFT OUTER JOIN dbo.ProductWarehouse pw ON pw.Warehouseid = Warehouse.ID
    INNER JOIN dbo.Products Products ON Products.ID = pw.ProductID
    ORDER BY Region.Area,
	     Warehouse.[Name],
	     Products.[Name]
    FOR XML RAW, ELEMENTS, ROOT

Figure 7: Result from Listing 7 (truncated for visibility)

Now with a element surrounding the document

The default name of ‘root’ can be replaced with something more appropriate.

Listing 8: Specifying root name

    SELECT Region.Area,
	   Warehouse.[Name],
	   Products.[Name],
	   Products.[Description]
    FROM dbo.Region Region 
    LEFT OUTER JOIN dbo.Warehouse Warehouse ON Warehouse.Region = Region.ID
    LEFT OUTER JOIN dbo.ProductWarehouse pw ON pw.Warehouseid = Warehouse.ID
    INNER JOIN dbo.Products Products ON Products.ID = pw.ProductID
    ORDER BY Region.Area,
	     Warehouse.[Name],
	     Products.[Name]
    FOR XML RAW, ELEMENTS, ROOT('Warehouses');

Figure 8: Result from query 8 (truncated for visibility)

With ‘Warehouses’ element

Conclusion

Although referred to as the most basic of XML options, RAW still has a variety of possible configurations. As this series develops, several of the aspects shown in this article will appear again.

References

XML Data
FOR XML
XML and JSON Recipes for SQL Server – Amazon.com

One Response to “XML RAW, ELEMENTS and ROOT – Basic Examples”

Trackbacks/Pingbacks

  1. XML AUTO – Basic Examples | Notes on SQL - June 20, 2019

    […] a previous article I gave example of XML RAW. Although RAW is useful, AUTO takes care of several aspects of XML […]

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.

%d bloggers like this: