T-SQL:如何仅替换img标签上的src ='data:image / png; base64'属性的内容

时间:2019-05-17 11:46:07

标签: html xml tsql attributes xhtml

场景: 我有性能非常糟糕的asp.net mvc应用程序(案例管理系统),我发现它会导致性能下降。

每个活动都有诸如“活动名称”,“活动状态”,“创建依据”等字段,这些字段可以从数据库中快速加载,但是活动在带有富文本编辑器的数据库上也有两个html字段。 一些用户将图像从剪贴板直接粘贴到RTF编辑器中,粘贴的图像采用base64格式,如下所示:

<img src="data:image/png;base64,iVBORw0xdBXhUR...***HERE ARE 2.4 MILION SYMBOLS...***FvqlEIVCqUUL2ASUVORK5CYII=" alt="" />

一些img标签的“ src”属性(直接粘贴在编辑器上)包含240万个符号。我尝试仅选择其中两个粘贴图像的两个编辑器之一,执行查询结果为5.38秒(两个图像和一些文本仅用于一条记录)。因此,我决定在这些字段中查找所有img标签,并仅针对封闭活动将其src属性的内容替换为占位符图像。这可能会对性能产生积极影响。

我该怎么办: 我需要替换每个直接粘贴图像的src属性的内容。

它们之间的共同点是: 每个粘贴的图像字符串均以'img src =“ data:image / png; base64,”开头。

它们之间的区别:某些img标签用'>'关闭,另一些用'/>'

关闭

问题: 因为我不知道如何仅找到src属性的开头和结尾,所以我试图选择以img标记的“ img src =“开头和img的结尾(”/>")。

select LEFT(Notes, (CHARINDEX('<img src=',Notes)-1)) +'<PATH TO PLACEHOLDER>' + RIGHT(Notes, Len(notes) - 1 - CHARINDEX('/>', Notes, CHARINDEX('<img src=',Notes))) from assignedActivity
where oid in('7B8086C1-7AF8-457C-8163-109CF167EA5E')

我会提出任何建议: 如何只替换每个src属性的内容?

以下是html编辑器内容的外观:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
   <head>
      <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> 
      <title>Some activity</title>
   </head>
   <body>
   <img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAeIAAACxCAYAAAAYhL5OAAAgAElEQVR4AexdBXhUR9d+1y3unhBCggYvbqVAsQqFukG9pdSpUKHupe4uQFvqlEIVCqUUL24JhCQQ93X7n3d2b7LZbA7zewOWEjTzUAAAAASUVORK5CYII=" alt="" />
   </body>
</html>

1 个答案:

答案 0 :(得分:1)

使用HTML进行处理可能会很棘手,但是默认情况下,文档带有xhtml名称空间。让我想,我们可以依靠内部结构来获得有效的XML。

您可以在此处实现此目标:

-您的样本在字符串变量中

DECLARE @html NVARCHAR(MAX)=
N'<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
   <head>
      <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> 
      <title>Some activity</title>
   </head>
   <body>
   <img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAeIAAACxCAYAAAAYhL5OAAAgAElEQVR4AexdBXhUR9d+1y3unhBCggYvbqVAsQqFukG9pdSpUKHupe4uQFvqlEIVCqUUL24JhCQQ93X7n3d2b7LZbA7zewOWEjTzUAAAAASUVORK5CYII=" alt="" />
   </body>
</html>';

-首先,我们必须将HTML与<!DOCTYPE >声明分开:
-我走了简单的路,并使用第一个>来计算正确的位置,将其切成两段:

DECLARE @PosFirstClosing INT=CHARINDEX('>',@html);
DECLARE @DocType NVARCHAR(300)=SUBSTRING(@html,1,@PosFirstClosing);

-隐式转换会将HTML转换为XML。这是关键点。
-如果失败,则无法使用此方法。
-只需尝试一下并确保您的数据始终严格为 XHTML

DECLARE @xhtml XML=SUBSTRING(@html,@PosFirstClosing+1,4000);

-现在我们可以使用XML方法替换<img src="xyz">的值

DECLARE @plcHolder NVARCHAR(MAX)='blah';

SET @xhtml.modify('declare namespace ns="http://www.w3.org/1999/xhtml";
                   replace value of (/ns:html/ns:body/ns:img/@src)[1] with sql:variable("@plcHolder")');

-在XML查看器中检查结果

SELECT @xhtml;

-现在,我们可以通过将文档类型连接回裸HTML来重建完整的html。

SET @html=@DocType + CAST(@xhtml AS NVARCHAR(MAX));

-这是结果:

SELECT @html

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
    <title>Some activity</title>
  </head>
  <body>
    <img src="blah" alt=""/>
  </body>
</html>

备注

这预计将只替换一个图像源。如果其中可能有更多,或者位置可能不是/html/body/img,则可以调整XPath或引入一些XQuery。但您的问题与此无关。因此随和...