2011-09-07 87 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();