Serialization and Concatenating String Values
A common requirement for an XML based application is the ability to do some form of simple string building. For example, the following query outputs a set of elements whose values are built up as a string, depending on some other value that is passed is as part of an iteration:
declare @x xml
set @x=''
select @x.query('
for $index in (1, 2, 3)
return
<element>
{ "Item" }{ $index }
</element>
')
The result of this query is the following set of 3 nodes:
<element>Item1</element>
<element>Item2</element>
<element>Item3</element>
In this instance, we constructed the string value for the element by creating 2 separate text nodes - one containing the string literal "Item" and the other containing the iterator value. As part of XML serialization, consecutive text nodes in the XML infoset are merged into a single text node, thus providing us with our desired output. Alternatively, we could have used the XQuery concat() function:
declare @x xml
set @x=''
select @x.query('
for $index in (1, 2, 3)
return
<element>
{ concat( "Item", $index cast as xs:string ? ) }
</element>
')
Notice that we had to add an explicit cast to the iterator value since the concat() function will only accept string values as it's arguments.
A further option would be to build your string value as a sequence of atomic values:
declare @x xml
set @x=''
select @x.query('
for $index in (1, 2, 3)
return
<element>
{ ( "Item", $index ) }
</element>
')
But, there is a subtle difference in the output of this query which is as follows:
<element>Item 1</element>
<element>Item 2</element>
<element>Item 3</element>
Notice that there is a space between the "Item" string value and the iterator value. Sequences of items are serialized with a space between each of the entries!
So, if you need to build strings - use the concat() function explicitly or rely on the XML infoset serialization rules and build multiple, consecutive text nodes. Remember that sequences are serialized with a space between each item.