4

我目前正在寻找一种解决方案,以从任意原始 HTML 片段中查找并列出任何未关闭的 HTML 标记。我不觉得这应该是一个可怕的问题,但我似乎无法在 JS 中找到能做到这一点的东西。不幸的是,这需要在客户端,因为它被用于向 HTML 页面呈现注释。很明显,注释是有点讨厌的事情,因为它们选择或应用的格式可能只适用于 HTML 元素的一部分(即,覆盖在现有 HTML 标记上的标记)。

一个简单的用例是您可能只想渲染 HTML 页面的一部分,然后再注入其余部分。例如,想象一个假设的片段:

<p>This is my text <StartDelayedInject/> with a comment I added. </p>
<p> But it doesn't exist until now. </p> <StopDelayedInject/>

我将进行一些预处理以重建 HTML,以便将部分元素包装到应用适当格式的跨度类型元素中。最初,这将以以下形式解析:

<p><span>This is my text</span></p>

在一些用户操作之后,它将被修改为如下形式:

<p><span>This is my text</span><span>with a comment I added.</span></p>
<p>But it doesn't exist until now.</p>

这是一个非常简化的示例案例(显然 ul 元素和表格之类的东西会变得更复杂),但给出了一般原则。但是,为了有效地做到这一点,我需要能够检查一段 HTML 并找出已打开(但未关闭)的标签。如果我知道该信息,我可以将最后一个未终止的文本数据包装到一个跨度中,关闭未关闭的标签,并知道在需要时返回该点以注入剩余的内容。但是,我需要知道仍然打开的标签,这样当我注入或修改另一段内容时,我可以确保将其放在正确的位置(例如,在第一段)。

根据我对上下文无关语法的理解,这应该是一项相对微不足道的任务。每次打开/输入或关闭/退出标签时,您可以只保留一堆打开但尚未关闭的标签。话虽如此,我更愿意使用一个更成熟的解决方案的库,而不是为此目的制作幼稚的解析器。我假设有一些 JS HTML 解析器可以做到这一点,对吧?他们中的很多人都知道如何关闭标签,所以他们在某个时候很清楚地计算了这一点。

4

2 回答 2

3

问题是 JavaScript 只能通过两种方式访问​​ html:

  1. 从某种意义上说,每个元素都是一个对象,具有由浏览器在页面加载时创建的属性和方法。
  2. 从某种意义上说,它是一串文本。

使用与 html 交互的第一种方法,无法检测未封闭的标签,因为您只能访问浏览器在解析 html 后为您创建的对象。

使用第二种方法,您必须通过 html 解析器运行整个 html 字符串。有些人可能会认为您可以简单地使用正则表达式来完成,但是,这是不可行的。我向您推荐这个奇妙的stackoverflow 问题

即使您找到了一个非常强大的 html 解析器来使用,您仍然会遇到这样一个事实,即在您的 JavaScript 甚至触及它之前,浏览器将尝试解析可能损坏的 html,并且到处都可能出现错误。

编辑:

如果您喜欢解析器的想法,John Resig 创建了这个您可能想要参考的示例。

于 2013-10-02T23:12:33.647 回答
1

不完美,但这是我检查打开/关闭标签之间不匹配的快速方法:

function find_unclosed_tags(str) {
    str = str.toLowerCase();
    var tags = ["a", "span", "div", "ul", "li", "h1", "h2", "h3", "h4", "h5", "h6", "p", "table", "tr", "td", "b", "i", "u"];
    var mismatches = [];
    tags.forEach(function(tag) { 
        var pattern_open = '<'+tag+'( |>)'; 
        var pattern_close = '</'+tag+'>'; 

        var diff_count = (str.match(new RegExp(pattern_open,'g')) || []).length - (str.match(new RegExp(pattern_close,'g')) || []).length;

        if(diff_count != 0) {
            mismatches.push("Open/close mismatch for tag " + tag + ".");
        }
    });

    return mismatches;
}
于 2020-11-21T08:17:11.250 回答