регулярное выражение (или другой код JavaScript), чтобы устранить ненужные пробелы в HTML - PullRequest
0 голосов
/ 27 марта 2011

Я хотел бы обработать некоторый HTML-код в javascript, устранить все лишние пробелы и преобразовать вкладки и переводы строк в один пробел. Вот сложная часть: некоторые пробелы имеют смысл, а некоторые нет, и программно сложно сказать, что есть что. Пример:

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

Здесь пробел между закрывающим тегом span и открывающим тегом «a» (и т. Д.) Имеет смысл - без него вокруг ссылки не будет пробелов.

Есть ли общий способ справиться с этим? Казалось бы, требуется, чтобы алгоритм имел некоторые знания о структуре html и различных характеристиках различных тегов.

(примечание: в случае, если вам интересно, почему я анализирую html в javascript .... это для экспериментальной гизмо-конструктора шаблонов на стороне клиента - длинная история, но, пожалуйста, примите, что у меня есть веская причина для этого :))

Ответы [ 2 ]

0 голосов
/ 28 марта 2011

Хорошо, я решил это сам, поэтому я поставлю свое решение здесь. Я решил поработать с DOM, а не с html как строкой, и тогда я смогу взять innerHTML в качестве последнего шага. Код немного громоздкий, но идея такова:

Пройдите по дереву DOM элемента, сохранив данные для каждого узла в массив (то есть, линейный, а не дерево). Для узлов элементов сохраните в массиве как "startelem", так и "endelem", эквивалентные начальным и конечным тегам. Также обратите внимание на вычисляемое свойство каждого элемента «display» (например, inline, block и т. Д.) И поместите его в оба элемента массива. (Для всех узлов я также сохраняю глубину в дереве, но не похоже, что мне нужно это использовать).

Для текстовых узлов обратите внимание на то, является ли это обычным текстовым узлом, всеми пробелами или пустой строкой.

Пройдите по массиву, и для текстовых узлов «пробел» посмотрите на предыдущий и следующий элемент в массиве. Если любой из них отображен: встроенный, оставьте узел как один пробел. Если нет, измените текстовый узел на пустую строку.

После этого выполнение 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;
    }
  };
0 голосов
/ 27 марта 2011

Вы можете заменить все >\s+< на ><. Но это не безопасно.

Представьте себе следующее: <span>this</span> <span>text</span> станет thistext при печати. Замена всех вхождений более чем одного пробела в одно поле должно быть безопасным:

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