如何将所有HTML img close标签转换为符合XML标签? (<img/>到<img/>)

时间:2017-02-26 17:44:22

标签: asp.net sql-server regex xml-parsing sql-server-2014

任务:我们正在通过HttpWebRequest(大约6,000次调用)抓取内容的HTML。修剪此字符串并将其存储在SQL Server 2014数据库中,以便以XML格式进行处理。

问题:在SQL Server中,由于图像标记,我们会收到XML解析错误:“...end tag does not match start tag”。

现在,我在SQL Server中有一个相当不优雅且 可能 有缺陷的解决方案。

示例字符串

<div someattr="aaa">
    <div class="bbb">Some Text</div>
    <img src="image.jpg" width="150">      <-- Notice the lack of />
</div>

期望的结果

<div someattr="aaa">
    <div class="bbb">Some Text</div>
    <img src="image.jpg" width="150"/>      <-- Notice the />
</div>

我在ASP.Net中尝试过无数的Regex组合,而且我似乎弊大于利。任何指导或指示都将不胜感激。

此致,

约翰

4 个答案:

答案 0 :(得分:2)

我建议您使用HTML解析器并以比字符串更好的方式存储数据。但是,如果您正在使用正则表达式来寻找快速而肮脏的解决方案,这可能会对您有所帮助:

寻找这个正则表达式:

(<img[^>]*?[^\/]\s*)(>)

并将其替换为:

$1/$2
  • [^>]*?查找除>之外的任何字符,但尽可能少
  • [^\/]\s*确保>之前的最后一个字符不是斜杠/或者不是斜杠后跟空格
  • 第一部分和第二部分分为$1$2。它只会匹配,如果还没有斜杠,并且它是img标记。
  • 如果>标记之间有<img ...>个字符作为字符串,或者标记未在<img title=""完全关闭,那么它就无法工作。

以下是一个实例:https://regex101.com/r/HIxIIR/1

答案 1 :(得分:1)

首先尝试将你的html转换为xhtml,那里有一些转换器。正则表达式和HTML也不适合我...

答案 2 :(得分:1)

不幸的是,HTML不一定是有效的XML(XHTML除外)。所以你期待未封闭的标签。 HTML明确地允许某些标签像<br >一样未被封闭,并且即使存在实际缺失甚至重叠的标签,也可以构建为健壮,即使在HTML中也是如此。

根据您期望的HTML,您可以尝试将其中一些错误更正为XML。例如,您知道在具有不同属性值和内容的所有结构上它总是相同的。如果你得到的HTML可以是任何东西,我恐怕你运气不好。也许您可以将其存储为NVARCHAR(MAX),如果您需要在数据库中查询它,请使用LIKE

答案 3 :(得分:1)

下面是一个只使用T-SQL的快速而肮脏的解决方案。

Rextester演示:http://rextester.com/TLF34624

CREATE FUNCTION processHtml(@html VARCHAR(MAX))
RETURNS VARCHAR(MAX)
AS
BEGIN
    DECLARE @remainingHtml VARCHAR(MAX),
            @processedHtml VARCHAR(MAX),
            @imgPos INT,
            @closingAngleBracketPos INT,
            @openingAngleBracketPos INT;
    SET @remainingHtml = @html;
    SET @imgPos = PATINDEX('%<img%[^</]>%', @remainingHtml);
    WHILE @imgPos > 0
    BEGIN
        SET @processedHtml = CONCAT(@processedHtml, SUBSTRING(@remainingHtml, 1, @imgPos - 1));
        SET @remainingHtml = SUBSTRING(@remainingHtml, @imgPos, LEN(@remainingHtml));
        SET @closingAngleBracketPos = PATINDEX('%[^/]>%', @remainingHtml);
        SET @openingAngleBracketPos = CHARINDEX('<', @remainingHtml, 2);
        IF @closingAngleBracketPos < 0
            SET @imgPos = -1;
        ELSE IF @closingAngleBracketPos < @openingAngleBracketPos
        BEGIN
            SET @processedHtml = CONCAT(@processedHtml, SUBSTRING(@remainingHtml, 1, @closingAngleBracketPos), '/>');
            SET @remainingHtml = SUBSTRING(@remainingHtml, @closingAngleBracketPos + 2, LEN(@remainingHtml));
            SET @imgPos = PATINDEX('%<img%[^</]>%', @remainingHtml);
        END
        ELSE
        BEGIN
            SET @processedHtml = CONCAT(@processedHtml, SUBSTRING(@remainingHtml, 1, @openingAngleBracketPos - 1));
            SET @remainingHtml = SUBSTRING(@remainingHtml, @openingAngleBracketPos, LEN(@remainingHtml));
            SET @imgPos = PATINDEX('%<img%[^</]>%', @remainingHtml);
        END
    END

    SET @processedHtml = CONCAT(@processedHtml, @remainingHtml);
    RETURN @processedHtml;
END