Retrieving Dynamic XML from SQL Server

Introduction


This article will describe the different ways of retrieving XML documents, highlight my experiences, and list the differences between them.

Three flavors of XML Output

To allow the retrieval of data in the XML format from SQL Server, the FOR XML command has been added to the T-SQL syntax. Using the FOR XML command with a sequel query allows the results to be generated as XML.

The command allows three variants

1.      RAW

2.      AUTO

3.      EXPLICIT

If we take the following SQL Query (see Figure 1), which uses the Pubs sample database shipped with the SQL Server, and apply it to each of the modes (or variants), we gain an understanding of the various types of XML output that each mode is capable of producing.

tblStates
tblCities

RAW Mode

Query

SELECT '<rows>'+(

      SELECT      S.State_Id,

            S.State_Code,

            S.State_Name,

           

            C.City_Id,

            C.City_Code,

            C.City_Name

             

      FROM tblStates S

            INNER JOIN tblCities C

                  ON C.State_Id = S.State_Id

      FOR XML RAW

)+'</rows>'

Output

Here is a snippet of the structure generated by the RAW mode.

<rows>

  <row State_Id="1" State_Code="AP" State_Name="Andhra Pradesh" City_Id="1" City_Code="NLR" City_Name="Nellore" />

  <row State_Id="1" State_Code="AP" State_Name="Andhra Pradesh" City_Id="2" City_Code="TPT" City_Name="Tirupati" />

  <row State_Id="1" State_Code="AP" State_Name="Andhra Pradesh" City_Id="3" City_Code="HYD" City_Name="Hyderabad" />

  <row State_Id="1" State_Code="AP" State_Name="Andhra Pradesh" City_Id="4" City_Code="KRN" City_Name="Karnool" />

  <row State_Id="2" State_Code="TN" State_Name="Tamil Nadu" City_Id="5" City_Code="CHN" City_Name="Chennai" />

  <row State_Id="2" State_Code="TN" State_Name="Tamil Nadu" City_Id="6" City_Code="MDR" City_Name="Madhurai" />

  <row State_Id="2" State_Code="TN" State_Name="Tamil Nadu" City_Id="7" City_Code="KBR" City_Name="Koimbattore" />

  <row State_Id="3" State_Code="KA" State_Name="Kerala" City_Id="8" City_Code="TVD" City_Name="Trivendram" />

  <row State_Id="4" State_Code="KT" State_Name="Karnataka" City_Id="9" City_Code="BGR" City_Name="Banglore" />

  <row State_Id="4" State_Code="KT" State_Name="Karnataka" City_Id="10" City_Code="MGR" City_Name="Manglore" />

  <row State_Id="4" State_Code="KT" State_Name="Karnataka" City_Id="11" City_Code="MSR" City_Name="Mysore" />

  <row State_Id="4" State_Code="KT" State_Name="Karnataka" City_Id="12" City_Code="BLR" City_Name="Belur" />

  <row State_Id="4" State_Code="KT" State_Name="Karnataka" City_Id="13" City_Code="SRP" City_Name="Sri Ranga Patnam" />

  </rows>


The XML document produced contains an element <Row>, which is fixed, for each record of the result set generated by Query. This is not very useful because we have no control over the element naming and document structure. The RAW mode falls short of the XML document I am looking to create, and really has limited use.  This query forms all data into attributes format.

Query

SELECT '<rows>'+(

      SELECT      S.State_Id,

            S.State_Code,

            S.State_Name,

           

            C.City_Id,

            C.City_Code,

            C.City_Name

             

      FROM tblStates S

            INNER JOIN tblCities C

                  ON C.State_Id = S.State_Id

      FOR XML RAW ('City'), ELEMENTS

)+'</rows>'

Output

<rows>

<City>

  <State_Id>1</State_Id>

  <State_Code>AP</State_Code>

  <State_Name>Andhra Pradesh</State_Name>

  <City_Id>1</City_Id>

  <City_Code>NLR</City_Code>

  <City_Name>Nellore</City_Name>

  </City>

<City>

  <State_Id>1</State_Id>

  <State_Code>AP</State_Code>

  <State_Name>Andhra Pradesh</State_Name>

  <City_Id>3</City_Id>

  <City_Code>HYD</City_Code>

  <City_Name>Hyderabad</City_Name>

  </City>

<City>

  <State_Id>1</State_Id>

  <State_Code>AP</State_Code>

  <State_Name>Andhra Pradesh</State_Name>

  <City_Id>4</City_Id>

  <City_Code>KRN</City_Code>

  <City_Name>Karnool</City_Name>

  </City>

<City>

  <State_Id>2</State_Id>

  <State_Code>TN</State_Code>

  <State_Name>Tamil Nadu</State_Name>

  <City_Id>7</City_Id>

  <City_Code>KBR</City_Code>

  <City_Name>Koimbattore</City_Name>

  </City>

  </rows>

The above query generates an xml with nodes for item in data.

AUTO Mode

Query

SELECT '<rows>'+(

      SELECT      [State].State_Id,

            [State].State_Code,

            [State].State_Name,

           

            [City].City_Id,

            [City].City_Code,

            [City].City_Name

             

      FROM tblStates [State]

            INNER JOIN tblCities [City]

                  ON [City].State_Id = [State].State_Id

      FOR XML AUTO

)+'</rows>'

Output

Below is a cross section of the output structure generated by the AUTO mode.

<rows>

<State State_Id="1" State_Code="AP" State_Name="Andhra Pradesh">

  <City City_Id="1" City_Code="NLR" City_Name="Nellore" />

  <City City_Id="2" City_Code="TPT" City_Name="Tirupati" />

  <City City_Id="3" City_Code="HYD" City_Name="Hyderabad" />

  <City City_Id="4" City_Code="KRN" City_Name="Karnool" />

  </State>

<State State_Id="2" State_Code="TN" State_Name="Tamil Nadu">

  <City City_Id="5" City_Code="CHN" City_Name="Chennai" />

  <City City_Id="6" City_Code="MDR" City_Name="Madhurai" />

  <City City_Id="7" City_Code="KBR" City_Name="Koimbattore" />

  </State>

<State State_Id="3" State_Code="KA" State_Name="Kerala">

  <City City_Id="8" City_Code="TVD" City_Name="Trivendram" />

  </State>

<State State_Id="4" State_Code="KT" State_Name="Karnataka">

  <City City_Id="9" City_Code="BGR" City_Name="Banglore" />

  <City City_Id="10" City_Code="MGR" City_Name="Manglore" />

  <City City_Id="11" City_Code="MSR" City_Name="Mysore" />

  <City City_Id="12" City_Code="BLR" City_Name="Belur" />

  <City City_Id="13" City_Code="SRP" City_Name="Sri Ranga Patnam" />

  </State>

  </rows>

As you can see the <State> and <City> tags have a parent-child relationship, giving us the hierarchical structure we require. This node relationship is determined on the order in which the tables are declared within the query, with each table declared in the sequence becoming a child of the previously declared table.

Look back at Query and notice the aliases given within the query affect the names generated within the XML document. Using this, we can control the labeling of the XML elements and attributes, and achieve the naming convention we require.

The AUTO mode allows us to create the XML document we want, but the following disadvantages become apparent with further use:

  • We can create hierarchical structures, but only in a linear fashion, as a parent node can only have one child and vice versa.
  • Using aliases to create element and attribute names can become tedious and is sometimes counterproductive to the readability of the query.
  • We cannot have both attributes and elements within the document. Its either all elements, specified using the ELEMENTS keyword, or the default, which is attributes.

These shortcomings are addressed within EXPLICIT mode.