如何删除XML字段前后的所有间距字符?
<data version="2.0">
<field>
1
</field>
<field something=" some attribute here... ">
2
</field>
</data>
请注意1和2之间的间距以及'some attribute here ...',我想用PHP删除它。
if(($xml = simplexml_load_file($file)) === false) die();
print_r($xml);
此外数据似乎不是字符串,我需要在每个变量之前追加(字符串)。为什么呢?
答案 0 :(得分:2)
你可能想要使用这样的东西:
$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>
之间的空格相反) ),所以我建议您使用的源应该对空格不那么混乱。
答案 1 :(得分:1)
由于simplexml_load_file()
将数据读入数组,您可以执行以下操作:
function TrimArray($input){
if (!is_array($input))
return trim($input);
return array_map('TrimArray', $input);
}
答案 2 :(得分:1)
要在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_r
或var_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);
即使转换为字符串通常也适用(例如使用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();