Reputation: 374
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?
There's no real-world problem to be solved here — I'm simply curious.
Upvotes: 0
Views: 483
Reputation: 6798
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('.');
Upvotes: 4
Reputation: 374
Based on the answer I accepted, I went with:
DECLARE @x xml = CONVERT(xml, N'');
SELECT
Apple = @x,
Banana = @x,
Orange = @x,
Pear = @x
FOR XML RAW ('Fruits'),
ELEMENTS,
TYPE;
Tags can be rendered in different ways depending on where and how the rendering is done. This can be in the query processor, specific FOR XML
server-side code, or even by the client driver in some cases.
Details in What does server side FOR XML return? by the SQL Server Programmability Team.
Upvotes: 1
Reputation: 72194
It's not so much the self-closing tags you want, as it is semantically equivalent to a non-self-closing one anyway. It's that you want your data as attributes rather than elements.
It's much easier with FOR XML PATH
. Normally you would have your date in a table, but I've shown you with a VALUES
virtual table
SELECT
v.Name AS [@Name]
FROM (VALUES
('Apple'),
('Banana'),
('Orange'),
('Pear')
) v(Name)
FOR XML PATH('Fruit'), ROOT('Fruits'), TYPE;
This does also produce self-closing tags, somewhat as a by-product.
Upvotes: 0
Reputation: 72194
Assuming you were actually asking for FOR XML
to generate self-closing tags, you can get this using CAST('' AS xml)
SELECT
Apple = CAST('' AS xml),
Banana = CAST('' AS xml),
Orange = CAST('' AS xml),
Pear = CAST('' AS xml)
FOR XML RAW ('Fruits'), ELEMENTS, TYPE;
You can also do this using FOR XML PATH
SELECT
CAST('' AS xml) Apple,
CAST('' AS xml) Banana,
CAST('' AS xml) Orange,
CAST('' AS xml) Pear
FOR XML PATH('Fruit'), ROOT('Fruits'), TYPE;
Note that because they are semantically equivalent, any good XML parser will not see a difference, and may freely convert between one and the other without you noticing.
Upvotes: 2