在SQL Server中,确定给定字符串是否为有效XML的最佳方法是什么?

Ven*_*kat 15 xml t-sql sql-server-2005

第三方组件正在填充nvarchar表中具有某些值的列.大多数情况下,它是一个人类可读的字符串,但偶尔它是XML(如果在第三方comp中有一些内部异常).

作为一个临时解决方案(直到他们修复它并始终使用字符串),我想解析XML数据并提取实际消息.

环境: SQL Server 2005; 字符串总是小于1K; 这张表中可能有几千行.


我遇到了几个解决方案,但我不确定它们是否足够好:

  1. 调用sp_xml_preparedocument存储过程并将其包装在TRY/CATCH块周围.检查返回值/句柄.
  2. 编写托管代码(在C#中),再次异常处理并查看它是否是有效字符串.

这些方法似乎都没有效率.我正在寻找类似于ISNUMERIC():ISXML()函数的东西.还有其他更好的检查字符串的方法吗?

Mik*_*son 9

我想解析XML数据并提取实际的消息.

也许没有必要检查有效的XML.您可以在case语句中检查是否存在相应的xml标记,charindex并使用提取错误消息substring.

这是一个带有简化XML字符串的示例,但我认为您可以理解.

declare @T table(ID int, Col1 nvarchar(1000))

insert into @T values
(1, 'No xml value 1'),
(2, 'No xml value 2'),
(3, '<root><item>Text value in xml</item></root>')

select
  case when charindex('<item>', Col1) = 0
  then Col1
  else
    substring(Col1, charindex('<item>', Col1)+6, charindex('</item>', Col1)-charindex('<item>', Col1)-6)
  end  
from @T
Run Code Online (Sandbox Code Playgroud)

结果:

No xml value 1
No xml value 2
Text value in xml
Run Code Online (Sandbox Code Playgroud)


Mag*_*ier 5

根据公认的答案,我创建了此代码以检查有效的XML,并可以选择将输入字符串转换为XML(或从XML中提取所需的元素/属性),因为我发现TRY_CONVERT可以成功地工作,以防您只是简单地传递文本,这是我没有想到的,因此需要再次检查以防止最终转换为XML,以防万一,如果源列仅包含一些文本(示例行1),则需要这样做:

declare @T table(ID int, Col1 nvarchar(1000))
insert into @T values
(1, 'random text value 1'),
(2, '<broken> or invalid xml value 2'),
(3, '<root><item>valid xml</item></root>')
select id, Col1,
 Converted_XML = CASE 
        when [Col1] IS NULL THEN NULL                   /* NULL stays NULL */ 
        when TRY_CONVERT(xml, [Col1]) is null THEN NULL /* Xml Document Error */
        when CHARINDEX('<', [Col1]) < 1 AND CHARINDEX('>', [Col1]) < 1 THEN NULL        /* no xml */
        else CONVERT(xml, [Col1])                       /* Parsing succesful. => in this case you can convert string to XML and/or extract the values */
    END,
    Result_Comment = CASE 
        when [Col1] IS NULL THEN 'NULL always stays NULL'
        when TRY_CONVERT(xml, [Col1]) is null THEN 'Xml Document Error'
        when CHARINDEX('<', [Col1]) < 1 AND CHARINDEX('>', [Col1]) < 1 THEN 'no xml'
        else [Col1]
    END
FROM @T ;
Run Code Online (Sandbox Code Playgroud)