Alright, think I figured out what it was. I thought it was using UNION earlier, but didn't add the ORDER BY and so wasn't getting proper results. Just tried with order by and got it working.
;with c
as
(
select 1 as Customer_id, 'Fred' as FirstName, 'Flintstone' as LastName
union select 2, 'Betty', 'Ruble'
)
select 1 as Tag
, 0 as Parent
, Customer_id as "customer!1!customer_id!hide"
, null as "name!2!!CDATA"
from c
union
select 2 as Tag
, 1 as Parent
, Customer_Id
, FirstName + ' ' + LastName as "name!2!!CDATA"
from c
order by "customer!1!customer_id!hide", Tag
for xml explicit, root('customers')
;
The highlighted portion is key to keeping the data organized together properly. The order by Tag column will ensure that the elements are sequenced correctly.
You can simply add other elements in the same way . If you want address to be under contacts, then its parent column value needs to be the same as the tag value of the contacts element.