要做到这一点在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);
即使转换为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();
请参阅我的答案在http://stackoverflow.com/questions/8200582/remove-newline-from-xml-element-值/ 8200664#8200664可能的解决方案 – Gordon