我很难找到这个文档,所以在这里发布它,以防万一它能帮助到其他人
如果您想使用多个libxml选项,请用管道分隔它们,如下所示
<?php
$xml = simplexml_load_string($string, 'SimpleXMLElement', LIBXML_NOCDATA | LIBXML_NOBLANKS);
?>
(PHP 5, PHP 7, PHP 8)
simplexml_load_string — 将XML字符串解释为对象
$data
,$class_name
= SimpleXMLElement::class,$options
= 0,$namespace_or_prefix
= "",$is_prefix
= false
接受一个格式良好的XML字符串并将其作为对象返回。
data
格式良好的XML字符串
class_name
您可以使用此可选参数,以便simplexml_load_string() 将返回指定类的对象。该类应扩展SimpleXMLElement 类。
options
namespace_or_prefix
命名空间前缀或URI。
is_prefix
返回一个object 类SimpleXMLElement,其属性包含XML文档中保存的数据,或者在失败时返回false
。
为在XML数据中找到的每个错误生成E_WARNING
错误消息。
使用libxml_use_internal_errors() 来抑制所有XML错误,并使用libxml_get_errors() 来迭代这些错误。
示例 #1 解读XML字符串
<?php
$string = <<<XML
<?xml version='1.0'?>
<document>
<title>Forty What?</title>
<from>Joe</from>
<to>Jane</to>
<body>
I know that's the answer -- but what's the question?
</body>
</document>
XML;
$xml = simplexml_load_string($string);
print_r($xml);
?>
以上示例将输出
SimpleXMLElement Object ( [title] => Forty What? [from] => Joe [to] => Jane [body] => I know that's the answer -- but what's the question? )
此时,您可以使用$xml->body
等。
我很难找到这个文档,所以在这里发布它,以防万一它能帮助到其他人
如果您想使用多个libxml选项,请用管道分隔它们,如下所示
<?php
$xml = simplexml_load_string($string, 'SimpleXMLElement', LIBXML_NOCDATA | LIBXML_NOBLANKS);
?>
一种更简单的将结果转换为数组的方法(需要json模块)。
<?php
function object2array($object) { return @json_decode(@json_encode($object),1); }
?>
示例
<?php
$xml_object=simplexml_load_string('<SOME XML DATA');
$xml_array=object2array($xml_object);
?>
小心检查解析错误。空SimpleXMLElement可能解析为FALSE,如果您的XML不包含文本或仅包含命名空间元素,则您的错误检查可能错误。检查解析错误时,始终使用`=== FALSE`。
<?php
$xml = <<<XML
<?xml version="1.0" encoding="UTF-8"?>
<ns1:Root xmlns:ns1="http://example.com/custom">
<ns1:Node>There's stuff here</ns1:Node>
</ns1:Root>
XML;
$simplexml = simplexml_load_string($xml);
// 这将输出 "Parse Error"。
echo ($simplexml ? 'Valid XML' : 'Parse Error'), PHP_EOL;
// 但这将输出 "There's stuff here",证明 SimpleXML 对象已成功创建。
echo $simplexml->children('http://example.com/custom')->Node, PHP_EOL;
// 请改用以下方法:
echo ($simplexml !== FALSE ? 'Valid XML' : 'Parse Error'), PHP_EOL;
?>
参见
https://bugs.php.net/bug.php?id=31045
https://bugs.php.net/bug.php?id=30972
https://bugs.php.net/bug.php?id=69596
似乎有很多关于 SimpleXML 处理 CDATA 数据存在“问题”的讨论,以及编写函数来去除 CDATA 数据等等。起初我也这么认为,但在 PHP 5.2.6 版本下,它的行为实际上是正常的。
关键在于上面例子 #6 中提到的内容
http://uk2.php.net/manual/en/simplexml.examples.php
“要将元素或属性与字符串进行比较,或将其传递给需要字符串的函数,必须使用 (string) 将其强制转换为字符串。否则,PHP 会将元素视为对象。”
如果标签包含 CDATA 数据,SimpleXML 会记住这一事实,将其与元素的字符串内容分开表示。因此,某些函数(包括 print_r())可能不会显示您预期的结果。但是,如果您显式地强制转换为字符串,则会得到所有内容。
<?php
$xml = simplexml_load_string('<foo>Text1 & XML entities</foo>');
print_r($xml);
/*
SimpleXMLElement Object
(
[0] => Text1 & XML entities
)
*/
$xml2 = simplexml_load_string('<foo><![CDATA[Text2 & raw data]]></foo>');
print_r($xml2);
/*
SimpleXMLElement Object
(
)
*/
// 我的 CDATA 数据去哪里了?
// 让我们尝试显式转换
print_r( (string)$xml );
print_r( (string)$xml2 );
/*
Text1 & XML entities
Text2 & raw data
*/
// 好多了
?>
如前所述,不要使用 var_dump() 或 print_r() 来查看 SimpleXML 对象结构,因为它们并不总是返回您期望的结果。
考虑以下情况
<?php
// xml 数据
$xml_txt = '
<root>
<folder ID="65" active="1" permission="1"><![CDATA[aaaa]]></folder>
<folder ID="65" active="1" permission="1"><![CDATA[bbbb]]></folder>
</root>';
// 将 xml 加载到 SimpleXML 对象中
$xml = simplexml_load_string($xml_txt, 'SimpleXMLElement', LIBXML_NOCDATA);//LIBXML_NOCDATA LIBXML_NOWARNING
// 查看对象结构
print_r($xml);
/* 这将输出
SimpleXMLElement Object
(
[folder] => Array
(
[0] => aaaa
[1] => bbbb
)
)
*/
// 但是...
foreach ($xml->folder as $value){
print_r($value);
}
/* 输出每个 folder 元素的完整结构:
SimpleXMLElement Object
(
[@attributes] => Array
(
[ID] => 65
[active] => 1
[permission] => 1
)
[0] => aaaa
)
SimpleXMLElement Object
(
[@attributes] => Array
(
[ID] => 65
[active] => 1
[permission] => 1
)
[0] => bbbb
)
*/
?>
这似乎没有在任何地方记录,但是您可以参考元素“值”来更改它,如下所示:
<?php
$xml = simplexml_load_string('<root><number>1</number></root>');
echo $xml->asXml(). "\n\n";
$xml->number->{0} = $xml->number->{0} + 1;
echo $xml->asXml();
?>
输出
<?xml version="1.0"?>
<root><number>1</number></root>
<?xml version="1.0"?>
<root><number>2</number></root>
但是,这只适用于直接赋值,不适用于任何其他运算符。
<?php
$xml = simplexml_load_string('<root><number>1</number></root>');
echo $xml->asXml(). "\n\n";
$xml->number->{0} += 1;
// 或:
$xml->number->{0}++;
echo $xml->asXml();
?>
以上两种情况都会导致以下输出:
<?xml version="1.0"?>
<root><number>1</number></root>
<?xml version="1.0"?>
<root><number>1<0/></number></root>
请注意,并非所有 LIBXML 选项都支持 options 参数。
例如,LIBXML_XINCLUDE 不起作用。但是,有一个解决方法
<?php
$xml = new DOMDocument();
$xml->loadXML ($XMLString);
$xml->xinclude();
$xml = simplexml_import_dom($xml);
?>
当序列化包含 html CDATA 的字段时,以下解决方法存在问题。对于 HTML 以外的任何其他内容类型,请尝试修改函数 parseCDATA。
只需在序列化之前添加以下几行代码。
这也是针对此错误的解决方法 http://bugs.php.net/bug.php?id=42001
<?PHP
if(strpos($content, '<![CDATA[')) {
function parseCDATA($data) {
return htmlentities($data[1]);
}
$content = preg_replace_callback(
'#<!\[CDATA\[(.*)\]\]>#',
'parseCDATA',
str_replace("\n", " ", $content)
);
}
?>
一个简单的扩展,添加了一个用于检索特定属性的方法。
<?php
class simple_xml_extended extends SimpleXMLElement
{
public function Attribute($name)
{
foreach($this->Attributes() as $key=>$val)
{
if($key == $name)
return (string)$val;
}
}
}
$xml = simplexml_load_string('
<xml>
<dog type="poodle" owner="Mrs Smith">Rover</dog>
</xml>', 'simple_xml_extended');
echo $xml->dog->Attribute('type');
?>
输出 'poodle'
我更喜欢使用这种技术而不是类型转换属性。
我想将一个包含字符串和其他相同类型数组的数组转换为一个 SimpleXML 对象。
这是我开发的用于执行此转换的函数 array2xml 的代码。请注意,这段代码很简单,没有任何检查。
<?php
function array2xml($array, $tag) {
function ia2xml($array) {
$xml="";
foreach ($array as $key=>$value) {
if (is_array($value)) {
$xml.="<$key>".ia2xml($value)."</$key>";
} else {
$xml.="<$key>".$value."</$key>";
}
}
return $xml;
}
return simplexml_load_string("<$tag>".ia2xml($array)."</$tag>");
}
$test['type']='lunch';
$test['time']='12:30';
$test['menu']=array('entree'=>'salad', 'maincourse'=>'steak');
echo array2xml($test,"meal")->asXML();
?>
这是一个简单的SimpleXML封装函数。
据我所知,它与Julio Cesar Oliveira(上面)的函数功能相同。
它将XML字符串解析成一个多维关联数组。
第二个参数是一个回调函数,该函数会对所有数据执行操作(例如,如果您希望所有数据都被修剪,就像Julio在他的函数中所做的那样,只需将'trim'作为第二个参数传递)。
<?php
function unserialize_xml($input, $callback = null, $recurse = false)
/* bool/array unserialize_xml ( string $input [ , callback $callback ] )
* 反序列化XML字符串,返回一个多维关联数组,可以选择对所有非数组数据运行回调函数
* 所有失败都返回false
* 注意:
* 根XML标签将被剥离
* 由于其递归特性,unserialize_xml() 也支持 SimpleXMLElement 对象和数组作为输入
* 使用 simplexml_load_string() 进行 XML 解析,有关更多信息,请参阅 SimpleXML 文档
*/
{
// 获取输入,如果它是递归的顶层,则使用 simplexml 加载 xml 字符串
$data = ((!$recurse) && is_string($input))? simplexml_load_string($input): $input;
// 将 SimpleXMLElements 转换为数组
if ($data instanceof SimpleXMLElement) $data = (array) $data;
// 递归进入数组
if (is_array($data)) foreach ($data as &$item) $item = unserialize_xml($item, $callback, true);
// 运行回调函数并返回
return (!is_array($data) && is_callable($callback))? call_user_func($callback, $data): $data;
}
?>
<?php
$xml = json_decode(json_encode((array) simplexml_load_string($string)), 1);
?>
提醒一下,`json_encode` 会尝试将数据转换为 UTF-8,而无需特定了解源编码。如果您没有使用 UTF-8,则此方法可能会导致编码问题。
XML2Array 函数现在是递归的!
<?php
function XML2Array ( $xml , $recursive = false )
{
if ( ! $recursive )
{
$array = simplexml_load_string ( $xml ) ;
}
else
{
$array = $xml ;
}
$newArray = array () ;
$array = ( array ) $array ;
foreach ( $array as $key => $value )
{
$value = ( array ) $value ;
if ( isset ( $value [ 0 ] ) )
{
$newArray [ $key ] = trim ( $value [ 0 ] ) ;
}
else
{
$newArray [ $key ] = XML2Array ( $value , true ) ;
}
}
return $newArray ;
}
?>
这是我对Bob的简单SimpleXML封装函数的更新。
我注意到他的版本会将一个空的SimpleXMLElement转换成一个空数组。
<?php
/**
* https://php.net/manual/en/function.simplexml-load-string.php#91564
*
* bool/array unserialize_xml ( string $input [ , callback $callback ] )
* 反序列化XML字符串,返回一个多维关联数组,可以选择对所有非数组数据运行回调函数
* 所有失败都返回false
* 注意:
* 根XML标签将被剥离
* 由于其递归特性,unserialize_xml() 也支持 SimpleXMLElement 对象和数组作为输入
* 使用 simplexml_load_string() 进行 XML 解析,有关更多信息,请参阅 SimpleXML 文档
*
* @param $input
* @param null $callback
* @param bool $recurse
* @return array|mixed
*
*/
function unserialize_xml($input, $callback = null, $recurse = false)
{
// 获取输入,如果它是递归的顶层,则使用 simplexml 加载 xml 字符串
$data = ((!$recurse) && is_string($input))? simplexml_load_string($input): $input;
// 将 SimpleXMLElements 转换为数组
if ($data instanceof SimpleXMLElement){
if(!empty($data)){
$data = (array) $data;
} else {
$data = '';
}
}
// 递归进入数组
if (is_array($data)) foreach ($data as &$item) $item = unserialize_xml($item, $callback, true);
// 运行回调函数并返回
return (!is_array($data) && is_callable($callback))? call_user_func($callback, $data): $data;
}
?>
使用 `libxml_disable_entity_loader()` 来限制加载外部文件。参见 http://www.idontplaydarts.com/2011/02/scanning-the-internal-network-using-simplexml/
如果您想设置输出xml的字符集,只需设置encoding属性,如下所示:
<?php simplexml_load_string('<?xml version="1.0" encoding="utf-8"?><xml/>'); ?>
由 `$xml->asXML` 生成的 XML 输出将包含带重音符号的字符,例如“é”,而不是“é”。
希望这有帮助
SimpleXML 无法在 foreach 循环中简单地处理 CDATA 节。
<?php
$sx = simplexml_load_string('
<test>
<one>hi</one>
<two><![CDATA[stuff]]></two>
<t>
<for>two</for>
</t>
<multi>one</multi>
<multi>two</multi>
</test>');
foreach((array) $sx as $tagname => $val) {
if (is_string($val)) {
// <one> 将在此处
} elseif (is_array($val)) {
// <multi> 将在此处,因为它出现多次
} elseif (is_object($val)) {
// <t> 将在此处,因为它包含标签
// <two> 将在此处,因为它包含 CDATA!
}
}
?>
要在循环中进行测试,请执行以下操作
<?php
if (count((array) $val) == 0) {
// 这不是包含其他标签的标签
$val = '' . $val;
// 现在 CDATA 以神奇的方式显示了。
}
?>
Wrapper XMLReader 类,用于简单地 SAX 读取大型 xml
https://github.com/dkrnl/SimpleXMLReader
使用方法示例: http://github.com/dkrnl/SimpleXMLReader/blob/master/examples/example1.php
在四处摸索了一段时间后,我突然意识到了一些事情(也许很明显,对我来说却不是)。希望可以帮助其他人避免像我一样浪费时间 :-P
当你遇到类似这样的情况时
<?php
$xmlstr = <<<XML
<?xml version="1.0" encoding="utf-8"?>
<double xmlns="http://foosite.foo/">2328</double>
XML;
?>
SimpleXML 对象将被“转换”为 text() 内容
<?php
$xml = simplexml_load_string($xmlstr);
echo $xml; // 这将输出 2328(字符串)
?>
如果要使用名称空间中存在的类,请使用其全名。simple_load_string 无法识别简短名称。
class.new.php
<?php
namespace foo\bar;
class new extends SimpleXMLElement
{
public function do()
{
echo "done";
}
}
?>
false.php
<?php
use \foo\bar\new;
$result = simplexml_load_string($xml, 'new'); // 它会给出警告
$result->do(); // 致命错误
?>
true.php
<?php
use \foo\bar\new;
$result = simplexml_load_string($xml, '\foo\bar\new');
$result->do(); // 输出 done
?>