Reputation: 127
I have to process an XML file with following format:
<Root>
<A name="x1">
<B exp="h1", ref="r1"/>
<C exp="h2", ref="r2", rat = "ra1"/>
<D exp="h3", ref="r3"/>
</A>
<A name="x2">
<E exp="h4", ref="r4"/>
<F exp="h5", ref="r5"/>
</A>
</Root>
I want to write an stored procedure to get a table like:
|A_name|tag_name|attrbute|val|
|x1 | B |exp|h1|
|x1 | B |ref|r1|
|x1 | C |exp|h2|
|x1 | C |rat|ra1|
|x1 | C |ref|r2|
|x1 | D |exp|h3|
|x1 | D |ref|r3|
|x2 | E |exp|h4|
|x2 | E |ref|r4|
|x2 | F |exp|h5|
|x2 | F |ref|r5|
How can I do? I've already try
SELECT localname
FROM OPENXML(@idoc, '/A')
WHERE localname!='A'
to get the tag name. However, I am not able to join them with attribute of tag A.
Upvotes: 1
Views: 120
Reputation: 8829
Similar to gotqn's answer... you can get all of the attributes of an element by way of a @*
wildcard query thus avoiding the pivot (which requires knowledge of all the attribute names ahead of time), e.g.:
select
a.a.value('(@name)[1]', 'nvarchar(50)') as 'a_name',
b.b.value('local-name(.)', 'nvarchar(50)') as 'tag_name',
c.c.value('local-name(.)', 'nvarchar(50)') as 'attribute',
c.c.value('data(.)', 'nvarchar(50)') as 'val'
from @example.nodes('//A') a(a)
cross apply a.a.nodes('*') b(b)
cross apply b.b.nodes('@*') c(c);
| a_name | tag_name | attribute | val |
|--------|----------|-----------|-----|
| x1 | B | exp | h1 |
| x1 | B | ref | r1 |
| x1 | C | exp | h2 |
| x1 | C | ref | r2 |
| x1 | C | rat | ra1 |
| x1 | D | exp | h3 |
| x1 | D | ref | r3 |
| x2 | E | exp | h4 |
| x2 | E | ref | r4 |
| x2 | F | exp | h5 |
| x2 | F | ref | r5 |
Upvotes: 1
Reputation: 43666
If your initial data is wrong (and the commas are not used to separate tags) you can try this:
DECLARE @XML XML = N'<Root>
<A name="x1">
<B exp="h1" ref="r1"/>
<C exp="h2" ref="r2" rat = "ra1"/>
<D exp="h3" ref="r3"/>
</A>
<A name="x2">
<E exp="h4" ref="r4"/>
<F exp="h5" ref="r5"/>
</A>
</Root>'
SELECT [A_name]
,[B_name]
,attribute
,value
FROM
(
SELECT T1.c.value('(./@name)[1]', 'varchar(12)') as [A_name]
,T2.c.value('local-name(.)', 'varchar(12)') as [B_name]
,T2.c.value('(@exp)[1]', 'varchar(30)') AS [exp]
,T2.c.value('(@ref)[1]', 'varchar(30)') AS [ref]
,T2.c.value('(@rat)[1]', 'varchar(30)') AS [rat]
FROM @XML.nodes('Root/A') T1(c)
CROSS APPLY T1.c.nodes('./*') T2(c)
) DS
UNPIVOT
(
[value] for [attribute] IN ([exp], [ref], [rat])
) UNPVT;
Upvotes: 1