用于查找未关闭的HTML标记的JavaScript库/函数

时间:2013-10-02 23:00:05

标签: javascript html tags

我目前正在寻找一种解决方案,可以从任意原始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,以便将部分元素包装到应用适当格式的span-type元素中。最初这将以以下形式解析:

<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解析器会这样做,对吧?他们中的很多人都知道如何关闭标签,所以在某些时候他们很清楚地计算了这一点。

2 个答案:

答案 0 :(得分:3)

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

  1. 从某种意义上说,每个元素都是一个对象,其中包含浏览器在页面加载时创建的属性和方法。
  2. 从某种意义上说它是一串文字。
  3. 使用第一种与html接口的方法,无法检测未关闭的标签,因为在解析html后,您只能访问浏览器为您创建的对象。

    使用第二种方法,您必须通过html解析器运行整个html字符串。有些人可能会认为你可以使用regexp来完成它,但是,这是不可行的。我推荐你这个很棒的stackoverflow question

    即使你找到了一个非常强大的html解析器,你仍然会遇到这样的问题,即在你的JavaScript触及它之前,浏览器会试图解析可能已损坏的html,并且可能会到处都是错误。

    编辑:

    如果您喜欢解析器的想法,John Resig创建了您可能想要引用的this example one

答案 1 :(得分:0)

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

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;
}