使用 OPENXML 在 SQL 服务器中获取标签和属性的名称
Get the name of tag and attribute in SQL Server using OPENXML
我必须处理具有以下格式的 XML 文件:
<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>
我想写一个存储过程来得到一个 table 像:
|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|
我该怎么办?我已经试过了
SELECT localname
FROM OPENXML(@idoc, '/Root/A')
WHERE localname!='A'
获取标签名称。但是,我无法使用标签 A 的属性加入它们。
我发现结合使用nodes()和value()的性能比OPENXML差很多。所以即使 OPENXML 已经过时,我仍然想使用它,因为我有 GB XML 结果要读取。
如果看到 OPENXML
outperform well-written nodes()
and value()
code when processing large amounts of data. OPENXML
is an extremely RBAR 过程要求您为每个要处理的 XML 文档调用两个存储过程和一个 UDF,我会感到很惊讶。如果您使用 nodes()
和 value()
的代码性能不佳,它可能有回溯引用(即:'../'
)和其他此类性能杀手。
不过,这里有一些 OPENXML
疯狂的东西会产生您正在寻找的结果集...
declare @idoc int, @doc nvarchar(max) = 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>';
exec sp_xml_preparedocument @idoc output, @doc;
;with rowset as (
select id, parentid, nodetype, localname, prefix, namespaceuri, datatype, prev, [text]
from openxml(@idoc, '/Root/A')
)
select A_name, tag_name, attribute, val
from rowset Router
outer apply (
select A_name_id=Rinner.id
from rowset Rinner
where Rinner.nodetype=2 and Rinner.parentid=Router.id and Rinner.localname=N'name'
) NameAttributes
outer apply (
select A_name=Rinner.[text]
from rowset Rinner
where Rinner.nodetype=3 and Rinner.parentid=NameAttributes.A_name_id and Rinner.localname=N'#text'
) NameValues
cross apply (
select tag_id=Rinner.id, tag_name=Rinner.localname
from rowset Rinner
where Rinner.nodetype=1 and Rinner.parentid=Router.id
) Children
cross apply (
select attribute_id=Rinner.id, attribute=Rinner.localname
from rowset Rinner
where Rinner.nodetype=2 and Rinner.parentid=Children.tag_id
) ChildAttributes
outer apply (
select val=Rinner.[text]
from rowset Rinner
where Rinner.nodetype=3 and Rinner.parentid=ChildAttributes.attribute_id
) ChildAttributeValues
where nodetype=1 and parentid=0
order by Router.id, Children.tag_id, ChildAttributes.attribute
exec sp_xml_removedocument @idoc;
A_name tag_name attribute 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
我必须处理具有以下格式的 XML 文件:
<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>
我想写一个存储过程来得到一个 table 像:
|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|
我该怎么办?我已经试过了
SELECT localname
FROM OPENXML(@idoc, '/Root/A')
WHERE localname!='A'
获取标签名称。但是,我无法使用标签 A 的属性加入它们。
我发现结合使用nodes()和value()的性能比OPENXML差很多。所以即使 OPENXML 已经过时,我仍然想使用它,因为我有 GB XML 结果要读取。
如果看到 OPENXML
outperform well-written nodes()
and value()
code when processing large amounts of data. OPENXML
is an extremely RBAR 过程要求您为每个要处理的 XML 文档调用两个存储过程和一个 UDF,我会感到很惊讶。如果您使用 nodes()
和 value()
的代码性能不佳,它可能有回溯引用(即:'../'
)和其他此类性能杀手。
不过,这里有一些 OPENXML
疯狂的东西会产生您正在寻找的结果集...
declare @idoc int, @doc nvarchar(max) = 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>';
exec sp_xml_preparedocument @idoc output, @doc;
;with rowset as (
select id, parentid, nodetype, localname, prefix, namespaceuri, datatype, prev, [text]
from openxml(@idoc, '/Root/A')
)
select A_name, tag_name, attribute, val
from rowset Router
outer apply (
select A_name_id=Rinner.id
from rowset Rinner
where Rinner.nodetype=2 and Rinner.parentid=Router.id and Rinner.localname=N'name'
) NameAttributes
outer apply (
select A_name=Rinner.[text]
from rowset Rinner
where Rinner.nodetype=3 and Rinner.parentid=NameAttributes.A_name_id and Rinner.localname=N'#text'
) NameValues
cross apply (
select tag_id=Rinner.id, tag_name=Rinner.localname
from rowset Rinner
where Rinner.nodetype=1 and Rinner.parentid=Router.id
) Children
cross apply (
select attribute_id=Rinner.id, attribute=Rinner.localname
from rowset Rinner
where Rinner.nodetype=2 and Rinner.parentid=Children.tag_id
) ChildAttributes
outer apply (
select val=Rinner.[text]
from rowset Rinner
where Rinner.nodetype=3 and Rinner.parentid=ChildAttributes.attribute_id
) ChildAttributeValues
where nodetype=1 and parentid=0
order by Router.id, Children.tag_id, ChildAttributes.attribute
exec sp_xml_removedocument @idoc;
A_name tag_name attribute 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