XML数据类型的方法“值”的变量1必须是一个字符串文字(The argument 1 of the

2019-09-22 09:02发布

我已经经历了这么写着: XML数据类型的方法“值”必须是一个字符串文字 ,但我的问题是一个有点不同。 我有一点XML的一个变量我要挑开,我给出的路径。 本来我想这样的:

declare @x xml
select @x = '....'
select @x.value('(' + @path + ')[1]', 'varchar(max)')

但是,当然,失败。 后来我发现了SQL:变量和尝试这样做:

select @x.value('(sql:variable("@path"))[1]', 'varchar(max)')

但奇怪的返回@path的价值(为什么?)。 我一直在搞乱,但不能得到它做正确的事情。

思考的人?

Answer 1:

您选择退货的价值@path因为sql:variable()返回一个文本值,所以实际上你问SQL服务器选择文字值@path从文件,它的作用。 我知道,做你想要将使用动态SQL,像这样的东西的唯一方法:

declare @xml xml = '
<root>
    <element attr="test">blah</element>
</root>';

declare @p nvarchar(max) = '(//element/text())[1]';
declare @sql nvarchar(max) 
    = 'select @x.value(''' + @p + ''', ''nvarchar(max)'')';

exec sp_executesql @sql, @parameters = N'@x xml', @x = @xml;

不过,我要提醒你,这不是很好的做法(想想SQL注入,验证输入等)



Answer 2:

从帮助wBob微软的网站上,我现在已经有了一个干净的解决方案。 表现为,当然,关注的问题作为整个文件将被映射为一个单一路径的缘故,而是改进留给建议可能性读者:)

if object_id('VMConfigVal') is not null
drop function VMConfigVal
go
create function VMConfigVal(@x xml, @path varchar(max))
returns nvarchar(max)
as
begin
    declare @ret nvarchar(max)

    ;with cte as
    (
    select  value = x.c.value('.', 'varchar(50)')
    ,       path = cast ( null as varchar(max) )
    ,       node = x.c.query('.')
    from    @x.nodes('/*') x(c)
    union all
    select  n.c.value('.', 'varchar(50)')
    ,       isnull( c.path + '/', '/' )
        +       n.c.value('local-name(.)', 'varchar(max)')
    ,       n.c.query('*')
    from    cte c
    cross   apply c.node.nodes('*') n(c)
    )
    select @ret = value from cte where path = @path
    return @ret
    end
go

所以我现在可以这样做:

select dbo.VMConfigVal(MyXMLConfig, '/hardware/devices/IDE/ChannelCount')
from someTable

甜!



Answer 3:

如果你只需要找到名称的子元素,并希望抽象的名字从这里开始的XPath字面一些选项:

// Returns the /root/node/element/@Value with @Name contained in @AttributeName SQL variable.
SELECT @Xml.value('(/root/node/element[@Name=sql:variable("@AttributeName")]/@Value)[1]', 'varchar(100)')

// Returns the text of the child element of /root/node with the name contained in @ElementName SQL variable.
SELECT @Xml.value('(/root/node/*[name(.)=sql:variable("@ElementName")]/text())[1]', 'varchar(100)')

// Searching the xml hierarchy for elements with the name contained in @ElementName and returning the text().
SELECT @Xml.value('(//*[name(.)=sql:variable("@ElementName")]/text())[1]', 'varchar(100)')

需要声明@ElementName或@AttributeName SQL变量来运行这些。 我测试的第一条语句,但还没有明确测试的其他2条语句,仅供参考。



文章来源: The argument 1 of the XML data type method “value” must be a string literal
标签: xml tsql