XML Workshop 3 : Advanced XML Processing

Introduction

In the previous article, we have seen some examples which demonstrate the XML processing capabilities of SQL Server 2005. We had seen several examples which shows how to read values from an XML variable/field.

In this installment, we will look into the different ways to generate an XML buffer/variable with the results of a query. Most of the times you would need this if you need to call a function/SP which takes an XML variable as a parameter.

The results of a query can be transformed to XML format by using the FOR XML TSQL keyword. FOR XML should always be used with any of the following keywords: AUTO, RAW, PATH or EXPLICIT. In this article we will see the usages of AUTO and RAW.

Examples

Step 1

1 /*

2 Let us create the sample table and populate it.

3 */

4

5 CREATE TABLE [dbo].[OrderDetails](

6 [OrderDetailID] [int] IDENTITY(1,1) NOT NULL,

7 [OrderNumber] VARCHAR(10) NOT NULL,

8 [ItemNumber] [varchar](20) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,

9 [Qty] [int] NULL,

10 [Rate] FLOAT NULL,

11 [QtyPicked] INT NULL

12 ) ON [PRIMARY]

13

14 INSERT INTO OrderDetails (OrderNumber, ItemNumber, Qty, Rate, QtyPicked)

15 SELECT '00001', 'A001', 10, 11.25, 0

16 UNION SELECT '00001', 'A002', 20, 15, 0

17 UNION SELECT '00001', 'A003', 30, 23.75, 0

Step 2

1 /*

2 The simplest way to return values in XML format is to use the keyword

3 FOR XML with AUTO.

4 */

5

6 SELECT OrderNumber, ItemNumber, Qty FROM OrderDetails FOR XML AUTO

7

8 /*

9 OUTPUT:

10

11

12

13

14 */

Step 3

1 /*

2 Though the query returns the results in XML format,

3 it is not an XML data type. The result is NVARCHAR.

4 To return the results as an XML data type, use the

5 keyword TYPE.

6 */

7

8 SELECT OrderNumber, ItemNumber, Qty FROM OrderDetails FOR XML AUTO, TYPE

9

10 /*

11 OUTPUT:

12

13

14

15

16 */

Step 4

1 /*

2 By default, SQL SERVER returns the values as attributes.

3 Some times you might need the values as nodes. Use the

4 ELEMENTS keyword for that.

5 */

6

7 SELECT OrderNumber, ItemNumber, Qty FROM OrderDetails FOR XML AUTO, TYPE, ELEMENTS

8

9 /*

10 OUTPUT:

11

12

13 00001

14 A001

15 10

16

17

18 00001

19 A002

20 20

21

22

23 00001

24 A003

25 30

26

27 */

Step 5

1 /*

2 You will notice that the result does not have a ROOT element.

3 A correct XML document/fragment should always have a ROOT element.

4 Let us have this added by using the ROOT keyword.

5 */

6

7 SELECT OrderNumber, ItemNumber, Qty FROM OrderDetails FOR XML AUTO, TYPE, ELEMENTS, ROOT

8

9 /*

10 OUTPUT:

11

12

13

14 00001

15 A001

16 10

17

18

19 00001

20 A002

21 20

22

23

24 00001

25 A003

26 30

27

28

29 */

Step 6

1 /*

2 Well, we have a element now. However, the name is not good.

3 Let us change the name of the root element.

4 */

5

6 SELECT OrderNumber, ItemNumber, Qty FROM OrderDetails FOR XML AUTO, TYPE, ELEMENTS, ROOT('orderInfo')

7

8 /*

9 OUTPUT:

10

11

12

13 00001

14 A001

15 10

16

17

18 00001

19 A002

20 20

21

22

23 00001

24 A003

25 30

26

27

28 */

Step 7

1 /*

2 So far, we have seen how to assign a custom name to the element as

3 well as a custom name to each row. it is also possible to give a custom

4 name to each element by using a column alias. The following example shows that.

5 */

6

7 SELECT

8 OrderNumber as 'OrderNum',

9 ItemNumber as ItemCode,

10 Qty as Quantity

11 FROM OrderDetails FOR XML AUTO, TYPE, ELEMENTS, ROOT('itemInfo')

12

13 /*

14 OUTPUT:

15

16

17

18 00001

19 A001

20 10

21

22

23 00001

24 A002

25 20

26

27

28 00001

29 A003

30 30

31

32

33 */

Step 8

1 /*

2 So far, we have seen, how to rename the element

3 as well as the columns. Now let us see how to rename the

4 names of rows. By default the AUTO keyword generates rows

5 with the name of the table/alias.

6 */

7

8 SELECT

9 OrderNumber,

10 ItemNumber,

11 Qty

12 FROM OrderDetails itemInfo FOR XML AUTO, TYPE, ELEMENTS, ROOT('orderInfo')

13

14 /*

15 OUTPUT:

16

17

18

19 00001

20 A001

21 10

22

23

24 00001

25 A002

26 20

27

28

29 00001

30 A003

31 30

32

33

34 */

Step 9

1 /*

2 In the previous example, we had assigned an alias to the table

3 in order to customize the element names of each row. This approach works well.

4 However, if the query is complex, some times, it will be very confusing to

5 use alias names just to format the XML node names.

6

7 The AUTO keyword does not provide a way to customize the name of rows. By using

8 the RAW keyword, instead of AUTO, we can easily customize the rows. The following

9 example demonstrates this by using the RAW keyword.

10 */

11

12 SELECT

13 OrderNumber,

14 ItemNumber,

15 Qty

16 FROM OrderDetails FOR XML RAW('itemInfo'), TYPE, ELEMENTS, ROOT('orderInfo')

17

18 /*

19 OUTPUT:

20

21

22

23 00001

24 A001

25 10

26

27

28 00001

29 A002

30 20

31

32

33 00001

34 A003

35 30

36

37

38 */

Step 10

1 /*

2 So far, we are able to format the XML results in the way we wish.

3 We are able to rename the root node, rows and element names.

4

5 Now let us look at a different case. When SQL Server generates the

6 XML results, it will skip the columns which has NULL values. Let us

7 look at an example.

8

9 The code below, updates a column to NULL. Look at the results. The

10 third row does not have element.

11 */

12

13 UPDATE OrderDetails SET Qty = NULL WHERE OrderDetailID = 3

14

15 SELECT

16 OrderNumber,

17 ItemNumber,

18 Qty

19 FROM OrderDetails FOR XML RAW('itemInfo'), TYPE, ELEMENTS, ROOT('orderInfo')

20

21 /*

22 OUTPUT:

23

24

25

26 00001

27 A001

28 10

29

30

31 00001

32 A002

33 20

34

35

36 00001

37 A003

38

39

40 */

Step 11

1 /*

2 In the previous example, we have seen that, if a column is

3 NULL, then the element will not be present in the generated XML.

4

5 This can create problems most of the times. For example, if we

6 need to pass this XML fragment to another function/SP and if

7 that function/SP expects the element to be present in all the rows

8 the function/SP will fail.

9

10 So, we need a way to generate an empty element when the value is NULL.

11 The keyword XSINIL does the trick.

12 */

13

14 SELECT

15 OrderNumber,

16 ItemNumber,

17 Qty

18 FROM OrderDetails FOR XML RAW('itemInfo'), TYPE, ELEMENTS XSINIL, ROOT('orderInfo')

19

20 /*

21 OUTPUT:

22

23

24

25 00001

26 A001

27 10

28

29

30 00001

31 A002

32 20

33

34

35 00001

36 A003

37

38

39

40 */

Conclusions

In this article, we have seen the usage of keywords AUTO and RAW for formatting the results as XML. In the next article we will see the usage PATH and EXPLICIT.