FOR XML 无法序列化节点 NoName 的数据 - 无法替换 XML 字符

Cra*_*aig 5 xml sql sql-server

我正在使用 SQL Server 2014,我试图从表中的数据中删除 XML 字符,并且对于大多数 XML 字符我都成功了。但我对这个字符有疑问:0xDE7B

我有一个包含 STUFF 函数的 T-SQL 语句:

SELECT DISTINCT
    b.[Doc#],
    STUFF((SELECT '; ' + ltrim(rtrim(a.[MyColumn]))
           FROM #temp th
           WHERE a.[Doc#] = b.[Doc#]
           GROUP BY ltrim(rtrim(a.[MyColumn]))
           FOR XML PATH (''), TYPE).value('(./text())[1]', 'varchar(max)'), 1, 2, '') [MyColumn]
Run Code Online (Sandbox Code Playgroud)

我收到以下错误:

消息 6841,级别 16,状态 1,第 547 行
FOR XML 无法序列化节点“NoName”的数据,因为它包含 XML 中不允许的字符 (0xDE7B)。要使用 FOR XML 检索此数据,请将其转换为二进制、varbinary 或图像数据类型并使用 BINARY BASE64 指令。

但是当我执行以下操作时:

REPLACE([MyColumn], CHAR(0xDE7B), '')
Run Code Online (Sandbox Code Playgroud)

这最终会将该列中的所有值清空。我有一个函数可以删除所有其他 XML 字符(即 0x0000、0x0001、0x0002...),并且它似乎对它们有效。

Shn*_*ugo 6

有问题的字符是 \xef\xbf\xbd

\n

您不应尝试使用自己的替换逻辑来删除禁用字符。可能的候选人有很多。即使这可行,明天您可能会得到一个新的,您没有想到... XML 正在隐式地为您做这件事。尝试这个:

\n
SELECT (SELECT 'This inlcudes forbidden characters like < & > and your \xef\xbf\xbd' AS [*] FOR XML PATH(''));\n
Run Code Online (Sandbox Code Playgroud)\n

结果将是“This inlcudes forbidden characters like &lt; &amp; &gt; and your ?

\n

引擎显然使用了一个简单的问号而不是\xef\xbf\xbd。原因是缺少N,因此您的字符串被视为VARCHAR(=ASCII)。只需尝试与领先的相同N即可恢复特殊字符:

\n
SELECT (SELECT N'This inlcudes forbidden characters like < & > and your \xef\xbf\xbd' AS [*] FOR XML PATH(''));\n
Run Code Online (Sandbox Code Playgroud)\n

您可以像这样在代码中使用它

\n
SELECT DISTINCT\n    b.[Doc#],\n    STUFF((SELECT '; ' + ltrim(rtrim((SELECT a.[MyColumn] AS [*] FOR XML Path('')))) --<-- a.MyColumn should be NVARCHAR(X)\n           FROM #temp th\n           WHERE a.[Doc#] = b.[Doc#]\n           GROUP BY ltrim(rtrim((SELECT a.[MyColumn] AS [*] FOR XML Path(''))))\n           FOR XML PATH (''), TYPE).value('(./text())[1]', 'nvarchar(max)'), 1, 2, '') [MyColumn]\n
Run Code Online (Sandbox Code Playgroud)\n

确保永远不要让任何人VARCHAR干扰。所有涉及的列和所有涉及的步骤(函数(!))必须接受NVARCHAR并返回NVARCHAR

\n

因此我将你的 Final 的返回类型更改.value()nvarchar(max)

\n