XML解析:第1行,字符345,重复属性

时间:2019-05-05 09:48:37

标签: sql-server

我正在尝试从XML列中获取特定的属性值,但出现错误

  

XML解析:第1行,字符345,重复属性

我的代码:

select 
    ship_to_cust_num,
    tank_num,
    tank_capacity_qty,
    tank_pkg_type_code,
    COALESCE(REPLACE(CAST(CAST(b.tank_inspection AS NTEXT) AS XML).value('(/TankInspection/Questions/Question[@AASAQno="9"]/@QAns)[1]', 'VARCHAR(50)'), '#', ''), 0)
from 
    bulk_site_tank (nolock)b
where 
    convert(varchar, b.tank_inspection) != 'NULL'

1 个答案:

答案 0 :(得分:1)

简单的答案是错误告诉您问题所在。但是要进一步解释。采取以下简单的声明:

DECLARE @xml varchar(MAX);

SET @XML = '
<root>
    <child>
        <element attribute="1">value</element>
        <element attribute="2" attribute="2">Another Value</element>
    </child>
</root>';

SELECT *
FROM (VALUES(CONVERT(xml, @XML)))V(X);

如果运行该命令,则会收到错误消息:

  

消息9437,级别16,状态1,第11行XML解析:第5行,字符46,重复属性

毫不奇怪,就像您看到的那样,第二个element节点被attribute声明了两次。


那么,如何解决这个问题?

首先,这意味着您将XML数据存储为xml数据类型以外的数据类型。 XML应该使用xml数据类型存储(这正是它的用途),并且只能在其中存储有效的XML。结果,您将无法在行中插入无效的XML,也不会处于该位置。就像你一样,你只能做一件事。找到所有“不良”行:

SELECT tank_inspection
FROM bulk_site_tank
WHERE TRY_CONVERT(xml,tank_inspection) IS NULL
  AND tank_inspection IS NOT NULL;

然后检查上述数据集中返回的每一行并修复数据。使其成为有效的XML。然后,修复您的数据类型:

ALTER TABLE bulk_site_tank ALTER COLUMN tank_inspection xml;

现在所有内容都是有效的XML,您可以修复自己的查询:

SELECT ship_to_cust_num,
       tank_num,
       tank_capacity_qty,
       tank_pkg_type_code,
       REPLACE(b.tank_inspection.value('(/TankInspection/Questions/Question[@AASAQno="9"]/@QAns)[1]', 'varchar(50)'), '#', '') --AS ?
FROM bulk_site_tank b
WHERE b.tank_inspection IS NOT NULL;

请注意,我更改为ANSI_NULL语法,并摆脱了NOLOCK(因为我假设您不知道它在这里实际做什么)。 CAST / CONVERT表达式也消失了,我已经删除了COALESCE。当您的value表达式返回varchar(50)时,COALESCE的第二个参数为0。这样会将XML返回的值隐式转换为int,并可能导致转换错误。

不过,恐怕要由您来清理数据,恐怕没有人可以帮助您。这只是为什么数据类型选择不当会成为问题的原因之一;就像我之前说过的,就好像使用了正确的数据类型一样,永远也不会插入无效的XML。

祝你好运!