Error - FOR XML could not serialize the data for node 'NoName'

brenda grossnickle 206 Reputation points
2025-05-17T22:00:51.08+00:00

I am using FOR XML to concatenate varchar data. The data came from user input so it could have garbage characters. Getting the "Error - FOR XML Could Not Serialize the data for node NoName". Not really picky about what to do with the bad data, could stay, could be replaced with '' empty string, don't really care. There are just a couple of bad data instances out of 77k rows. Just need the FOR XML to work.

 

below is some test data and to get it to work i added "ltrim(rtrim((SELECT [col1] AS [*] FOR XML Path(''))))" where it use to be just "col1". then added the update statements.

 

Really out of my depth here. what gotchas or suggestions do you have for my solution?

 
/***** create test data *****/
 
drop table temp.#test
 
create table #test (recid int identity, col1 varchar(126))
 
insert into #test (col1) values
 
                ('aaa'),
 
    ('ccc' + cast(0x1A as varchar(30)) + 'bbb'),
 
                ('"ddd <e' )
 
/****** Use STUFF, FOR XML to concatenate rows *******/
 
drop table temp.#list_complete
 
declare @SQLStuff nvarchar(max) = ''
 
SELECT @SQLStuff =
 
    STUFF((SELECT ';      ' + ltrim(rtrim((SELECT [col1] AS [*] FOR XML Path(''))))
 
           FROM #test
 
           FOR XML PATH (''), TYPE).value('(/text())[1]', 'varchar(max)'), 1, 2, '')
 
select * into #list_complete from
 
                (select cast( @SQLStuff as varchar(128)) as codes)a
 
/******* update XML escape characters ********/
 
update #list_complete set codes = replace(codes, '&lt;', '<')
 
update #list_complete set codes = replace(codes, '&gt;', '>')
 
update #list_complete set codes = replace(codes, '&apos;', '''')
 
update #list_complete set codes = replace(codes, '&quot;', '"')
 
update #list_complete set codes = replace(codes, '&amp;', '&')
 
select * from #list_complete

 

SQL Server Transact-SQL
SQL Server Transact-SQL
SQL Server: A family of Microsoft relational database management and analysis systems for e-commerce, line-of-business, and data warehousing solutions.Transact-SQL: A Microsoft extension to the ANSI SQL language that includes procedural programming, local variables, and various support functions.
197 questions
{count} votes

2 answers

Sort by: Most helpful
  1. Erland Sommarskog 121.3K Reputation points MVP Volunteer Moderator
    2025-05-18T09:46:12.0933333+00:00

    As Viorel says, the best solution string_agg; then you don't have to fight these restrictions. But I have a recollection that you need to support anitque versions of SQL Server. string_agg reqiures SQL 2017.

    I'm leaning towards that it is better to get the garbage out before you do the FOR XML thing. Here is code to remove all control characters from 0 to 31:

    drop table temp.#test
     
    create table #test (recid int identity, col1 varchar(126))
     
    insert into #test (col1) 
       values ('aaa'),
              ('ccc' + cast(0x1A as varchar(30)) + 'bbb'),
              ('"ddd <e' )
    
    -- Code to remove control characters
    declare @pat char(7) = concat('%[', char(0), '-', char(31) + ']%')
    while 1 = 1
    begin
       update #test
       set    col1 = substring(col1, 1, patindex(@pat collate French_BIN2, col1) - 1) +
                     substring(col1, patindex(@pat collate French_BIN2, col1) + 1, len(col1)) 
       where  col1 LIKE @pat collate French_BIN2
       if @@rowcount = 0
          break
    end
     
    /****** Use STUFF, FOR XML to concatenate rows *******/
    drop table temp.#list_complete
    declare @SQLStuff nvarchar(max) = ''
    SELECT @SQLStuff =
        STUFF((SELECT ';      ' + ltrim(rtrim(col1))
               FROM #test
               FOR XML PATH (''), TYPE).value('(/text())[1]', 'varchar(max)'), 1, 2, '')
                    (select cast( @SQLStuff as varchar(128)) as codes)a
     
    SELECT * FROM #list_complete
    

    Don't worry about the French. We want a binary collation, and French is shorter than Latin1_General.

    The exact range of characters may need some fine-tuning. There may be more characters to add. On the other hand, you may want to permit for tag, carriage return and line feed.


  2. Yitzhak Khabinsky 26,571 Reputation points
    2025-05-19T23:21:33.5766667+00:00

    Hi @brenda grossnickle,

    You can use the following T-SQL to identify rows with questionable characters for the XML data type. It will work starting from SQL Server 2012 onwards.

    Casting by using the TRY_CAST(... AS XML) does all magic. The questionable strings will have NULL values at the end for your analysis.

    -

    - DDL and sample data population, start
    DECLARE @test table (recid INT IDENTITY PRIMARY KEY, col1 VARCHAR(126));
    INSERT @test (col1) VALUES 
    ('aaa'),
    ('ccc' + cast(0x1A as varchar(30)) + 'bbb'),
    ('"ddd <e');
    -- DDL and sample data population, end
      
    -- Code to identify 'bad' strings in a row
    WITH rs AS
    (
    	SELECT * 
    		, TRY_CAST('<r>' + col1 + '</r>' AS XML) AS xml_type
    	FROM @test
    )
    SELECT * FROM rs
    WHERE xml_type IS NULL;
     
    
    0 comments No comments

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.