如何在HTML文档中包装所有已知文本?

问题描述 投票:1回答:2

我想在HTML文档中找到与RegEx匹配的所有TEXT或HREF,并用标记包装它们(例如将纯文本转换为链接)。

请考虑以下HTML:

<body>
  <!-- test1 <div>test2 <a href="test3">test4</a></div> -->
  test5
  <a href="test6">notest</a>
  <div>
    test8
    <p>
      test9 notest test10
      <a href="notest">test12</a>
      <input type="text" name="test13">test14</input>
    </p>
    test15
  </div>
</body>

那么这将是我要求的替代品:

<body>
  <!-- test1 <div>test2 <a href="test3">test4</a></div> -->
  <div class="wrapped">test5</div>
  <div class="wrapped"><a href="test6">notest</a></div>
  <div>
    <div class="wrapped">test8</div>
    <p>
      <div class="wrapped">test9</div> notest
      <div class="wrapped">test10</div>
      <div class="wrapped"><a href="notest">test12</a></div>
      <input type="text" name="test13">test14</input>
    </p>
    <div class="wrapped">test15</div>
  </div>
</body>

请注意,测试5, 6, 8, 9, 10, 12, 15被包裹了。

插入输入框或任何其他未显示的特殊HTML标记(例如<script> <doctype>等)是不可接受的。

我之前正在使用堆栈原则:

  1. 将身体推到堆叠上。
  2. e = stack.pop()
  3. 将类型元素的e的所有子元素推入堆栈,除了链接(<a>节点)和class="wrapped"的元素。
  4. 检查匹配的e.children或文本和包装的所有剩余href类型链接。
  5. 在所有类型文本的e.children中包装所有最里面的匹配。
  6. 如果stack不为空,则转到2。
  7. 完成

JavaScript只需要在Firefox 8上运行。

我想在没有树遍历的情况下完成包装,线性将是最佳的

javascript regex dom traversal
2个回答
1
投票

你为什么不想要任何树遍历?我认为你当前的算法和它一样好。

问题是DOM没有提供任何复杂的方法来获取所有文本节点。

我没有进行任何性能测试,但是这个速度可能大致相同:

  1. nodes := getElementsByTagName('*')
  2. excludes := document.querySelectorAll('a, a *, .wrapped, .wrapped *, script, style, input, textarea [, ...]')querySelectorAll表现相当不错)
  3. targets := nodes - excludes (不确定这里的表现)
  4. 迭代targets 迭代孩子 包装每个textNode
  5. 分别处理<a>元素

1
投票

你很幸运!我不久前写了这样的东西。

它可能需要一些修改才能使它与正则表达式一起使用,但这不应该太难。该代码已在IE7,8,9,Chrome和Firefox中进行了测试

/*global window document addEvent*/

function textContent(node) {
    if (typeof node.textContent !== "undefined") {
        return node.textContent;
    } else {
        return node.nodeValue; // IE
    }
}
function setTextContent(node, new_value) {
    if (typeof node.textContent !== "undefined") {
        node.textContent = new_value;
    } else {
        node.nodeValue = new_value; // IE
    }
}

function replace_stuff(context_element) {
    var i = 0, node, pos, before, after, div;
    if (1 === context_element.nodeType) {
        for (; i < context_element.childNodes.length; i += 1) {
            replace_em(context_element.childNodes[i]);
        }
    } else if (3 === context_element.nodeType) {
        node = context_element;
        pos = textContent(node).indexOf("YOURSTRING"); // replace with regex if you so desire
        while (-1 !== pos) {
            before = textContent(node).substring(0, pos);
            after = textContent(node).substring(pos + 10, textContent(node).length);  // 10 is the lenth of YOURSTRING
            context_element.parentNode.insertBefore(document.createTextNode(before), node);
            div = document.createElement("div");
            div.appendChild(document.createTextNode("YOURSTRING")); // reinsert original content
            context_element.parentNode.insertBefore(div, node);
            setTextContent(node, after);
            pos = textContent(node).indexOf("YOURSTRING"); // find next occurance
        }
    }
}

addEvent(window, "load", function () {  // you may need to change this line
    replace_stuff(document.getElementById("main"));
});

基本上它检查节点的textContent是否为YOURSTRING,将文本分成两个节点:YOURSTRING之前的文本和之后的文本。然后它将YOURSTRING包装在div中并将其插入到其他两个节点之间。

© www.soinside.com 2019 - 2024. All rights reserved.