2011-10-20 3 views
2

PHP에서 DOMDocument를 사용하여 HTML 문서에 항목을 추가/구문 분석하려고합니다. 읽었을 때 formOutput을 true로 설정하고 preserveWhiteSpace를 false로 설정하면 탭과 줄 바꿈을 순서대로 유지해야하지만 새로 생성되거나 추가 된 노드는 그렇지 않은 것처럼 보입니다.PHP의 DomDocument를 사용할 때 줄 바꿈 유지 appendChild

다음
<table> 
    <tr> 
     <td></td> 
    </tr> 
</table> 

이야 내가 원하는 : 같은

여기
$dom = new \DOMDocument; 
$dom->formatOutput = true; 
$dom->preserveWhiteSpace = false; 
$dom->loadHTMLFile($htmlsource); 
$tables = $dom->getElementsByTagName('table'); 
foreach($tables as $table) 
{ 
    $table->setAttribute('class', 'tborder'); 
    $div = $dom->createElement('div'); 
    $div->setAttribute('class', 'm2x'); 
    $table->parentNode->insertBefore($div, $table); 
    $div->appendChild($table); 
} 
$dom->saveHTMLFile($html) 

는 HTML 보이는 내용은 다음과 같습니다

여기
<div class="m2x"> 
    <table class="tborder"> 
     <tr> 
      <td></td> 
     </tr> 
    </table> 
</div> 

내가 무엇을 얻을 : 여기

코드의

<div class="m2x"><table class="tborder"><tr> 
<td></td> 
     </tr></table></div> 

내가 잘못하고있는 것이 있습니까? 나는 운이 좋았던 것의 많은 다른 방법으로 이것을 인터넷 검색하는 것을 시도했다.

답변

2

불행히도 원하는대로 출력을 들여 쓰기하는 함수를 작성해야 할 수도 있습니다. 내가 도움이 될만한 약간의 기능을 만들었습니다.

function indentContent($content, $tab="\t") 
{    

     // add marker linefeeds to aid the pretty-tokeniser (adds a linefeed between all tag-end boundaries) 
     $content = preg_replace('/(>)(<)(\/*)/', "$1\n$2$3", $content); 

     // now indent the tags 
     $token = strtok($content, "\n"); 
     $result = ''; // holds formatted version as it is built 
     $pad = 0; // initial indent 
     $matches = array(); // returns from preg_matches() 

     // scan each line and adjust indent based on opening/closing tags 
     while ($token !== false) 
     { 
       $token = trim($token); 
       // test for the various tag states 

       // 1. open and closing tags on same line - no change 
       if (preg_match('/.+<\/\w[^>]*>$/', $token, $matches)) $indent=0; 
       // 2. closing tag - outdent now 
       elseif (preg_match('/^<\/\w/', $token, $matches)) 
       { 
         $pad--; 
         if($indent>0) $indent=0; 
       } 
       // 3. opening tag - don't pad this one, only subsequent tags 
       elseif (preg_match('/^<\w[^>]*[^\/]>.*$/', $token, $matches)) $indent=1; 
       // 4. no indentation needed 
       else $indent = 0; 

       // pad the line with the required number of leading spaces 
       $line = str_pad($token, strlen($token)+$pad, $tab, STR_PAD_LEFT); 
       $result .= $line."\n"; // add to the cumulative result, with linefeed 
       $token = strtok("\n"); // get the next token 
       $pad += $indent; // update the pad size for subsequent lines  
     }  

     return $result; 
} 

indentContent($dom->saveHTML())는 반환합니다

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd"> 
<html> 
    <body> 
     <div class="m2x"> 
      <table class="tborder"> 
       <tr> 
        <td> 
        </td> 
       </tr> 
      </table> 
     </div> 
    </body> 
</html> 

내가 this one로 시작하는이 기능을 만들었습니다.

+0

위대한 기능! 그러나 불행히도 void 요소를 사용할 때 너무 많은 공간을 들여 쓰기합니다. – Stan

1

ghbarratt가 작성한 위대한 기능을 수정하여 들여 쓰지 않았으므로 void elements.

function indentContent($content, $tab="\t") 
{ 
    // add marker linefeeds to aid the pretty-tokeniser (adds a linefeed between all tag-end boundaries) 
    $content = preg_replace('/(>)(<)(\/*)/', "$1\n$2$3", $content); 

    // now indent the tags 
    $token = strtok($content, "\n"); 
    $result = ''; // holds formatted version as it is built 
    $pad = 0; // initial indent 
    $matches = array(); // returns from preg_matches() 

    // scan each line and adjust indent based on opening/closing tags 
    while ($token !== false) 
    { 
     $token = trim($token); 
     // test for the various tag states 

     // 1. open and closing tags on same line - no change 
     if (preg_match('/.+<\/\w[^>]*>$/', $token, $matches)) $indent=0; 
     // 2. closing tag - outdent now 
     elseif (preg_match('/^<\/\w/', $token, $matches)) 
     { 
      $pad--; 
      if($indent>0) $indent=0; 
     } 
     // 3. opening tag - don't pad this one, only subsequent tags (only if it isn't a void tag) 
     elseif (preg_match('/^<\w[^>]*[^\/]>.*$/', $token, $matches)) 
     { 
      $voidTag = false; 
      foreach ($matches as $m) 
      { 
       // Void elements according to http://www.htmlandcsswebdesign.com/articles/voidel.php 
       if (preg_match('/^<(area|base|br|col|command|embed|hr|img|input|keygen|link|meta|param|source|track|wbr)/im', $m)) 
       { 
        $voidTag = true; 
        break; 
       } 
      } 

      if (!$voidTag) $indent=1; 
     } 
     // 4. no indentation needed 
     else $indent = 0; 

     // pad the line with the required number of leading spaces 
     $line = str_pad($token, strlen($token)+$pad, $tab, STR_PAD_LEFT); 
     $result .= $line."\n"; // add to the cumulative result, with linefeed 
     $token = strtok("\n"); // get the next token 
     $pad += $indent; // update the pad size for subsequent lines  
    }  

    return $result; 
} 

모든 크레딧은 ghbarratt에 있습니다.

+0

+1 더 나은 방법. 그리고 나는 대부분 http://recursive-design.com/blog/2007/04/05/format-xml-with-php/에서 그것을 훔친 이후로 나는 그것에 대한 많은 크레딧을받을 자격이 거의 없다. – ghbarratt