I am assuming the answer to my question is going to be something simple which I can't figure out myself. Here is the scenario:
I am using SQL Server 2008 R2 where a table has an XML column where the data is saved in the following format:
<Person>
<firstName>John</firstName>
<lastName>Lewis</lastName>
</Person>
The Person
node can have any number of child-nodes for which the element names might be different (not known beforehand). I am looking for a query to return an XML which has the values for all the nodes as attributes.
So the output for the above XML should be:
<Person firstName="John" lastName="Lewis"/>
I can't think of a query to get the above output. I don't want to use a query like
Select
PersonColumn.value('(/Person/firstName)[1]', 'varchar(100)') AS '@firstName'
, PersonColumn.value('(/Person/lastName)[1]', 'varchar(100)') AS '@lastName'
FROM MyTable
WHERE MyTable.MyPrimaryKey=1
FOR XML PATH('Person'), TYPE
since I don't know what nodes might there be under the Person
node.
I've tried to do this
select
PersonColumn.query('
element Person {
for $i in /Person/*
return attribute {local-name($i)} {string($i)}
}
')
from MyTable
but it turns out that it's impossible to use dynamic attribute names
XQuery [MyTable.PersonColumn.query()]: Only constant expressions are supported for the name expression of computed element and attribute constructors.: select PersonColumn.query(' element Person { for $i in /Person/* return attribute {local-name($i)} {string($i)} } ') from MyTable
So best I can do so far is
select
cast(
'<Person ' +
(
select
PersonColumn.query('
for $i in /Person/*
return concat(local-name($i), "=""", data($i), """")
').value('.', 'nvarchar(max)')
for xml path('')
) + '/>'
as xml)
from MyTable
It's also possible to do this
select
cast(
'<Person ' +
PersonColumn.query('
for $i in /Person/*
return concat(local-name($i), "=""", data($i), """")
').value('.', 'nvarchar(max)') +
'/>'
as xml)
from MyTable
but it will not work if your data contains some characters like <
>
and so on