2009-04-14 62 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> 

我一直在尋找四處尋找答案,一切,我」我們發現似乎試圖通過這種方式控制空白區域:

$foo = new DOMDocument(); 
$foo->preserveWhiteSpace = false; 
$foo->formatOutput = true; 

但這似乎沒有做任何事情。也許這隻適用於閱讀XML?請記住我正在嘗試寫入新文件。

有沒有什麼內置到DOMDocument這樣做?或者一個可以輕鬆完成這個功能的功能?

+1

我不知道問題是什麼。你顯示的代碼會給出你要求的輸出。證明:http://codepad.org/4UGyRspx和http://codepad.org/bLTOFQrp - 您是否在詢問縮進級別,例如使用的空間數量? – Gordon 2012-03-04 18:20:13

+0

有一個很好的簡單的功能(基於正則表達式)這裏:[格式化XML與PHP(http://recurser.com/articles/2007/04/05/format-xml-with-php/) – Tomalak 2009-04-14 06:08:43

+0

相關的只要壓痕關注:與轉換的preg_replace壓痕(沒有回調)(http://stackoverflow.com/questions/8616594/converting-indentation-with-preg-replace-no-callback) – hakre 2013-03-10 09:49:16

回答

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,並在該類內部創建了一個變量$ this-> xml,該變量包含DOMDocument的一個實例,並且它似乎不適用於該設置。 我也希望有真正的標籤,而不是空格。 – 2009-04-14 04:26:55

7

經過John的一些幫助和我自己的努力,似乎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
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時調用哪種方法?

我用這個:

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

(...)

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

它完美,但打印出來只有元素,所以你必須手動打印<?xml ... ?>部分..

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

得好好的,希望這有助於

1

在這個話題處理XML文本流大多數的答案。 這是使用dom功能執行縮進作業的另一種方法。 loadXML()dom方法將xml源中存在的縮進字符作爲文本節點導入。這個想法是從dom中刪除這些文本節點,然後重新創建格式正確的文本節點(有關更多詳細信息,請參閱下面的代碼中的註釋)。

的xmlIndent()函數被實現爲indentDomDocument類,它是從DOM文檔繼承的方法。 下面是如何使用它的一個完整的例子:

$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

喲偷看,

剛剛發現,很顯然,一個根XML元素可能不包含文本的孩子。這是不直觀的。 F。但顯然,這是因爲,例如,

將無法​​縮進。

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

所以你去,H。噸。 H。 et c。