正则表达式(或其他javascript代码),以消除html中不需要的空格

时间:2011-03-26 23:43:14

标签: javascript html regex html-parsing

我想在javascript中处理一些html代码,以消除所有额外的空白,并将标签和换行符转换为单个空格。这是一个棘手的部分:一些空白是有意义的,有些则不是,并且很难以编程方式告诉哪个是哪个。例如:

<table>
 <tr>
  <td>hi</td>
 </tr>
</table>

在上面的代码中,可以消除所有空格和换行符,因为在tr和td标记之间有一个空格实际上没有意义(即使浏览器可能在那里创建一个文本节点,它也不会改变外观这页纸)。另一方面:

<span>following is a link</span>
 <a href="#">here it is</a>
<span>and this is text after the link</span>

这里,结束范围标记和开头“a”标记(等)之间的空白是有意义的 - 没有它,链接周围就没有空格。

有没有一般的方法来处理这个?似乎要求该算法具有一些html结构知识和不同标签的不同特征。

(注意:如果你想知道为什么我在javascript中解析html ....这是一个实验性客户端模板构建器Gizmo - 长篇故事,但请接受我有充分的理由这样做:))

2 个答案:

答案 0 :(得分:0)

您可以将所有>\s+<替换为><。但这不安全。

想象一下:<span>this</span> <span>text</span>在打印时会变成thistext。用一个透明空间替换多个空格的所有出现应该是安全的:

html = html.replace(/>\s+</g,"> <"); 

答案 1 :(得分:0)

好的,我自己解决了,所以我会把解决方案放在这里。我决定使用DOM而不是html作为字符串,然后我可以抓住innerHTML作为最后一步。代码有点笨重,但想法是:

遍历元素的DOM树,将每个节点的数据保存到数组中(即线性,而不是树)。对于元素节点,在数组中存储“startelem”和“endelem”,相当于开始标记和结束标记。还要记下每个元素的计算“显示”属性(例如内联,块等),并将其放在数组中的两个项目中。 (对于所有节点,我也将深度存储到树中,但似乎我不需要使用它。)

对于文本节点,请注意它是常规文本节点,所有空格还是空字符串。

遍历数组,对于“空白”文本节点,查看数组中的上一个和下一个项目。如果显示其中任何一个:内联,则将节点保留为单个空格。如果不是,请将文本节点更改为空字符串。

之后,对元素执行innerHTML将不会有额外的空格,并且,尽管我可以说,元素的浏览器中的外观将保持不变。

以下是代码:

  var stripUnneededTextNodes= function (elem) {
   var array = [];
   addNodeAndChildrenToArray(elem, 1, array);
   for (var i=1; i<array.length-1; i++) {
      if (array[i].type == "whitespace") {
        if (array[i-1].display == "inline" && array[i+1].display == "inline") {
          array[i].node.nodeValue = ' ';
          }
        else {
          array[i].node.nodeValue = '';
          array[i].killed = true;
          }          
        delete array[i].node;
        }
      else if (array[i].type == "text") {
        var val = array[i].node.nodeValue;
        if (val.charAt(0) == ' ' && array[i-1].display != "inline") {
          array[i].node.nodeValue = val = val.substring(1);
          }
        if (val.charAt(val.length-1) == ' ' && array[i+1].display != "inline") {
          array[i].node.nodeValue = val.substring(0, val.length-1);
          }
        delete array[i].node;
        }
      }
   };

 var addNodeAndChildrenToArray = function (node, depth, array) {
  switch (node.nodeType) {
    case 1: { // ELEMENT_NODE
      var display = document.defaultView.getComputedStyle (node, null).display;
      array.push ({type: "startelem", tag: node.tagName, display: display, depth: depth});

      if (node.childNodes && node.childNodes.length != 0) {
         for (var i=0; i<node.childNodes.length; i++)
            addNodeAndChildrenToArray(node.childNodes.item(i), depth+1, array);
        }
      array.push ({type: "endelem", tag: node.tagName, display: display, depth: depth});
      }
      break;

    case 3: { //TEXT_NODE
      var newVal = node.nodeValue.replace(/\s+/g, ' ');
      node.nodeValue = newVal;
      if (newVal == ' ')
        array.push ({type: "whitespace", node: node, depth: depth});
      else if (newVal == '')
        array.push ({type: "emptytext", depth: depth});
      else
        array.push ({type: "text", node: node, display: "inline", depth: depth});
      }
      break;
    }
  };