Search code examples
sql-servert-sqlsql-server-2019for-xmlselect-for-xml

Generating self-closing XML tags for lists in SQL Server


I saw this XML example data in a 2013 SQL Server question on Stack Overflow:

<Fruits>
  <Apple />
  <Banana />
  <Orange />
  <Pear />
</Fruits>

I'm more used to seeing such lists structured as (for example):

<Fruits>
  <Fruit name="Apple" />
  <Fruit name="Banana" />
  <Fruit name="Orange" />
  <Fruit name="Pear" />
</Fruits>

I struggled to produce the (textually more compact) self-closing list format using FOR XML in SQL Server, eventually settling on:

SELECT 
    CONVERT(xml, 
        (
            SELECT 
                Apple = '', 
                Banana = '', 
                Orange = '', 
                Pear = ''
            FOR XML RAW ('Fruits'), ELEMENTS
        )
    );

Using the TYPE directive instead of converting the subquery result to xml didn't produce self-closing elements (though the result is logically equivalent):

<Fruits>
  <Apple></Apple>
  <Banana></Banana>
  <Orange></Orange>
  <Pear></Pear>
</Fruits>

Is there a neater way to produce the list in self-closing form using FOR XML in SQL Server?

db<>fiddle

There's no real-world problem to be solved here — I'm simply curious.


Solution

  • Casting '' as XML returns a self closing element or query('.') the generated XML, TYPE is required.

    SELECT 
        Apple = '', 
        Banana = cast('' as xml), 
        Orange = '', 
        Pear = cast('' as xml)
    FOR XML RAW ('Fruits'), ELEMENTS, TYPE;
    
    SELECT 
    (SELECT 
        Apple = '', 
        Banana = '', 
        Orange = '', 
        Pear = ''
    FOR XML RAW ('Fruits'), ELEMENTS, TYPE).query('.');