2011-03-14 49 views
2

如何使用T-SQL(SQL2008)遍历XML文档中的所有节点。 我需要为文档中每个不同的节点路径(元素)创建表格模式。如何遍历XML中的所有节点 - Sql2008

declare @x xml=' 
<logins> 
    <roles> 
    <role name="Administrator" /> 
    <role name="elUser" /> 
    <role name="ElAdministrator"/> 
    <role name="regionalManager" /> 
    <role name="Rep"/> 
    <role name="DiscountAdministrator" /> 
    <role name="LoginAdmin"/> 
    <groups> 
     <group name="Administrators"> 
     <role name="Administrator"/> 
     <role name="elUser" /> 
     <role name="ElAdministrator" /> 
     <role name="Rep" /> 
     <role name="regionalManager" /> 
     <role name="DiscountAdministrator" /> 
     <role name="LoginAdmin" /> 
     </group> 
    </groups> 
    </roles> 
    <members> 
    <member login="apeiris" ofgroup="Administrator"></member> 
    </members> 
</logins>' 

编辑上面包括 我想通用脚本创建/维护模式的,意思是我不知道前手的节点。

+2

看看[我如何从XML获取元素名称列表](http://stackoverflow.com/questions/2266132/how-can-i-get-a-list-of-element-names -from-AN-XML的值在-SQL服务器)。问题不明确,你试图实现什么 – RichardTheKiwi 2011-03-14 21:01:48

+0

你不需要知道你将如何处理你推断的数据?例如,如果路径是/ logins/roles/role,您将必须知道您正在添加角色... – 2011-03-14 21:15:00

+0

@ Richard,Exaclty我在找什么。 – TonyP 2011-03-15 12:51:31

回答

-1

我很确定如果你知道哪些节点将成为表格,你可以使用XPath语句...你有这个文件的样本吗?

这让我你的角色名的所有7:

SELECT  Logins.L.query('data(@name)').value('.', 'varchar(60)') as RoleName 
FROM  @x.nodes('/logins/roles/role') Logins (L) 

从这里你可以使用同样的想法,让你需要的数据,并执行任何基于SQL关闭无论你选择SELECT结果。

+0

原来的问题并没有说明节点路径是未知的...... – 2011-03-14 21:12:53

+0

有罪,因为我没有注意到最后添加到问题的限定符... – 2011-03-16 18:33:05

1

下面的代码可以用来映射整个XML结构和存储在文档中的值,我们只知道它的根名称。

当我测试它只需要几次运行,之后它就吸收了太多的sql资源,并且无关的事务开始受到影响。

我试过寻找方法使它与nodes()函数一起工作,但只有旧的OPENXML做了我所需要的工作。

然后我将它插入一个表变量并操作它。

对于这个特定的问题,可以生成动态sql来验证是否存在必要的表,如果需要,创建它们之后进行值插入。

DECLARE @idoc INT 
DECLARE @param_XML XML = 
'<root> 
    <element1>hello 
     <element2>1</element2> 
     <element3 id="3">goodbye</element3> 
    </element1> 
</root>' 

EXEC sys.sp_xml_preparedocument @idoc OUTPUT, @param_XML 


--SELECT id, parentid, nodetype,localname, prev, [text] 
SELECT * 
FROM OPENXML (@idoc, '/root', 2) 

-- remeber to close document to avoid memory leak 
EXEC sys.sp_xml_removedocument @idoc 
0

如果结构仍然喜欢你贴,所以你不必担心,如果加入更多的角色

试试这个:

declare @x xml=' 
<logins> 
<roles> 
<role name="Administrator" /> 
<role name="elUser" /> 
<role name="ElAdministrator"/> 
<role name="regionalManager" /> 
<role name="Rep"/> 
<role name="DiscountAdministrator" /> 
<role name="LoginAdmin"/> 
<groups> 
    <group name="Administrators"> 
    <role name="Administrator"/> 
    <role name="elUser" /> 
    <role name="ElAdministrator" /> 
    <role name="Rep" /> 
    <role name="regionalManager" /> 
    <role name="DiscountAdministrator" /> 
    <role name="LoginAdmin" /> 
    </group> 
</groups> 
    <groups> 
    <group name="SimpleUser"> 
    <role name="Administrator"/> 
    <role name="elUser" /> 
    <role name="ElAdministrator" /> 
    <role name="Rep" /> 
    <role name="regionalManager" /> 
    <role name="DiscountAdministrator" /> 
    <role name="LoginAdmin" /> 
    </group> 
</groups> 
</roles> 
<members> 
<member login="apeiris" ofgroup="Administrator"></member> 
</members> 
</logins>' 

select 
row_number() over (partition by 
t.x.value('(group/@name)[1]' , 'varchar(100)') 
order by t.x.value('(group/@name)[1]' , 'varchar(100)')) Id, 
t.x.value('(group/@name)[1]' , 'varchar(100)') GroupName, 
p.y.value('@name' , 'varchar(100)') RoleName 
from @x.nodes('//logins/roles/role') p(y) 
cross apply @x.nodes('//groups') t(x) 

它提供了在XML中的所有角色和组