2011-03-26 9 views
0

javascriptでいくつかのhtmlコードを処理して余分な空白をすべて除去し、タブと改行を単一のスペースに変換したいと考えています。ここでは難しい部分があります:空白で意味のあるものもあれば、そうでないものもあります。例:上記のコードでregex(またはその他の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タグと開口部「」タグ(など)の間の空白は意味がある - それなしで、リンクの前後にスペースはありません。

これを処理する一般的な方法はありますか?アルゴリズムには、html構造と異なるタグの異なる特性に関する知識が必要であるように見えます。

(注:なぜ私はj​​avascriptでhtmlを解析しているのだろうと思っています....実験的なクライアントサイドのテンプレートビルダーgizmo - 長い話ですが、私には良い理由があることを受け入れてくださいこの:))

+6

理由:

ここでは、コードのですか?どうして?どうして?どうして? –

+1

だからこそ、真剣に、それは長い話ですが、出力を効率的に(最も重要なことに)フォーマットしていない状態に保ちながら、人々が最もフレンドリーでかわいらしいインデントされた方法でhtmlを編集できるようにしたいと思います。私が言ったように、良い理由があることを安心してください。 – rob

+0

可能な複製http://stackoverflow.com/questions/1550532/trimming-whitespace-from-html-content? –

答えて

0

[OK]を、よく私はので、私はここに私の解決策を置くそれを自分で解決しました。私は文字列としてhtmlではなくDOMを扱うことにしました。そして最後のステップとして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; 
    } 
    }; 
+0

に変換するのはなぜでしょうか? http://tidy.sourceforge.net/ – markmnl

+0

http://ja.wikipedia.org/wiki/HTML_Tidy、http://infohound.net/tidy/ – markmnl

+0

あなたはインデントとして必要なものを制御できます - あなたのケースでは1つのスペース – markmnl

0

すべて>\s+<><に置き換えることができます。しかし、これは安全ではありません。

以下を想像してください。<span>this</span> <span>text</span>は、印刷するとthistextになります。単一withespaceで複数の空白のすべての回出てくるの交換はいえ安全でなければならない:

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

ええ、後者は私がやったことです。私はまた、いくつかの特別なケーシングを考えました。たとえば、 rob

関連する問題