【问题标题】:regex (or other javascript code) to eliminate unneeded whitespace in html正则表达式(或其他 javascript 代码)以消除 html 中不需要的空格
【发布时间】:2011-07-23 16:52:36
【问题描述】:

我想在 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 -- 说来话长,但请接受我这样做有充分的理由:) )

【问题讨论】:

  • 为什么?为什么?为什么?为什么?
  • 因为因为因为。说真的,这是一个很长的故事,但我希望允许人们以最用户友好、漂亮、缩进的方式编辑 html,同时保持输出高效并且(最重要的是)不会搞砸格式。正如我所说,请放心,这是有充分理由的——只要对我有好处。
  • 我看到了 html 上的正则表达式的问题。由于这是在浏览器环境中发生的,因此我也可以使用 dom。 (也就是说,遍历元素的 dom 树,查找仅包含空格的文本节点,检查它们周围元素的计算样式是否内联或你有什么,如果合适,将文本节点更改为空字符串,然后获取 innerHTML)所以我对这种解决方案持开放态度。

标签: javascript html regex html-parsing


【解决方案1】:

您可以将所有&gt;\s+&lt; 替换为&gt;&lt;。但这并不安全。

想象一下:&lt;span&gt;this&lt;/span&gt; &lt;span&gt;text&lt;/span&gt; 在打印时会变成thistext。不过,用一个空格替换所有出现的多个空格应该是安全的:

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

【讨论】:

  • 是的,后者是我所做的。我还考虑了一些特殊的套管,例如将
【解决方案2】:

好的,我自己解决了,所以我会把我的解决方案放在这里。我决定使用 DOM 而不是 html 作为字符串,然后我可以获取 innerHTML 作为最后一步。代码略显笨重,但思路是:

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

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

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

在此之后,对元素执行 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;
    }
  };

【讨论】:

  • 你可以控制你想要的缩进 - 在你的情况下一个空格
  • 因为我在 javascript 中需要它,而上面的内容正是我所需要的。我也怀疑 html tidy 是否知道如何正确地做,因为如果不处理所有 css 等,它就无法知道一个元素是否是内联的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-11-01
  • 2016-07-23
  • 2014-04-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多