从字符串中删除HTML标记不能按预期方式工作

时间:2016-06-13 12:00:29

标签: xml string tsql xhtml special-characters

我有一个函数可以从给定的XML字符串中删除HTML标记,如下所示:

ALTER FUNCTION dbo.fGetTextWithoutHtml
(
    @Html XML
)
RETURNS NVARCHAR(2000)
AS
BEGIN
    DECLARE @text NVARCHAR(2000) = CONVERT(NVARCHAR(2000), @html)
    DECLARE @start INT
    DECLARE @end INT
    DECLARE @length INT

    SET @start = CHARINDEX('<', @text)
    SET @end = CHARINDEX('>', @text, CHARINDEX('<', @text))
    SET @length = (@end - @start) + 1
    WHILE @start > 0 AND @end > 0 AND @length > 0
    BEGIN
        SET @text = STUFF(@text, @start, @length, '')
        SET @start = CHARINDEX('<', @text)
        SET @end = CHARINDEX('>', @text, CHARINDEX('<', @text))
        SET @length = (@end - @start) + 1
    END
    RETURN LTRIM(RTRIM(@text))
END

输入XML如下所示:

  

<html xmlns="http://www.w3.org/1999/xhtml" xml:space="preserve"> <p>​- This is a string.<br /></p></html>

预期输出为:

  

“ - 这是一个字符串。”

但是当我使用我的功能时,我得到一个奇怪的结果。如果我将其复制到编辑器,输出如下所示:

  

- 这是一个字符串。”

如果我将结果直接复制到SQL Server编辑器,它会在开头获得一个额外的(更宽的)连字符:

  

- 这是一个字符串。”

如何在没有HTML标签,附加连字符和前导空格的情况下获取字符串?

修改

我试图找出输入字符串中是否存在不可打印的字符:

PRINT CONVERT(NVARCHAR(2000), @html)

结果如下:

<html xmlns="http://www.w3.org/1999/xhtml" xml:space="preserve"> &#x20;<p>​- This is a string.<br /></p></html>

我的字符串中有&#x20。但是当我改变了

RETURN LTRIM(RTRIM(@text))

RETURN LTRIM(RTRIM(REPLACE(@text, '&#x20;', '')))

结果看起来一样(空格和附加连字符仍在那里)......

1 个答案:

答案 0 :(得分:2)

当您将HTML作为XML传递并且有一个“xhtml”命名空间时,我建议您使用XML方法读取您的内容:

DECLARE @x XML = N'<html xmlns="http://www.w3.org/1999/xhtml" xml:space="preserve"> <p>​- This is a string.<br /></p></html>';
WITH XMLNAMESPACES(DEFAULT 'http://www.w3.org/1999/xhtml')
SELECT Each.node.value('(text())[1]','nvarchar(max)') AS pContent
FROM @x.nodes('/html//*') Each(node)

结果看起来是正确的,但在连字符之前有一个不可打印的符号(你可以通过将光标移到这个文本上看到这一点。有一个位置,你的光标不会移动......现在尝试相同的代码< em>没有前导“N”。现在你在连字符前面得到一个问号。这是一个 unicode 符号,没有为VARCHAR定义... < / p>

尝试使用此代码按字节读取unicode字符串:

CREATE FUNCTION dbo.SingleBytes(@SomeText NVARCHAR(MAX))
RETURNS TABLE
AS
RETURN
WITH nr10 AS
(
    SELECT * FROM (VALUES(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) AS tbl(A)
)
,RunningNumbers AS
(
    SELECT TOP (ISNULL(DATALENGTH(@SomeText),0)) ROW_NUMBER() OVER(ORDER BY (SELECT(NULL))) AS Nmbr FROM nr10,nr10 AS a,nr10 AS b,nr10 AS c,nr10 AS d,nr10 AS e,nr10 AS f,nr10 AS g
)
,ByteWise AS
(
    SELECT CAST(CAST(@SomeText AS VARBINARY(MAX)) AS VARCHAR(MAX)) AS ByteWiseText
)
SELECT SUBSTRING(ByteWiseText,Nmbr,1) AS TheCharacter
      ,ASCII(SUBSTRING(ByteWiseText,Nmbr,1)) AS ASCII_Code
FROM ByteWise,RunningNumbers;
GO

SELECT * FROM dbo.SingleBytes(N'<html xmlns="http://www.w3.org/1999/xhtml" xml:space="preserve"> <p>​- This is a string.<br /></p></html>');
GO

DROP FUNCTION dbo.SingleBytes;

您会发现>-之间有11-32,即0B20, find details here

这可能是列表的主要标志吗?

无论如何:您可以这样定义:

DECLARE @EvilChar NVARCHAR(1)=CAST(CAST(CHAR(11) + CHAR(32) AS VARBINARY(2)) AS NVARCHAR(1));

您可以在REPLACE ...

中使用此变量 祝你好运: - )