2011-09-07 71 views
5

如何刪除XML字段前後的所有間距字符?刪除XML元素的開始和結束空格

<data version="2.0"> 

    <field> 

    1 

    </field>   

    <field something=" some attribute here... "> 

    2 

    </field> 

</data> 

注意前間距1和2以及「這裏的一些屬性...」,我想刪除與PHP。

if(($xml = simplexml_load_file($file)) === false) die(); 

print_r($xml); 

此外,數據似乎不是字符串,我需要在每個變量前追加(字符串)。爲什麼?

+1

請參閱我的答案在http://stackoverflow.com/questions/8200582/remove-newline-from-xml-element-值/ 8200664#8200664可能的解決方案 – Gordon

回答

1

由於simplexml_load_file()讀取數據到一個數組,你可以做這樣的事情:

function TrimArray($input){ 

    if (!is_array($input)) 
     return trim($input); 

    return array_map('TrimArray', $input); 
} 
+0

不,它不會將數據讀入數組,但會創建一個** SimpleXMLElement **。而這個對象可以是字符串的情況(當你調用'trim'時會發生什麼)。 – hakre

1

您可能希望使用這樣的事:

$str = file_get_contents($file); 
$str = preg_replace('~\s*(<([^>]*)>[^<]*</\2>|<[^>]*>)\s*~','$1',$str); 
$xml = simplexml_load_string($xml,'SimpleXMLElement', LIBXML_NOCDATA); 

我沒有試過,但你可以在http://www.lonhosford.com/lonblog/2011/01/07/php-simplexml-load-xml-file-preserve-cdata-remove-whitespace-between-nodes-and-return-json/找到更多。

注意,打開和關閉括號(<x> _space_ </x>)和屬性(<x attr=" _space_ ">)之間的空間實際上是XML文檔的數據部分(與<x> _space_ <y>之間的空間對比度),所以我會建議源使用應該少一些凌亂的空間。

0

要做到這一點在PHP中,你首先必須將文檔轉換爲的DOMDocument,這樣就可以解決你想通過DOMXPath正常化內適當的空白節點。 (xpath in)SimpleXMLElement太有限,無法精確地訪問文本節點,因爲它需要執行此操作。

一個XPath查詢訪問所有文本節點是葉元素內的所有屬性是:

//*[not(*)]/text() | //@* 

鑑於$xml的SimpleXMLElement,你可以做空白正常化像下面的例子:

$doc = dom_import_simplexml($xml)->ownerDocument; 
$xpath = new DOMXPath($doc); 
foreach ($xpath->query('//*[not(*)]/text()|//@*') as $node) { 
    /** @var $node DOMText|DOMAttr */ 
    $node->nodeValue = trim(preg_replace('~\s+~u', ' ', $node->nodeValue), ' '); 
} 

也許你可以舒展這所有文本節點(as suggested in related Q&A),但是這可能需要根據情況的文件正常化。由於Xpath中的text()在文本節點和Cdata節之間沒有區別,因此在加載文檔時可能需要跳過這些類型的節點(DOMCdataSection)或將它們展開到文本節點中(爲此使用the LIBXML_NOCDATA option)以實現更有用結果。


另外的數據不顯示爲字符串,我需要每個變量之前要追加(字符串)。爲什麼?

因爲它是類型的SimpleXMLElement的對象,如果你想這樣的對象(元素)的字符串值,則需要將其轉換爲字符串。見還有以下參考問題:


最後但並非最不重要的:當您使用它在的SimpleXMLElement不信任print_rvar_dump:它沒有顯示真相。例如。你可以覆蓋__toString()這也可以解決您的問題:

class TrimXMLElement extends SimpleXMLElement 
{ 
    public function __toString() 
    { 
     return trim(preg_replace('~\s+~u', ' ', parent::__toString()), ' '); 
    } 
} 

$xml = simplexml_load_string($buffer, 'TrimXMLElement'); 

print_r($xml); 

即使轉換爲String通常會應用(例如用echo)的print_r輸出仍然不會反映這些變化。所以最好不要依賴它,它永遠不能顯示整個圖像。


完整的示例代碼,這個答案(Online Demo):

<?php 
/** 
* Remove starting and ending spaces from XML elements 
* 
* @link https://stackoverflow.com/a/31793566/367456 
*/ 

$buffer = <<<XML 
<data version="2.0"> 

    <field> 

    1 

    </field> 

    <field something=" some attribute here... "> 

    2 <![CDATA[ 34 ]]> 

    </field> 

</data> 
XML; 

class TrimXMLElement extends SimpleXMLElement implements JsonSerializable 
{ 
    public function __toString() 
    { 
     return trim(preg_replace('~\s+~u', ' ', parent::__toString()), ' '); 
    } 

    function jsonSerialize() 
    { 
     $array = (array) $this; 

     array_walk_recursive($array, function(&$value) { 
      if (is_string($value)) { 
       $value = trim(preg_replace('~\s+~u', ' ', $value), ' '); 
      } 
     }); 

     return $array; 
    } 
} 

$xml = simplexml_load_string($buffer, 'TrimXMLElement', LIBXML_NOCDATA); 

print_r($xml); 
echo json_encode($xml); 

$xml = simplexml_load_string($buffer, null, LIBXML_NOCDATA); 

$doc = dom_import_simplexml($xml)->ownerDocument; 
$doc->normalizeDocument(); 
$doc->normalize(); 

$xpath = new DOMXPath($doc); 
foreach ($xpath->query('//*[not(*)]/text()|//@*') as $node) { 
    /** @var $node DOMText|DOMAttr|DOMCdataSection */ 
    if ($node instanceof DOMCdataSection) { 
     continue; 
    } 
    $node->nodeValue = trim(preg_replace('~\s+~u', ' ', $node->nodeValue), ' '); 
} 

echo $xml->asXML();