为什么.value('@foo', 'varchar(20)')
会生成错误信息“不支持顶级属性节点”?
当您查询xml
数据类型时,上下文是文档节点,它是一个隐式节点,包含XML文档的根元素。文档节点没有名称和属性。
如何获取根元素上属性的值?
在您的XQuery表达式中,包括到第一个根元素的路径:
DECLARE @Data xml = '<Customer ID="123"><Order ID="ABC" /></Customer>'
SELECT @Data.value('Customer[1]/@ID', 'varchar(20)')
如果您不知道(或不想指定)根元素的名称,则只需使用*
匹配任何元素:
SELECT @Data.value('*[1]/@ID', 'varchar(20)')
由于查询上下文是文档节点,因此您不需要在XQuery表达式前加上斜杠(其他答案不必要地这样做)。
为什么我必须包含[1]
?
您传递给value()
的XQuery表达式必须保证返回单例。表达式Customer/@ID
不满足此要求,因为它匹配以下示例中的ID="123"
和ID="456"
:
DECLARE @Data xml = '<Customer ID="123" /><Customer ID="456" />'
请记住,xml
数据类型表示的是XML文档片段而不是XML文档,因此可以包含多个根元素。
Customer[1]/@ID
和(Customer/@ID)[1]
之间有什么区别?
表达式Customer[1]/@ID
检索第一个<Customer>
元素的ID
属性。
表达式(Customer/@ID)[1]
检索所有<Customer>
元素的ID
属性,并从该属性列表中选择第一个。
以下示例演示了差异:
DECLARE @Data xml = '<Customer /><Customer ID="123" /><Customer ID="456" />'
SELECT @Data.value('Customer[1]/@ID', 'varchar(20)')
SELECT @Data.value('(Customer/@ID)[1]', 'varchar(20)')
//Element[@foo]
或者如果您了解结构,则为/*/Elements/Element[@foo]
。 - StuartLC