如何从SQLServer中的FOR XML PATH查询中剥离非法字符

时间:2019-03-28 11:22:25

标签: sql-server for-xml-path

我有一个SQL Server表,该表以XML形式从XML中提取数据

SELECT * FROM myTable FOR XML PATH( 'myElement' ), ROOT( 'myDocument' ), TYPE

通过某种方式,用户设法将控制字符输入到自由文本字段(Ctrl-V)中,这意味着上面的查询失败并显示错误:

FOR XML could not serialize the data for node 'MYFIELDNAME' because it contains a character
(0x0016) which is not allowed in XML. To retrieve this data using FOR XML, convert it into
binary, varbinary, or use the BINARY BASE64 directive. 

由于我期望数据是文本,所以我不想将其转换为二进制形式,而是在源代码中去除所有无效的XML字符。

我在SO上找到了以下内容:

How to make FOR XML PATH not choke on ASCII Control Codes

但是它没有帮助,因为它不能解决最初提出的问题,但是可以纠正OP对XML规范的误读。

是否存在全局指导SQL Server去除无效字符而不是生成此错误的任何东西?

谢谢!

1 个答案:

答案 0 :(得分:0)

在转换为XML之前,您必须使用代码剥离字符。 通常,我会使用以下逻辑通过CTE进行此操作,然后在cte上使用FOX XML。

这不是最有效的,但可以解决问题:

    Select @FileDatePart = CONVERT(VARCHAR(MAX),Getdate(), 22)

    Select @FileDatePart = Replace(@FileDatePart, a.search, a.replace)
    From (
    Values ( '/', '' )
    ,      ( ':', '' )
    ,      ( ' ', '' )

    ) As a([Search], [Replace])

要使用ASCII码

    Select @FileDatePart = Replace(@FileDatePart, a.search, a.replace)
    From (
    Values (char(47), '' )
    ,      ( char(58), '' )
    ,      ( char(32), '' )

    ) As a([Search], [Replace])

用于ASCII值表

DECLARE @i INTEGER = 0
DECLARE @j INTEGER = 0
DECLARE @Step INTEGER = 16
DECLARE @Lim INTEGER = 255
DECLARE @aLine VARCHAR(MAX) = ''
DECLARE @Dec VARCHAR(MAX) = ''

SELECT  @Dec += 'Declare @i AS INTEGER = 1' + CHAR(13) + 'Declare @step as integer = ' + CAST(@Step AS VARCHAR(25)) + CHAR(13) + 'While @i * @Step < ' + CAST(@Lim AS VARCHAR(25)) + ' Begin  '
                + CHAR(13)

WHILE(@i < @Step)
    BEGIN
        SELECT  @i += 1
        SELECT  @aLine =
            @aLine + ' @i -1 + ' + CAST(@i AS VARCHAR(25)) + ' as Col' + CAST(@i AS VARCHAR(25)) + ', Isnull(cast(char(@i +' + CAST(@i - 1 AS VARCHAR(25)) + ') as Varchar(25)),''*NA*'') as VAL'
            + CAST(@i AS VARCHAR(25)) + CASE
                                            WHEN @i < @Step THEN ','
                                            ELSE ''
                                        END
    END

SELECT  @i = 1
DECLARE @output VARCHAR(MAX) = 'Select ' + REPLACE(@aLine, '@i', CAST(@i + @j AS VARCHAR(5)))

SELECT  @i += @Step
WHILE @i <= @Lim
    BEGIN
        SELECT  @output += CHAR(13) + 'union Select ' + REPLACE(@aLine, '@i', CAST(@i + @j AS VARCHAR(5)))
        SELECT  @i += @Step
    END
EXEC(@output)
GO