Reputation: 2504
I have the below XML
<myroot>
<scene>
<sceneId>983247</sceneId>
<item>
<coordinates>
<coordinate>0</coordinate>
<coordinate>1</coordinate>
<coordinate>2</coordinate>
<coordinate>3</coordinate>
</coordinates>
<Values>
<Value>34</Value>
<Value>541</Value>
<Value>255</Value>
<Value>332</Value>
</Values>
</item>
</scene>
</myroot>
How can I get using TSQL the following result:
Col1 Col2
0 34
1 541
2 255
3 332
Thanks,
M
Upvotes: 0
Views: 832
Reputation: 11007
Here's my XML noob approach.
If you only trust the element sequencing, and not the coordinate values themselves being a sequence:
select
coordinate = max(case when element = 'coordinate' then elemval end)
, value = max(case when element = 'Value' then elemval end)
from (
select
element = row.value('local-name(.)','varchar(32)')
, elemval = row.value('.','int')
, position = row.value('for $s in . return count(../*[. << $s]) + 1', 'int')
from @xml.nodes('/myroot/scene/item/*/*') a (row)
) a
group by position
Alternatively written as two .nodes()
and a JOIN
(you get the idea).
If do you trust the coordinate numbering to be a sequence starting at zero:
select
coordinate = row.value('for $s in . return count(../*[. << $s]) + 1', 'int')
- 1
, value = row.value('.','int')
from @xml.nodes('/myroot/scene/item/Values/*') a (row)
If you only trust the coordinate numbering to be a sequence, but from an arbitrary seed:
select
coordinate = row.value('for $s in . return count(../*[. << $s]) + 1', 'int')
+ row.value('(/myroot/scene/item/coordinates/coordinate)[1]','int')
- 1
, value = row.value('.','int')
from @xml.nodes('/myroot/scene/item/Values/*') a (row)
Paths can be abbreviated:
/myroot/scene/item/*/*
-> //item/*/*
/myroot/scene/item/Values/*
-> //Values/*
/myroot/scene/item/coordinates/coordinate
-> //coordinate
But I don't know the wisdom of this either way.
//item/*/*
can probably be made more specific, so that it only includes coordinate
and Value
edge nodes, but I don't know the syntax.
Upvotes: 0
Reputation:
This XPath 2.0 expression:
/myroot/scene/item/
string-join(for $pos in (0 to max(*/count(*)))
return string-join(for $col in (1 to max(count(*)))
return if ($pos=0)
then concat('Col',$col)
else *[$col]/*[$pos],
' '),
'
')
Output:
Col1 Col2
0 34
1 541
2 255
3 332
Upvotes: 1