必须先调用sp_xml_preparedocument获取句柄,否则openxml因句柄为空报“invalid xml document”错误;句柄为int output变量,须配对sp_xml_removedocument防泄漏,并正确处理命名空间、flags标志位、xpath路径及xsinil空值映射。

必须先调用 sp_xml_preparedocument,否则 OPENXML 直接报错“Invalid XML document”——这不是XML语法问题,是句柄为空导致的假性解析失败。
句柄声明与生命周期管理
句柄不是可选配置,而是强制中间状态:它是一个整数变量,必须显式声明为 INT 类型并带 OUTPUT 属性。漏掉 OUTPUT 或用 NULL 初始化都会让后续 OPENXML 返回空结果集。
-
@hdoc INT OUTPUT是唯一合法声明方式;@hdoc = NULL或未赋值就传入会触发静默失败 - 每次
sp_xml_preparedocument成功后,必须配对调用sp_xml_removedocument @hdoc,否则内存持续泄漏(尤其在高频调用的存储过程中) - 不能复用句柄:同一
@hdoc变量不能跨多次 XML 解析循环使用,每次都要重新 prepare + remove
命名空间和 flags 标志位必须显式匹配
XML 带 xmlns 时,默认完全不可见;flags 值选错会导致字段全为 NULL 且无任何提示。
- 若 XML 含命名空间(如
<root xmlns="http://a.com"><item id="1"></item></root>),必须在sp_xml_preparedocument第三个参数中声明:N'xmlns:ns="http://a.com"',并在 XPath 中前缀ns: -
flags = 0:只取属性(@id可读,<name></name>内容丢失) -
flags = 1:只取子元素(<name>Tom</name>可读,@id不可见) -
flags = 2:两者都映射(推荐起步值,但需注意WITH中列名不能重复)
WITH 子句中的 XPath 是相对路径,不是绝对路径
WITH 里写的路径基于 OPENXML 的第二个参数(节点路径)定位后的上下文,写成绝对路径反而查不到数据。
- XML 示例:
<root><user><uid>100</uid><nick>Tom</nick></user></root> - 若
OPENXML第二个参数为'/root/user',则WITH中应写uid INT 'uid'或uid INT './uid',不能写'/root/user/uid' - 字符串字段务必指定长度:
nick NVARCHAR(50) 'nick',不写默认NVARCHAR(100),可能截断长昵称 - 缺失节点要映射为
NULL,必须加XSINIL:email NVARCHAR(100) 'email' XSINIL
XML 字符串预处理不可省略
传入的 XML 字符串若含未转义的 &、、<code>>,sp_xml_preparedocument 会直接报错“illegal xml character”,错误位置提示毫无意义。
- 最稳妥做法是在调用存储过程前由应用层做 HTML 实体编码
- 若只能在 SQL 内处理,需用
REPLACE预清洗:SET @xml = REPLACE(REPLACE(REPLACE(@xml, '&', '&'), '', '>') - 日期字段要求严格 ISO 格式(
2023-10-05T14:30:00),否则转成NULL且无警告
真正容易被忽略的是:句柄泄漏在开发环境几乎不暴露问题,但上线后高频调用几分钟就会耗尽内存;而 XSINIL 和命名空间声明这两个点,一旦漏掉,数据就静默丢失,日志里连 warning 都没有。










