XML SimpleXML
The shortest way to read XML: attributes, array access, namespaces and conversion.
Reading
<?php
$xml = '<?xml version="1.0" encoding="UTF-8"?>
<books>
<book id="1"><title>PHP 入门</title><price>59</price></book>
<book id="2"><title>PHP 进阶</title><price>79</price></book>
</books>';
$s = simplexml_load_string($xml);
foreach ($s->book as $b) {
echo $b["id"] . " " . $b->title . " " . $b->price . "\n";
}
echo "共 " . count($s->book) . " 本\n";
echo "根元素: " . $s->getName() . "\n";1 PHP 入门 59
2 PHP 进阶 79
共 2 本
根元素: booksElements are properties ($s->book); attributes are array keys ($b["id"]). Repeated elements become iterable collections and count() works.
Converting to arrays
SimpleXML objects are not plain objects; json_encode often surprises. Convert explicitly.
<?php
$s = simplexml_load_string($xml);
// 直接 json_encode:单个元素和多个元素结构不一致
echo json_encode($s), "\n";
// 单个字段取值要转字符串
$first = (string)$s->book[0]->title;
var_dump($first);
// 转成数组
$arr = json_decode(json_encode($s), true);
print_r($arr["book"][0]);{"book":[{"title":"PHP 入门","price":"59","@attributes":{"id":"1"}},{"title":"PHP 进阶","price":"79","@attributes":{"id":"2"}}]}
string(9) "PHP 入门"
Array
(
[title] => PHP 入门
[price] => 59
[@attributes] => Array
(
[id] => 1
)
)Namespaces
Namespaced XML (RSS, SOAP, Office files) returns empty unless you declare the namespace via children().
<?php
$xml = '<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/">
<channel>
<item>
<title>第一篇</title>
<dc:creator>张三</dc:creator>
</item>
</channel>
</rss>';
$s = simplexml_load_string($xml);
echo (string)$s->channel->item->title, "\n";
$dc = $s->channel->item->children("dc", true);
echo (string)$dc->creator, "\n";
// 列出所有命名空间
print_r($s->getNamespaces(true));第一篇
张三
Array
(
[dc] => http://purl.org/dc/elements/1.1/
)true treats dc as a prefix rather than a URI. Omit it and you get silent empty results.XPath
<?php
$s = simplexml_load_string($xml);
// 属性筛选
$r = $s->xpath("/books/book[@id='2']/title");
echo (string)$r[0], "\n";
// 数值比较
$r = $s->xpath("//book[price > 60]/title");
echo (string)$r[0], "\n";
// 取属性集合
$r = $s->xpath("//book/@id");
echo implode(",", array_map("strval", $r)), "\n";PHP 进阶
PHP 进阶
1,2xpath() always returns an array (possibly empty); $r[0] on an empty array warns. Check if ($r) first.
Generating XML
<?php
$s = new SimpleXMLElement("<books></books>");
foreach ([["1", "PHP 入门", 59], ["2", "PHP 进阶", 79]] as [$id, $title, $price]) {
$b = $s->addChild("book");
$b->addAttribute("id", $id);
$b->addChild("title", htmlspecialchars($title, ENT_XML1, "UTF-8"));
$b->addChild("price", (string)$price);
}
$dom = dom_import_simplexml($s)->ownerDocument;
$dom->formatOutput = true;
echo $dom->saveXML();<?xml version="1.0"?>
<books>
<book id="1">
<title>PHP 入门</title>
<price>59</price>
</book>
<book id="2">
<title>PHP 进阶</title>
<price>79</price>
</book>
</books>addChild does not escape — & or < produces invalid XML. Escape with htmlspecialchars(..., ENT_XML1) or switch to DOM.
Which to choose
| Task | Best | Why |
|---|---|---|
| 读几个字段 | SimpleXML | 代码最短 |
| 要改结构、删节点 | DOM | SimpleXML 改起来别扭 |
| 几十 MB 的 XML | Expat | 内存恒定 |
| 要 XPath 复杂查询 | DOM 或 SimpleXML | 都支持 |
| 要严格类型和校验 | DOM + 手动检查 | SimpleXML 太宽松 |
if ($x) is true because the object exists. Always cast to (string) before testing.读取
<?php
$xml = '<?xml version="1.0" encoding="UTF-8"?>
<books>
<book id="1"><title>PHP 入门</title><price>59</price></book>
<book id="2"><title>PHP 进阶</title><price>79</price></book>
</books>';
$s = simplexml_load_string($xml);
foreach ($s->book as $b) {
echo $b["id"] . " " . $b->title . " " . $b->price . "\n";
}
echo "共 " . count($s->book) . " 本\n";
echo "根元素: " . $s->getName() . "\n";1 PHP 入门 59
2 PHP 进阶 79
共 2 本
根元素: books元素是对象属性($s->book),属性是数组下标($b["id"])。同名元素自动变成可遍历的集合,count() 直接可用。
转成数组
SimpleXML 的对象不是普通对象,json_encode 出来的结构常和预期不符。要数组就显式转。
<?php
$s = simplexml_load_string($xml);
// 直接 json_encode:单个元素和多个元素结构不一致
echo json_encode($s), "\n";
// 单个字段取值要转字符串
$first = (string)$s->book[0]->title;
var_dump($first);
// 转成数组
$arr = json_decode(json_encode($s), true);
print_r($arr["book"][0]);{"book":[{"title":"PHP 入门","price":"59","@attributes":{"id":"1"}},{"title":"PHP 进阶","price":"79","@attributes":{"id":"2"}}]}
string(9) "PHP 入门"
Array
(
[title] => PHP 入门
[price] => 59
[@attributes] => Array
(
[id] => 1
)
)命名空间
带命名空间的 XML(RSS、SOAP、Office 文档)直接访问会拿到空值,必须先用 children() 声明命名空间。
<?php
$xml = '<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/">
<channel>
<item>
<title>第一篇</title>
<dc:creator>张三</dc:creator>
</item>
</channel>
</rss>';
$s = simplexml_load_string($xml);
echo (string)$s->channel->item->title, "\n";
$dc = $s->channel->item->children("dc", true);
echo (string)$dc->creator, "\n";
// 列出所有命名空间
print_r($s->getNamespaces(true));第一篇
张三
Array
(
[dc] => http://purl.org/dc/elements/1.1/
)children("dc", true) 的第二个参数 true 表示「把 dc 当前缀而不是 URI」。不传就只能用完整 URI,而且拿不到结果时不会报错,只会静默返回空。XPath
<?php
$s = simplexml_load_string($xml);
// 属性筛选
$r = $s->xpath("/books/book[@id='2']/title");
echo (string)$r[0], "\n";
// 数值比较
$r = $s->xpath("//book[price > 60]/title");
echo (string)$r[0], "\n";
// 取属性集合
$r = $s->xpath("//book/@id");
echo implode(",", array_map("strval", $r)), "\n";PHP 进阶
PHP 进阶
1,2xpath() 总是返回数组(可能为空),取不到时 $r[0] 会报 undefined offset。先判断 if ($r) 更稳。
生成 XML
<?php
$s = new SimpleXMLElement("<books></books>");
foreach ([["1", "PHP 入门", 59], ["2", "PHP 进阶", 79]] as [$id, $title, $price]) {
$b = $s->addChild("book");
$b->addAttribute("id", $id);
$b->addChild("title", htmlspecialchars($title, ENT_XML1, "UTF-8"));
$b->addChild("price", (string)$price);
}
$dom = dom_import_simplexml($s)->ownerDocument;
$dom->formatOutput = true;
echo $dom->saveXML();<?xml version="1.0"?>
<books>
<book id="1">
<title>PHP 入门</title>
<price>59</price>
</book>
<book id="2">
<title>PHP 进阶</title>
<price>79</price>
</book>
</books>addChild 的第二个参数不会自动转义——内容里有 & 或 < 会生成非法 XML。要么手动 htmlspecialchars(..., ENT_XML1),要么改用 DOM。
三种方式怎么选
| 任务 | 推荐 | 原因 |
|---|---|---|
| 读几个字段 | SimpleXML | 代码最短 |
| 要改结构、删节点 | DOM | SimpleXML 改起来别扭 |
| 几十 MB 的 XML | Expat | 内存恒定 |
| 要 XPath 复杂查询 | DOM 或 SimpleXML | 都支持 |
| 要严格类型和校验 | DOM + 手动检查 | SimpleXML 太宽松 |
null,(string) 之后是空字符串,**判断 if ($x) 会因为对象非空而为真**。取值一律显式 (string) 再判空。