使用T / SQL FOR XML技巧进行连接时,如何对值分隔符进行实体编码

时间:2019-04-15 11:40:20

标签: sql-server xml tsql

我正在使用T / SQL FOR XML技巧将一组值与定界符连接起来。我想对值中的定界符(在本例中为|)进行实体编码,但是FOR XML重新编码|。所以我最终以|

if object_id('tempdb..#t') is not null drop table #t
create table #t (v varchar(100))
insert #t(v) values ('Foo'),('A|B'),('Bar')

select (
    select '|' + v AS [text()]
    FROM #t
    FOR XML PATH ('')
) + '|' as vConcat

-- Result of above = |Foo|A|B|Bar| -- delimiter in A|B not escaped

select (
    select '|' + replace(v, '|', '|') AS [text()] 
    FROM #t
    FOR XML PATH ('')
) + '|' as vConcat

-- Result of above = |Foo|A|B|Bar| -- delimiter double-escaped

有没有办法让FOR XML编码其他字符?还是有更好的方法在FOR XML中实现转义分隔符?

使用其他定界符不是我要找的答案。

我知道将整个表达式包装在替换中以撤消double编码是可行的,但是这并不使我感到非常优雅。

select replace((
    select '|' + replace(v, '|', '|') AS [text()] 
    FROM #t
    FOR XML PATH ('')
) + '|', '|', '|') as vConcat

-- Result of above = |Foo|A|B|Bar|

修改

为使问题更清楚,我想对常用的特殊XML字符进行实体编码(仅在原始值内)

if object_id('tempdb..#t') is not null drop table #t
create table #t (v varchar(100))
insert #t(v) values ('F&o'),('A|B'),('Bar'),('A|B')

select (
    select '|' + v AS [text()]
    FROM #t
    FOR XML PATH ('')
) + '|' as vConcat

-- Result of above = |F&o|A|B|Bar|A|B| -- special chars encoded but not delimiter in A|B value

select (
    select '|' + replace(v, '|', '|') AS [text()] 
    FROM #t
    FOR XML PATH ('')
) + '|' as vConcat

-- Result of above = |F&o|A|B|Bar|A|B| -- delimiter in A|B value double-encoded

-- Desired result = |F&o|A|B|Bar|A|B|

1 个答案:

答案 0 :(得分:1)

您可以在XML上使用value()

SELECT (SELECT '|' + replace(v, '|', '|') AS [text()]
               FROM #t
               FOR XML PATH (''), TYPE).value('.', 'varchar(max)') + '|' vconcat;

db<>fiddle