TSQL 从 HTML 中删除带有特定 src 的 img 标签

Posted

技术标签:

【中文标题】TSQL 从 HTML 中删除带有特定 src 的 img 标签【英文标题】:TSQL remove img tag with specific src from HTML 【发布时间】:2016-12-06 14:07:40 【问题描述】:

我的数据库中有一个带有许多 img 标签的 html 文本。我的目标是删除带有特定 src 的 img 标签

我的输入是

<div>
    <p>some text goes here <img  src="/upload/remove-me.png" /></p>
    <p>some other text goes here <img  src='/upload/remove-me.png'  /></p>    
    <p>some other text goes here <img src="/upload/filename.png" /></p>
</div>

我想删除我的输出结果为 src="/upload/remove-me.png" 的所有图像

<div>
    <p>some text goes here</p>
    <p>some other text goes here</p>
    <p>some other text goes here <img src="/upload/filename.png" /></p>
</div>

有没有办法在 TSQL 中使用正则表达式?

【问题讨论】:

tsql 不支持正则表达式,除了 clr 函数。我建议在 sql server 之外执行此操作。 【参考方案1】:

如果img 作为一个整体是不变的(不仅仅是src):

<img  src='/upload/remove-me.png'  />

那么你可以使用一个简单的REPLACE,像这样:

UPDATE tablename SET columnname=REPLACE(
  columnname,
  N' <img  src=''/upload/remove-me.png''  />',
  N''
)
WHERE columnname LIKE N'% <img  src=''/upload/remove-me.png''  />%'

标签前的空格是有意的。 如果标记存储在ntext 列中,请先转换为nvarchar(max),否则REPLACE 将失败。

如果这不是一次性数据更正的任务,您应该将其包含在您的业务逻辑层中。

【讨论】:

这不起作用,因为即使问题中给出的示例数据也没有统一的属性。 正确。如果 OP 可以将其限制为一组已知的排列,他可以每个都做一个UPDATE。否则,您上面的解决方案显然更适合此任务 替换不是一个选项,在我的示例中,我发布了我可能拥有的不同变体。所以需要一些通用的东西【参考方案2】:

从您的示例看来,标签的属性可以按任何顺序排列,因此我们需要遍历文本以一次取出一个 img 标签。显然,您需要在数据的备份版本上尝试此操作,以确保它只删除您想要删除的内容:

declare @HTML table(a nvarchar(max)) 
insert into @HTML
select 
'<div>
    <p>some text goes here <img  src="/upload/remove-me.png" /></p>
    <p>some other text goes here <img  src="/upload/remove-me.png"  /></p>    
    <p>some other text goes here <img src="/upload/filename.png" /></p>
</div>'


declare @URL nvarchar(50) = 'src="/upload/remove-me.png"'   -- Search for img tags with this text in.
declare @TagStart int = -1
declare @TagEnd int = -1

while @TagStart <> 0
begin
    select @TagStart = patindex('%<img%' + @URL + '%/>%',a)-1       -- Find the start of the first img tag in the text.
            ,@TagEnd = patindex('%/>%'
                                        ,substring(a
                                        ,patindex('%<img%' + @URL + '%/>%',a)
                                        ,999999999
                                        )
                                )+1                                 -- Find the end of the first img tag in the text.
    from @HTML

    update @HTML                -- Update the table to remove just this tag
    set a = (select left(a,@TagStart) + right(a,len(a)-@TagStart-@TagEnd)
            from @HTML
            )

    select @TagStart = patindex('%<img%' + @URL + '%/>%',a)     -- Check if there are any more img tags with the URL to remove.  Will return 0 if there are none.
    from @HTML
end

select a as CleanHTML
from @HTML

【讨论】:

完全按预期工作。谢谢【参考方案3】:

XML DML 提供了更优雅的解决方案。很可能您的主表的 HTML 字段为 (n)varchar(max)),因此需要一个临时表。

declare @HTML table(id int, a xml) 
insert into @HTML
select id, html
from dbo.myTable
/* content of html field
'<div>
    <p>some text goes here <img  src="/upload/remove-me.png" /></p>
    <p>some other text goes here <img  src="/upload/remove-me.png"  /></p>    
    <p>some other text goes here <img src="/upload/filename.png" /></p>
</div>'
*/
update @html
set a.modify('delete //img[contains(@src,"remove-me")]') --delete nodes and update
from @HTML cross apply a.nodes('div') t(v)

--select * from @html --just to see what happens
update dbo.myTable
set html = h.a
from dbo.myTable t
inner join @html h on t.id = h.id

【讨论】:

确实非常优雅! 你的解决方案非常优雅,我喜欢它,但唯一的缺点是它需要有效的 xml 结构,不幸的是我的输入文本可能并不总是以 开头,它只能以纯文本开头没有任何标签 这也适用于纯文本。只需使用div 包装该字段即可。像这样insert into @HTML select id, '&lt;div&gt;'+html+'&lt;/div&gt;' from dbo.myTable【参考方案4】:

下面的函数应该可以完成这项工作。它只是找到目标图像名称的图像开始和结束标记,然后删除文本。

ALTER FUNCTION Html_RemoveImageAttributes
(
    @sourceImage        NVARCHAR(100),
    @inputHtml          NVARCHAR(MAX)
)
RETURNS NVARCHAR(MAX)
AS
BEGIN

    DECLARE @imageTagStart INT = CHARINDEX('<img ' , @inputHtml, 1);
    DECLARE @imageIndex INT = CHARINDEX(@sourceImage, @inputHtml, @imageTagStart);
    DECLARE @imageTagEnd INT = CHARINDEX('/>' , @inputHtml, @imageTagStart);

    DECLARE @outputHtml NVARCHAR(MAX) = @inputHtml;

    WHILE (@imageIndex > 0) 
    BEGIN

        IF (@imageIndex > @imageTagStart) AND (@imageIndex < @imageTagEnd)
        BEGIN

            -- Remove first occurrence of image.
            SET @outputHtml = REPLACE(@outputHtml, SUBSTRING(@outputHtml, @imageTagStart, @imageTagEnd - @imageTagStart + 2), '');

            SET @imageTagStart  = CHARINDEX('<img ' , @outputHtml);
            SET @imageIndex  = CHARINDEX(@sourceImage, @outputHtml);
            SET @imageTagEnd  = CHARINDEX('/>' , @outputHtml);
        END
        ELSE
        BEGIN

            SET @imageTagStart  = CHARINDEX('<img ' , @outputHtml, @imageTagEnd);
            SET @imageIndex  = CHARINDEX(@sourceImage, @outputHtml, @imageTagEnd);
            SET @imageTagEnd  = CHARINDEX('/>' , @outputHtml, @imageTagEnd + 1);

        END

    END


    RETURN @outputHtml

END

下面的例子展示了如何使用它:

DECLARE @sourceImage NVARCHAR(50) = 'remove-me.png';
DECLARE @input NVARCHAR(4000) = N'<div>
    <p>some text goes here <img  src="/upload/remove-me.png" /></p>
    <p>some other text goes here <img  src=''/upload/remove-me.png''  /></p>    
    <p>some other text goes here <img src="/upload/filename.png" /></p>
</div>';

PRINT dbo.Html_RemoveImageAttributes(@sourceImage, @input);

【讨论】:

以上是关于TSQL 从 HTML 中删除带有特定 src 的 img 标签的主要内容,如果未能解决你的问题,请参考以下文章

需要从本地 iframe 中的 src url 中删除页眉和页脚

用于从 CSV 中删除带有特定单词的行的批处理文件

TSQL 在事务中尝试/捕获,反之亦然?

如何在 C# 中执行包含带有“-”、“\”或“;”的字符串的 TSQL 输入命令

使用 TSQL OPENJSON 如何从具有动态键名的 JSON 数组中提取值

TSQL - 计算多语句表 UDF 中的特定值并将它们传递给附加列