如何找到起始标记或结束标记的(字符串)长度?

时间:2013-05-03 15:05:57

标签: javascript jquery html dom

我正在尝试编写一个jQuery或纯Javascript函数(更喜欢更易读的解决方案),它可以计算HTML文档中起始标记或结束标记的长度。

例如,

<p>Hello.</p>
对于起始和结束标记长度,

将返回3和4。添加属性

<span class="red">Warning!</span>
对于起始和结束标记长度,

将返回18和7。最后,

<img src="foobar.png"/>
对于起始和结束标记长度,

将返回23和0(或-1)。

我正在寻找一个规范的,保证按工作规范的解决方案,因此我尝试使用DOM方法而不是手动文本操作。例如,我希望该解决方案即使对于像

这样的奇怪案例也能正常工作
<p>spaces infiltrating the ending tag</ p >

<img alt="unended singleton tags" src="foobar.png">

等。也就是说,我希望只要我们使用正确的DOM方法,我们应该能够找到<>之间的字符数,无论多么奇怪的事情,甚至

<div data-tag="<div>">HTML-like strings within attributes</div>

我查看了jQuery API(特别是Manipulation部分,包括DOM Insertion和General Attributes小节),但我没有看到任何有用的东西。

鉴于元素node,我目前最好的想法是

lengthOfEndTag = node.tagName.length + 3;

lengthOfStartTag = node.outerHTML.length
                 - node.innerHTML.length
                 - lengthOfEndTag;

但当然我不想对结束标记做出这样的假设。

(最后,我熟悉正则表达式 - 但是如果可能的话,尽量避免使用它们。)


修改

@Pointy和@squint帮助我理解,例如,因为在创建DOM时HTML被丢弃,所以不可能看到</ p >。没关系。调整后的目标是查找将在outerHTML 中呈现的开始和结束标记的长度。

2 个答案:

答案 0 :(得分:1)

另一种方法是在节点的克隆副本上使用 XMLSerializer的 serializeToString id 设置)以避免必须解析 innerHTML ,然后拆分为"><"

var tags = (function () {
    var x = new XMLSerializer(); // scope this so it doesn't need to be remade
    return function tags(elm) {
        var s, a, id, n, o = {open: null, close: null}; // spell stuff with var
        if (elm.nodeType !== 1) throw new TypeError('Expected HTMLElement');
        n = elm.cloneNode(); // clone to get rid of innerHTML
        id = elm.getAttribute('id'); // re-apply id for clone
        if (id !== null) n.setAttribute('id', id); // if it was set
        s = x.serializeToString(n); // serialise
        a = s.split('><');
        if (a.length > 1) { // has close tag
            o.close = '<' + a.pop();
            o.open = a.join('><') + '>'; // join "just in case"
        }
        else o.open = a[0]; // no close tag
        return o;
    }
}()); // self invoke to init

运行此功能后,您可以访问打开.length关闭属性

tags(document.body); // {open: "<body class="question-page">", close: "</body>"}

如果属性的值中包含><怎么办? XMLSerializer 将此转义为&gt;&lt;,因此不会更改.split
怎么没有关闭标签? close 将为null

答案 1 :(得分:0)

This answer帮助我了解@Pointy和@squint试图说的内容。

以下解决方案适合我:

$.fn.lengthOfStartTag = function () {
    var node = this[0];
    if (!node || node.nodeType != 1) {
        $.error("Called $.fn.lengthOfStartTag on non-element node.");
    }
    if (!$(node).is(":empty")) {
        return node.outerHTML.indexOf(node.innerHTML);
    }
    return node.outerHTML.length;
}

$.fn.lengthOfEndTag = function () {
    var node = this[0];
    if (!node || node.nodeType != 1) {
        $.error("Called $.fn.lengthOfEndTag on non-element node.");
    }
    if (!$(node).is(":empty")) {
        var indexOfInnerHTML = node.outerHTML.indexOf(node.innerHTML);
        return node.outerHTML.length - (indexOfInnerHTML + node.innerHTML.length);
    }
    return -1;
}

Sample jsFiddle here.