2009-04-14 38 views
21

私はDOMDocumentを使用して新しいXMLファイルを生成しています。ファイルの出力がうまくインデントされ、人間の読者に従うのが簡単です。PHPでのDOMDocumentのインデント

例えば、DOMDocument出力するデータ:

<?xml version="1.0"?> 
<this attr="that"><foo>lkjalksjdlakjdlkasd</foo><foo>lkjlkasjlkajklajslk</foo></this> 

私はXMLファイルになりたい:

<?xml version="1.0"?> 
<this attr="that"> 
    <foo>lkjalksjdlakjdlkasd</foo> 
    <foo>lkjlkasjlkajklajslk</foo> 
</this> 

私は答えを探して周りに検索する、と私は」すべてをしてきました見つかったのは、このように空白を制御しようとするようです。しかしこれは何もしないようです。おそらくこれはXMLを読むときにのみ機能しますか?私は新しい文書を書くことを心掛けています。

DOMDocumentには何も組み込まれていますか?これを簡単に達成できる機能ですか?

+1

私は質問が何であるか分かりません。あなたが表示するコードはあなたが求めている出力を与えます。証明:http://codepad.org/4UGyRspxとhttp://codepad.org/bLTOFQrp - あなたはインデントレベルについて質問していますか?使用されるスペースの数? – Gordon

+0

正規表現に基づく素直な関数があります:[PHPを使ったXML形式](http://recurser.com/articles/2007/04/05/format-xml-with-php/) – Tomalak

+0

関連する長いインデントが心配です:[preg_replace(コールバックなし)で字下げを変換](0120-919-066)。 – hakre

答えて

3

私はformatOutputpreserveWhiteSpaceを異なる方法で設定するコードを実行しようとしましたが、出力に影響を与えるメンバーはformatOutputです。あなたは下のスクリプトを実行し、それが動作するかどうか見ることができますか?

<?php 
    echo "<pre>"; 
    $foo = new DOMDocument(); 
    //$foo->preserveWhiteSpace = false; 
    $foo->formatOutput = true; 
    $root = $foo->createElement("root"); 
    $root->setAttribute("attr", "that"); 
    $bar = $foo->createElement("bar", "some text in bar"); 
    $baz = $foo->createElement("baz", "some text in baz"); 
    $foo->appendChild($root); 
    $root->appendChild($bar); 
    $root->appendChild($baz); 
    echo htmlspecialchars($foo->saveXML()); 
    echo "</pre>"; 
?> 
+0

コードは正常に動作しますが、私はそれを設定した方法で私のために働かない。私はクラスxmlを持っており、そのクラスの中にDOMDocumentのインスタンスを保持する変数$ this-> xmlを作成し、そのセットアップでは動作しないようです。 スペースだけでなく、実際のタブを使用することもできます。 –

+0

これは特殊なケースのようです。私はメンバーとして "xml"を使って簡単なクラスを作成しましたが、それはまだ機能しました。あまりにも多くの要因があり、正確なコード(またはあなたのためにまだ失敗した単純化されたバージョン)がなければ、それは再現することが不可能になるだろう。 –

+0

ご協力ありがとうございます。私は、うまくいけば私の問題を解決する基本的なインデント関数を書いています(見てみたい場合は、答えとして投稿しようとしています)。 –

7

私はこれを自分自身でやっていますが、DOMDocumentの本来の書式のサポートが私のニーズを満たしていないようです。そこで、私は自分自身のインデント機能を書くことに決めました。

これは私がすぐに一緒に投げた非常に粗末な機能なので、誰かが最適化のヒントやそれについて一般的なことがあれば、それを聞いてうれしいです!

function indent($text) 
{ 
    // Create new lines where necessary 
    $find = array('>', '</', "\n\n"); 
    $replace = array(">\n", "\n</", "\n"); 
    $text = str_replace($find, $replace, $text); 
    $text = trim($text); // for the \n that was added after the final tag 

    $text_array = explode("\n", $text); 
    $open_tags = 0; 
    foreach ($text_array AS $key => $line) 
    { 
     if (($key == 0) || ($key == 1)) // The first line shouldn't affect the indentation 
      $tabs = ''; 
     else 
     { 
      for ($i = 1; $i <= $open_tags; $i++) 
       $tabs .= "\t"; 
     } 

     if ($key != 0) 
     { 
      if ((strpos($line, '</') === false) && (strpos($line, '>') !== false)) 
       $open_tags++; 
      else if ($open_tags > 0) 
       $open_tags--; 
     } 

     $new_array[] = $tabs . $line; 

     unset($tabs); 
    } 
    $indented_text = implode("\n", $new_array); 

    return $indented_text; 
} 
+2

速い発言:タブを作成するためのstr_repeat()があります。残りの機能は私にとっては大丈夫です。私が見つけたものと小さなパフォーマンスの比較を設定することができます。別の考え方として、strtok()を使用して入力を反復的にトークン化することができます(置き換える/爆発するのではなく)。 – Tomalak

+0

ありがとう!私は実際にあなたが自分のものよりも優れた機能を好んでいます。 そして、私はstr_repeat()またはstrtok()について知りませんでした。 –

-2
header("Content-Type: text/xml"); 

$str = ""; 
$str .= "<customer>"; 
$str .= "<offer>"; 
$str .= "<opened></opened>"; 
$str .= "<redeemed></redeemed>"; 
$str .= "</offer>"; 
echo $str .= "</customer>"; 

最初次いで.xml以外の任意の拡張子を使用している場合は正しい値にヘッダContent-Typeヘッダを設定します。

1

xmlを印刷するときは、どのメソッドを呼び出しますか?それは完璧に動作しますが、唯一の要素を出力しますので、手動で<?xml ... ?>一部を印刷する必要があります

$doc = new DOMDocument('1.0', 'utf-8'); 
$root = $doc->createElement('root'); 
$doc->appendChild($root); 

(...)

$doc->formatOutput = true; 
$doc->saveXML($root); 

..:

私はこれを使用します

24

DOMDOCUMENTは、トリックを行います、私は個人的に過ごしグーグルとあれば、これを理解しようとしていると私はあなたがそのためには

$xmlDoc = new DOMDocument(); 
$xmlDoc->loadXML ($xml); 
$xmlDoc->preserveWhiteSpace = false; 
$xmlDoc->formatOutput = true; 
$xmlDoc->save($xml_file); 

を使用している場合、それはうまく動作しないことに注意が、時間のカップルあなたは同じコードを使用しますが、この順に:魅力のよう

$xmlDoc = new DOMDocument(); 
$xmlDoc->preserveWhiteSpace = false; 
$xmlDoc->formatOutput = true; 
$xmlDoc->loadXML ($xml); 
$xmlDoc->save($archivoxml); 

作品、これはXMLテキストの流れと、このトピックの契約で

+2

おい!あなたはロック!これを見つけてくれてありがとう! –

+3

Dammit ...これはXMLで動作するようですが、HTMLはまだ醜いです。 =/ –

+0

はい、HTMLで動作しないようです – 3zzy

1

ほとんどの回答に役立ちます願っています。 インデントジョブを実行するためにdom機能を使用するもう1つの方法があります。 loadXML()domメソッドは、xmlソースにあるインデント文字をテキストノードとしてインポートします。そのようなテキストノードをdomから削除し、正しくフォーマットされたテキストノードを再作成することです(詳細については、以下のコードのコメントを参照してください)。

xmlIndent()関数は、domDocumentから継承されたindentDomDocumentクラスのメソッドとして実装されています。ただ明らかに、ルートXML要素は、テキストの子を含んでいない可能性があることが分かった

$dom = new indentDomDocument("1.0"); 
$xml = file_get_contents("books.xml"); 

$dom->loadXML($xml); 
$dom->xmlIndent(); 
echo $dom->saveXML(); 

class indentDomDocument extends domDocument { 
    public function xmlIndent() { 
     // Retrieve all text nodes using XPath 
     $x = new DOMXPath($this); 
     $nodeList = $x->query("//text()"); 
     foreach($nodeList as $node) { 
      // 1. "Trim" each text node by removing its leading and trailing spaces and newlines. 
      $node->nodeValue = preg_replace("/^[\s\r\n]+/", "", $node->nodeValue); 
      $node->nodeValue = preg_replace("/[\s\r\n]+$/", "", $node->nodeValue); 
      // 2. Resulting text node may have become "empty" (zero length nodeValue) after trim. If so, remove it from the dom. 
      if(strlen($node->nodeValue) == 0) $node->parentNode->removeChild($node); 
     } 
     // 3. Starting from root (documentElement), recursively indent each node. 
     $this->xmlIndentRecursive($this->documentElement, 0); 
    } // end function xmlIndent 

    private function xmlIndentRecursive($currentNode, $depth) { 
     $indentCurrent = true; 
     if(($currentNode->nodeType == XML_TEXT_NODE) && ($currentNode->parentNode->childNodes->length == 1)) { 
      // A text node being the unique child of its parent will not be indented. 
      // In this special case, we must tell the parent node not to indent its closing tag. 
      $indentCurrent = false; 
     } 
     if($indentCurrent && $depth > 0) { 
      // Indenting a node consists of inserting before it a new text node 
      // containing a newline followed by a number of tabs corresponding 
      // to the node depth. 
      $textNode = $this->createTextNode("\n" . str_repeat("\t", $depth)); 
      $currentNode->parentNode->insertBefore($textNode, $currentNode); 
     } 
     if($currentNode->childNodes) { 
      $indentClosingTag = false; 
      foreach($currentNode->childNodes as $childNode) $indentClosingTag = $this->xmlIndentRecursive($childNode, $depth+1); 
      if($indentClosingTag) { 
       // If children have been indented, then the closing tag 
       // of the current node must also be indented. 
       $textNode = $this->createTextNode("\n" . str_repeat("\t", $depth)); 
       $currentNode->appendChild($textNode); 
      } 
     } 
     return $indentCurrent; 
    } // end function xmlIndentRecursive 

} // end class indentDomDocument 
-1

ヨ覗いて、

: 以下は、それを使用する方法の完全な例です。これは直感的ではありません。 f。しかし、明らかに、これは、例えば、

がインデントされないという理由です。だから、あなたは、時間を行く

https://bugs.php.net/bug.php?id=54972

。 t。 h。 et c。