有时我们的 xml 具有连字符节点,例如
<my_xml>
<some-node>value</some-node>
</my_xml>
您需要使用
<?php
$simpleXmlObj->{'some-node'}
?>
而不是
<?php
$simpleXmlObj->some-node;
?>
(PHP 5, PHP 7, PHP 8)
simplexml_load_file — 将 XML 文件解释为对象
$filename
,$class_name
= SimpleXMLElement::class,$options
= 0,$namespace_or_prefix
= "",$is_prefix
= false
将给定文件中的格式良好的 XML 文档转换为对象。
filename
XML 文件的路径
class_name
您可以使用此可选参数,以便 simplexml_load_file() 返回指定类的对象。该类应该扩展 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
// 文件 test.xml 包含一个 XML 文档,其中有一个根元素
// 以及至少一个元素 /[root]/title。
if (file_exists('test.xml')) {
$xml = simplexml_load_file('test.xml');
print_r($xml);
} else {
exit('Failed to open test.xml.');
}
?>
此脚本将在成功时显示
SimpleXMLElement Object ( [title] => Example Title ... )
此时,您可以开始使用 $xml->title
和任何其他元素。
有时我们的 xml 具有连字符节点,例如
<my_xml>
<some-node>value</some-node>
</my_xml>
您需要使用
<?php
$simpleXmlObj->{'some-node'}
?>
而不是
<?php
$simpleXmlObj->some-node;
?>
要正确地从 CDATA 中提取值,请确保通过使用强制转换运算符将 SimpleXML 元素强制转换为字符串值
<?php
$xml = '<?xml version="1.0" encoding="UTF-8" ?>
<rss>
<channel>
<item>
<title><![CDATA[Tom & Jerry]]></title>
</item>
</channel>
</rss>';
$xml = simplexml_load_string($xml);
// echo 会为您进行强制转换
echo $xml->channel->item->title;
// 但 vardump(或 print_r)不会!
var_dump($xml->channel->item->title);
// 所以将 SimpleXML 元素强制转换为 'string' 可以解决此问题
var_dump((string) $xml->channel->item->title);
?>
以上将输出
Tom & Jerry
object(SimpleXMLElement)#4 (0) {}
string(11) "Tom & Jerry"
// 迁移或使用本地机器时要小心
// 用于测试/开发。
// Windows 目录分隔符:"\" 和 "/"
// 您可能会混合使用分隔符 "C:\somedir\www/img/bg.jpg"。
// 混合使用分隔符的路径在其他函数中可以正常工作
// 但 simplexml_load_file() 在混合使用分隔符时会失败。
// 示例
include("C:\dir\my.php"); // 工作(Windows)
include("C:\dir/my.php"); // 工作(Windows)混合使用
include("C:/dir/my.php"); // 工作(Windows、Linux)
simplexml_load_file("C:\dir\my.php"); // 工作
simplexml_load_file("C:\dir/my.php"); // 混合使用时失败
simplexml_load_file("C:/dir/my.php"); // 工作
由于我的 XML 文件的编码是 UTF-8,而
我的网页的编码是 iso-8859-1,我得到了一些奇怪的字符,例如 ’ 而不是右单引号。
这个解决方案很难找到,但实现起来却很简单。
http://uk3.php.net/manual/en/function.iconv.php
使用 iconv() 函数,您可以从一种编码转换为另一种编码,TRANSLIT 选项似乎最适合我的需要。这是我的示例
<?php
// 将字符串从 utf-8 转换为 iso8859-1
$horoscope = iconv( "UTF-8", "ISO-8859-1//TRANSLIT", $horoscope );
?>
我在这个页面上找到了解决方案...
http://tinyurl.com/lm39xc
希望这有帮助
这有时会被忽略,但如果你的 XML 节点格式为
<prefix:element />
你需要确保将 [命名空间或前缀] 参数和 [isPrefix] 参数设置为 true。另外,在调用元素时,你需要避免添加前缀(如果前缀已经设置),所以在上面的例子中,“prefix:element”应该添加为“element”,但在保存时会自动添加前缀。
如果在加载或对象构造期间没有设置前缀,加载将无法正确获取节点,你将无法直接调用元素,因此 $xml->{'prefix:element'} 也不起作用。
如果你想要在你的对象中使用 CDATA,你应该使用 LIBXML_NOCDATA
<?php
$xml = simplexml_load_file($file_xml, 'SimpleXMLElement',LIBXML_NOCDATA);
print_r($xml);
?>
如果你想要检查这个函数何时失败,请确保用 === 而不是 == 来比较返回值
<?php
$url = 'http://www.example.com';
$xml = simpleXML_load_file($url,"SimpleXMLElement",LIBXML_NOCDATA);
if($xml === FALSE)
{
// 处理错误
}
else { // 执行操作 }
?>
否则,即使文档是正常的,你也可能会一直得到 FALSE。希望这能帮助到某人 ;)
尽管该函数的文档中有说明,但它并不接受所有路径名。
$ php -r 'print_r( simplexml_load_file("%25.xml"));'
PHP Warning: simplexml_load_file(): I/O warning : failed to load external entity "%25.xml" in Command line code on line 1
我偶然发现了这个问题:一个包含简单字符串的单一元素变成了一个字符串,但一个包含 *空格* 的单一元素变成了一个数组,其中包含一个元素,即空格字符串。
我相信对于 XML 专家来说,这很明智且奇妙,但这确实让我很困惑,我认为它也可能让其他人感到困惑。
<?php
$parsed = simplexml_load_string('<container><space> </space><blank></blank><string>hello</string></container>');
$content = json_decode(json_encode($parsed),TRUE);
var_dump($content);
/* 输出结果为:
array(3) {
'space' => array(1) { ← 没有预料到这个!
[0] => string(1) " "
}
'blank' => array(0) { }
'string' => string(5) "hello"
}
*/
如果你不希望 CDATA 值被转义,只需使用 LIBXML_NOCDATA 作为第 3 个参数加载 XML。
注意:这需要 PHP 版本 >= 5.1.0 才能正常工作。
示例
<?php simplexml_load_file('xmldatei.xml', null, LIBXML_NOCDATA); ?>
假设你已经将一个 XML 文件加载到 $simpleXML_obj 中。
结构如下
SimpleXMLElement Object
(
[node1] => SimpleXMLElement Object
(
[subnode1] => value1
[subnode2] => value2
[subnode3] => value3
)
[node2] => SimpleXMLElement Object
(
[subnode4] => value4
[subnode5] => value5
[subnode6] => value6
)
)
在对象中搜索特定节点时,可以使用此函数
<?php
function &getXMLnode($object, $param) {
foreach($object as $key => $value) {
if(isset($object->$key->$param)) {
return $object->$key->$param;
}
if(is_object($object->$key)&&!empty($object->$key)) {
$new_obj = $object->$key;
$ret = getCfgParam($new_obj, $param);
}
}
if($ret) return (string) $ret;
return false;
}
?>
因此,如果你想要获取 subnode4 的值,可以使用此函数,如下所示
<?php
$result = getXMLnode($simpleXML_obj, 'subnode4');
echo $result;
?>
它将显示 "value4"
如果你有一些节点包含特殊字符,它们将无法正确加载
例如,请查看以下节点
<node:number>1538-7445</node:number>
<node:coverDisplayDate>Sep 1 2012 12:00:00:000AM</node:coverDisplayDate>
你必须将 : 更改为其他特殊字符,例如 -,才能正确转换它
正确的节点
<node-number>1538-7445</node-number>
<node-coverDisplayDate>Sep 1 2012 12:00:00:000AM</node-coverDisplayDate>
我在调试时浪费了宝贵的时间。请注意这一点。?
如果你使用 simplexml 数据直接填充你的 MySQL 数据库(使用 MYSQLi 和绑定参数),请注意。
来自 simplexml 的数据是对象,而 MySQLi 的绑定参数函数不喜欢对象!(这会导致一些内存泄漏,并可能导致 Apache/PHP 崩溃)
为了正确执行此操作,你必须将你的值转换为正确的类型(字符串、整数...)然后再将它们传递给 MySQLi 的绑定方法。
我在文档中没有找到这一点,这给我带来了很多头痛。
有时你可能会尝试加载一个文件,但它会抱怨实体并抛出一个解析错误。
如果是这样,请检查问题文件是否不包含一个没有对应实体引用的&符号。
如果包含,或者你想谨慎行事,那么不要使用 simplexml_load_file,而是尝试以下方法
$file = file_get_contents('stuff.xml');
$temp = preg_replace('/&(?!(quot|amp|pos|lt|gt);)/', '&', $file);
$xml = simplexml_load_string($temp) or die("xml not loading");
将文件读入一个字符串中,在任何不是字符实体一部分的&符号后添加“amp;”,然后将字符串解析为 XML。
如果你要加载很多文件,这可能会减慢你的页面加载速度。
要设置超时,可以使用 file_get_context,然后使用 simplexml_load_string
<?php
$fp = fopen('http://www.example.com/rss', false, stream_create_context(array('http' => array('timeout', '1.5'))));
if ($fp) {
print_r( simplexml_load_string($fp) );
} else {
echo "The request timed out";
}
?>
使 SimpleXMLElement 对象在会话中保存。
除了无法在会话中保存之外,SimpleXMLElement 对象甚至可能在尝试重新进入会话时导致 session_start() 函数崩溃!
为了解决这个问题,我使用了以下模式。核心思想是在会话调用之间将 SimpleXMLElement 对象转换为字符串表示形式,该字符串表示形式当然可以在会话中保存。
<?php
//
// SimpleXMLElement 对象的会话保存处理
// (适用于/测试 PHP 5.1.5 和 PHP 5.2.1)
// myClass 模式允许方便地访问
// XML 结构,同时进行会话保存
//
class myClass
{
private $o_XMLconfig = null;
private $s_XMLconfig = '';
public function __construct($args_configfile)
{
$this->o_XMLconfig = simplexml_load_file($args_configfile);
$this->s_XMLconfig = $this->o_XMLconfig->asXML();
} // __construct()
public function __destruct()
{
$this->s_XMLconfig = $this->o_XMLconfig->asXML();
unset($this->o_XMLconfig); // 否则此对象将崩溃
// 后续调用
// session_start()!
} // __destruct()
public function __wakeup()
{
$this->o_XMLconfig = simplexml_load_string($this->s_XMLconfig);
} // __wakeup()
} // class myClass
?>
一个围绕 simplexml_load_file 的包装器,用于在 XML 服务器超时或出现 500 错误等时绕过讨厌的错误消息。
<?php
function loadXML2($domain, $path, $timeout = 30) {
/*
用法:
$xml = loadXML2("127.0.0.1", "/path/to/xml/server.php?code=do_something");
if($xml) {
// 加载 xml 文档
} else {
// 失败。显示友好错误消息。
}
*/
$fp = fsockopen($domain, 80, $errno, $errstr, $timeout);
if($fp) {
// 发出请求
$out = "GET $path HTTP/1.1\r\n";
$out .= "Host: $domain\r\n";
$out .= "Connection: Close\r\n\r\n";
fwrite($fp, $out);
// 获取响应
$resp = "";
while (!feof($fp)) {
$resp .= fgets($fp, 128);
}
fclose($fp);
// 检查状态是否为 200
$status_regex = "/HTTP\/1\.\d\s(\d+)/";
if(preg_match($status_regex, $resp, $matches) && $matches[1] == 200) {
// 将 xml 加载为对象
$parts = explode("\r\n\r\n", $resp);
return simplexml_load_string($parts[1]);
}
}
return false;
}
?>
如果您发现使用 simplexml_load_file() 时收到 500 错误,但您可以通过浏览器手动访问 xml/rss feed,那么您的脚本可能被用户代理嗅探器阻止。
在您的 xml 调用之前添加此代码以解决此问题
<?php
ini_set("user_agent","Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0)");
ini_set("max_execution_time", 0);
ini_set("memory_limit", "10000M");
$rss = simplexml_load_file($feed_url);
?>
Micro$oft Word 使用非标准字符,这些字符在使用 simplexml_load_file 时会造成问题。
许多系统在其实现的 ISO-8859-1 中包含非标准 Word 字符。因此,包含这些字符的 XML 文档可能对许多浏览器来说看起来格式良好(即)。但是,如果您尝试使用 simplexml_load_file 加载这种文档,您将遇到一些麻烦。
我相信这与 htmlentites 中讨论的完全相同的问题。以下关于 htmlentites 的注释在这里也很有意思(按相反的顺序给出,以提供历史记录)
http://it.php.net/manual/en/function.htmlentities.php#26379
http://it.php.net/manual/en/function.htmlentities.php#41152
http://it.php.net/manual/en/function.htmlentities.php#42126
http://it.php.net/manual/en/function.htmlentities.php#42511
关于 2006 年 4 月 7 日的匿名用户
有一种方法可以取回 HTML 标签。例如
<?xml version="1.0"?>
<intro>
欢迎来到 <b>Example.com</b>!
</intro>
<?php
// 我使用 @ 以便在加载失败时它不会在错误消息中输出我的 XML 的内容。内容可能是密码,所以只是为了安全起见。
$xml = @simplexml_load_file('content_intro.xml');
if ($xml) {
// asXML() 将保留 HTML 标签,但它也将保留父标签 <intro>,因此我用 str_replace 将它们剥离。如果有很多标签,您也可以使用 preg_replace。
$intro = str_replace(array('<intro>', '</intro>'), '', $xml->asXML());
} else {
$error = "无法加载 intro XML 文件。";
}
?>
使用这种方法,有人可以更改 content_intro.xml 中的 intro 并确保 HTML 格式良好,不会破坏整个网站设计。
如果您有一个 XML 文件,其中在一级包含一系列同名元素,simplexml 会错误地处理它们,并且不允许使用 foreach() 遍历数组。据我所知,这是由 PHP xml_parser 引起的问题(参见:http://ru2.php.net/manual/ru/function.xml-parser-create.php#53188)。
要避免这种情况,只需使用 count() 并使用 for() 遍历数组。
示例
<params>
<param>
<name>version.shell</name>
<value>1.0</value>
</param>
<param>
<name>version.core</name>
<value>1.0</value>
</param>
<param>
<name>file.lang</name>
<value>vc.lang</value>
</param>
...
</params>
<?php
$filename = '...';
$xml = simplexml_load_file($filename);
$p_cnt = count($xml->param);
for($i = 0; $i < $p_cnt; $i++) {
$param = $xml->param[$i];
...;
}
?>
看来 SimpleXML 不支持 CDATA... 我把这个小正则表达式函数拼凑在一起,以便在尝试使用 simplexml_load_file/simplexml_load_string 之类解析 XML 之前对 CDATA 进行排序。希望它能帮助到某些人,并且很乐意听到更好的解决方案。(当然,除了 *不* 使用 SimpleXML!;)
它查找任何 <![CDATA [文本和 HTML 等在此处]]> 元素,对封装的数据进行 htmlspecialchar() 处理,然后剥离 "<![CDATA [" 和 "]]>" 标签。
<?php
函数 simplexml_unCDATAise($xml) {
$new_xml = NULL;
preg_match_all("/\<\!\[CDATA \[(.*)\]\]\>/U", $xml, $args);
如果 (is_array($args)) {
如果 (isset($args[0]) && isset($args[1])) {
$new_xml = $xml;
为了 ($i=0; $i<count($args[0]); $i++) {
$old_text = $args[0][$i];
$new_text = htmlspecialchars($args[1][$i]);
$new_xml = str_replace($old_text, $new_text, $new_xml);
}
}
}
返回 $new_xml;
}
//用法:
$xml = '你的 XML 带有 CDATA...';
$xml = simplexml_unCDATAise($xml);
$xml_object = simplexml_load_string($xml);
?>
一个在使用代理后使用 simplexml_load_file 的非常有帮助的小函数
<?php
函数 getXMLfromURL($url) {
$Proxy = getenv("HTTP_PROXY");
如果 (strlen($Proxy) > 1) {
$r_default_context = stream_context_get_default ( 数组
('http' => 数组(
'proxy' => $Proxy,
'request_fulluri' => True,
),
)
);
libxml_set_streams_context($r_default_context);
}
$daten = simplexml_load_file($url);
返回 ($daten);
}
?>
其中 HTTP_PROXY 设置为例如:tcp://proxy:8080
对于嵌套和相同名称的值,我做了一些小修改,以便从谷歌地理编码获取和显示多个值。当没有完全匹配时,它会以以下格式返回所有接近匹配的值(这是一个简略版本):
<Response>
<Placemark id="1">
<address> New York 24, NY, USA</address>
<AddressDetails>
..................
</AddressDetails>
<Point>
<coordinates>-73.5850086,40.7207442,0</coordinates>
</Point>
</Placemark>
<Placemark id="2">
<address>New York 27, NY, USA</address>
<AddressDetails>
...................
</AddressDetails>
<Point>
<coordinates>-72.8987835,40.8003588,0</coordinates>
</Point>
</Placemark>
<Placemark id="3">
<address>Cedar Place School, 20 Cedar Pl, Yonkers, NY 10705, USA</address>
<AddressDetails>
..................
</AddressDetails>
<Point>
<coordinates>-73.8966320,40.9256520,0</coordinates>
</Point>
</Placemark>
</Response>
<?php
// 获取并分解结果,然后将它们存储在 $var 中
$Address = "99999 parkplace, new york, NY";
$urladdress = urlencode($Address);
$Base_url = "http://maps.google.com/maps/geo?q=";
$urlParts = "&output=xml";
$urlrequest = $Base_url . $urladdress . $urlParts;
$xml = simplexml_load_file($urlrequest);
$num = "0";
foreach ($xml->Response->Placemark as $value){
$num++;
$GeoFindAdd{$num} = $value->address;
$GeoFindCords{$num} = $value->Point->coordinates;
}
// 结果的简单显示
echo "找到 ",$num," 个可能的地理数据集 <br>";
$CountNumResults = "0";
为了 ( ; $num > 0; $num--){
$CountNumResults++;
echo $countnum,"<br> 地址 = ",$GeoFindAdd{$num},"<br> 坐标 = ",$GeoFindCords{$num},"<br>";
}
echo "END";
?>
使用该脚本发现 simplexml_load_file() 会删除 XML 文件中的任何 HTML 格式,并且只会加载到一定深度。如果你的 XML 文件太深,它会返回一个布尔值 false。
抱歉,之前函数中有一个错误
<?php
函数 &getXMLnode($object, $param) {
遍历($object 作为 $key => $value) {
如果(isset($object->$key->$param)) {
返回 $object->$key->$param;
}
如果(is_object($object->$key)&&!empty($object->$key)) {
$new_obj = $object->$key;
// 必须在那里使用 getXMLnode 函数(递归)
$ret = getXMLnode($new_obj, $param);
}
}
如果($ret) 返回 (字符串) $ret;
返回 false;
}
?>
获取所有标签及其值。(递归)
<?php
$xml = simplexml_load_file('settings.xml');
函数 all_tag($xml){
$i=0; $name = "";
遍历 ($xml 作为 $k){
$tag = $k->getName();
$tag_value = $xml->$tag;
如果 ($name == $tag){ $i++; }
$name = $tag;
echo $tag .' '.$tag_value[$i].'<br />';
// 递归
all_tag($xml->$tag->children());
}
}
all_tag($xml);
?>
如果对象的属性为空,则不会创建数组。这是一个正确传输的 object2array 版本。
<?php
function object2array($object)
{
$return = NULL;
if(is_array($object))
{
foreach($object as $key => $value)
$return[$key] = object2array($value);
}
else
{
$var = get_object_vars($object);
if($var)
{
foreach($var as $key => $value)
$return[$key] = ($key && !$value) ? NULL : object2array($value);
}
else return $object;
}
return $return;
}
?>
完整分析 XML。
<?php
$xml = simplexml_load_file('file.xml');
foreach($xml as $key0 => $value){
echo "..1..[$key0] => $value";
foreach($value->attributes() as $attributeskey0 => $attributesvalue1){
echo "________[$attributeskey0] = $attributesvalue1";
}
echo '<br />';
////////////////////////////////////////////////
foreach($value as $key => $value2){
echo "....2.....[$key] => $value2";
foreach($value2->attributes() as $attributeskey => $attributesvalue2){
echo "________[$attributeskey] = $attributesvalue2";
}
echo '<br />';
////////////////////////////////////////////////
foreach($value2 as $key2 => $value3){
echo ".........3..........[$key2] => $value3";
foreach($value3->attributes() as $attributeskey2 => $attributesvalue3){
echo "________[$attributeskey2] = $attributesvalue3";
}
echo '<br />';
////////////////////////////////////////////////
foreach($value3 as $key3 => $value4){
echo "...................4....................[$key3] => $value4";
foreach($value4->attributes() as $attributeskey3 => $attributesvalue4){
echo "________[$attributeskey3] = $attributesvalue4";
}
echo '<br />';
////////////////////////////////////////////////
foreach($value4 as $key4 => $value5){
echo ".....................5......................[$key4] => $value5";
foreach($value5->attributes() as $attributeskey4 => $attributesvalue5){
echo "________[$attributeskey4] = $attributesvalue5";
}
echo '<br />';
////////////////////////////////////////////////
foreach($value5 as $key5 => $value6){
echo "......................6.......................[$key5] => $value6";
foreach($value6->attributes() as $attributeskey5 => $attributesvalue6){
echo "________[$attributeskey5] = $attributesvalue6";
}
echo '<br />';
}}}}}
echo '<br />';
}
?>
如果需要将 SimpleXML 中的数据解析到会话变量中,请记住首先将数据定义为字符串。
如果不这样做,您将收到“节点不再存在”的警告,指向您的 session_start() 函数。
这将起作用
<?php
$new_version = simplexml_load_file('http://example.com/version.xml');
$_SESSION['current_version'] = (string)$new_version->version;
?>