PHP Conference Japan 2024

SimpleXML 基本用法

本参考中的许多示例都需要一个 XML 字符串。为了避免在每个示例中重复此字符串,我们将其放入一个文件中,并在每个示例中包含该文件。以下示例部分显示了包含的文件。或者,您可以创建一个 XML 文档,并使用 simplexml_load_file() 读取它。

示例 #1 包含文件 example.php,其中包含 XML 字符串

<?php
$xmlstr
= <<<XML
<?xml version='1.0' standalone='yes'?>
<movies>
<movie>
<title>PHP: Behind the Parser</title>
<characters>
<character>
<name>Ms. Coder</name>
<actor>Onlivia Actora</actor>
</character>
<character>
<name>Mr. Coder</name>
<actor>El Act&#211;r</actor>
</character>
</characters>
<plot>
So, this language. It's like, a programming language. Or is it a
scripting language? All is revealed in this thrilling horror spoof
of a documentary.
</plot>
<great-lines>
<line>PHP solves all my web problems</line>
</great-lines>
<rating type="thumbs">7</rating>
<rating type="stars">5</rating>
</movie>
</movies>
XML;
?>

当从基本的 XML 文档中提取字符串或数字时,SimpleXML 的简单性最为明显。

示例 #2 获取 <plot>

<?php
include 'example.php';

$movies = new SimpleXMLElement($xmlstr);

echo
$movies->movie[0]->plot;
?>

以上示例将输出

   So, this language. It's like, a programming language. Or is it a
   scripting language? All is revealed in this thrilling horror spoof
   of a documentary.

可以通过将元素名称封装在大括号和撇号中来访问 XML 文档中包含 PHP 命名约定不允许的字符(例如连字符)的元素。(例如,连字符)

示例 #3 获取 <line>

<?php
include 'example.php';

$movies = new SimpleXMLElement($xmlstr);

echo
$movies->movie->{'great-lines'}->line;
?>

以上示例将输出

PHP solves all my web problems

示例 #4 访问 SimpleXML 中的非唯一元素

当多个元素实例作为单个父元素的子元素存在时,将应用正常的迭代技术。

<?php
include 'example.php';

$movies = new SimpleXMLElement($xmlstr);

/* 对于每个 <character> 节点,我们都会输出一个单独的 <name>。 */
foreach ($movies->movie->characters->character as $character) {
echo
$character->name, ' played by ', $character->actor, PHP_EOL;
}

?>

以上示例将输出

Ms. Coder played by Onlivia Actora
Mr. Coder played by El ActÓr

注意:

属性(在前面的示例中为 $movies->movie)不是数组。它们是 可迭代可访问 的对象。

示例 #5 使用属性

到目前为止,我们只介绍了读取元素名称及其值的工作。SimpleXML 还可以访问元素属性。就像访问 数组 的元素一样访问元素的属性。

<?php
include 'example.php';

$movies = new SimpleXMLElement($xmlstr);

/* 访问第一个电影的 <rating> 节点。
* 也输出评分等级。 */
foreach ($movies->movie[0]->rating as $rating) {
switch((string)
$rating['type']) { // 将属性作为元素索引获取
case 'thumbs':
echo
$rating, ' thumbs up';
break;
case
'stars':
echo
$rating, ' stars';
break;
}
}
?>

以上示例将输出

7 thumbs up5 stars

示例 #6 将元素和属性与文本进行比较

要将元素或属性与字符串进行比较或将其传递给需要字符串的函数,必须使用 (string) 将其转换为字符串。否则,PHP 会将元素视为对象。

<?php
include 'example.php';

$movies = new SimpleXMLElement($xmlstr);

if ((string)
$movies->movie->title == 'PHP: Behind the Parser') {
print
'My favorite movie.';
}

echo
htmlentities((string) $movies->movie->title);
?>

以上示例将输出

My favorite movie.PHP: Behind the Parser

示例 #7 比较两个元素

即使两个 SimpleXMLElements 指向相同的元素,它们也被认为是不同的。

<?php
include 'example.php';

$movies1 = new SimpleXMLElement($xmlstr);
$movies2 = new SimpleXMLElement($xmlstr);
var_dump($movies1 == $movies2);
?>

以上示例将输出

bool(false)

示例 #8 使用 XPath

SimpleXML 包含内置的 XPath 支持。要查找所有 <character> 元素

<?php
include 'example.php';

$movies = new SimpleXMLElement($xmlstr);

foreach (
$movies->xpath('//character') as $character) {
echo
$character->name, ' 由 ', $character->actor, PHP_EOL;
}
?>

//” 用作通配符。要指定绝对路径,请省略其中一个斜杠。

以上示例将输出

Ms. Coder played by Onlivia Actora
Mr. Coder played by El ActÓr

示例 #9 设置值

SimpleXML 中的数据不必是常量。该对象允许操作其所有元素。

<?php
include 'example.php';
$movies = new SimpleXMLElement($xmlstr);

$movies->movie[0]->characters->character[0]->name = 'Miss Coder';

echo
$movies->asXML();
?>

以上示例将输出

<?xml version="1.0" standalone="yes"?>
<movies>
 <movie>
  <title>PHP: Behind the Parser</title>
  <characters>
   <character>
    <name>Miss Coder</name>
    <actor>Onlivia Actora</actor>
   </character>
   <character>
    <name>Mr. Coder</name>
    <actor>El Act&#xD3;r</actor>
   </character>
  </characters>
  <plot>
   So, this language. It's like, a programming language. Or is it a
   scripting language? All is revealed in this thrilling horror spoof
   of a documentary.
  </plot>
  <great-lines>
   <line>PHP solves all my web problems</line>
  </great-lines>
  <rating type="thumbs">7</rating>
  <rating type="stars">5</rating>
 </movie>
</movies>

示例 #10 添加元素和属性

SimpleXML 一直以来都能够轻松添加子元素和属性。

<?php
include 'example.php';
$movies = new SimpleXMLElement($xmlstr);

$character = $movies->movie[0]->characters->addChild('character');
$character->addChild('name', 'Mr. Parser');
$character->addChild('actor', 'John Doe');

$rating = $movies->movie[0]->addChild('rating', 'PG');
$rating->addAttribute('type', 'mpaa');

echo
$movies->asXML();
?>

以上示例将输出

<?xml version="1.0" standalone="yes"?>
<movies>
 <movie>
  <title>PHP: Behind the Parser</title>
  <characters>
   <character>
    <name>Ms. Coder</name>
    <actor>Onlivia Actora</actor>
   </character>
   <character>
    <name>Mr. Coder</name>
    <actor>El Act&#xD3;r</actor>
   </character>
  <character><name>Mr. Parser</name><actor>John Doe</actor></character></characters>
  <plot>
   So, this language. It's like, a programming language. Or is it a
   scripting language? All is revealed in this thrilling horror spoof
   of a documentary.
  </plot>
  <great-lines>
   <line>PHP solves all my web problems</line>
  </great-lines>
  <rating type="thumbs">7</rating>
  <rating type="stars">5</rating>
 <rating type="mpaa">PG</rating></movie>
</movies>

示例 #11 DOM 互操作性

PHP 有一种机制可以在 SimpleXML 和 DOM 格式之间转换 XML 节点。此示例演示如何将 DOM 元素更改为 SimpleXML。

<?php
$dom
= new DOMDocument;
$dom->loadXML('<books><book><title>blah</title></book></books>');
if (!
$dom) {
echo
'解析文档时出错';
exit;
}

$books = simplexml_import_dom($dom);

echo
$books->book[0]->title;
?>

以上示例将输出

blah

添加注释

用户贡献的注释 9 条注释

85
rowan dot collins at gmail dot com
9 年前
有一种常见的“技巧”,通常建议通过运行 json_encode() 然后 json_decode() 来将 SimpleXML 对象转换为数组。我想解释一下为什么这是一个坏主意。

最简单地说,因为 SimpleXML 的全部意义在于比普通数组更容易使用且功能更强大。例如,您可以编写 <?php $foo->bar->baz['bing'] ?>,它的含义与 <?php $foo->bar[0]->baz[0]['bing'] ?> 相同,无论 XML 中有多少个 bar 或 baz 元素;如果您编写 <?php (string)$foo->bar[0]->baz[0] ?>,您将获得该节点的所有字符串内容 - 包括 CDATA 部分 - 无论它是否还有子元素或属性。您还可以访问命名空间信息、能够对 XML 进行简单的编辑,甚至能够“导入”到 DOM 对象中,以进行更强大的操作。通过将对象转换为数组而不是阅读理解此页面上的示例,所有这些都将丢失。

此外,由于它不是为此目的而设计的,因此转换为 JSON 并返回实际上会在某些情况下丢失信息。例如,命名空间中的任何元素或属性都将被简单地丢弃,并且如果元素还有子元素或属性,则任何文本内容都将被丢弃。有时,这无关紧要,但如果您养成将所有内容都转换为数组的习惯,最终它会让您感到痛苦。

当然,您可以编写更智能的转换,它没有这些限制,但在这一点上,您根本无法从 SimpleXML 中获得任何价值,并且应该只使用更低级的 XML 解析器函数或 XMLReader 类来创建您的结构。您仍然不会拥有 SimpleXML 的额外便利功能,但那是您的损失。
66
jishcem at gmail dot com
11 年前
对我来说,使用数组比使用对象更容易,

所以,我使用了这段代码,

$xml = simplexml_load_file('xml_file.xml');

$json_string = json_encode($xml);

$result_array = json_decode($json_string, TRUE);

希望它能帮助到某人
9
匿名
7 年前
如果您的 xml 字符串包含使用“0”和“1”编码的布尔值,则在将元素直接转换为 bool 时会遇到问题

$xmlstr = <<<XML
<?xml version='1.0' standalone='yes'?>
<values>
<truevalue>1</truevalue>
<falsevalue>0</falsevalue>
</values>
XML;
$values = new SimpleXMLElement($xmlstr);
$truevalue = (bool)$values->truevalue; // true
$falsevalue = (bool)$values->falsevalue; // 也是 true!!!

相反,您需要首先转换为字符串或整数

$truevalue = (bool)(int)$values->truevalue; // true
$falsevalue = (bool)(int)$values->falsevalue; // false
2
Josef
3 年前
如何确定节点是否存在

<?xml version='1.0' standalone='yes'?>
<book>
<author>Josef</author>
<isbn></isbn>
</book>

empty($xml->isbn) 将为 true
isset($xml->isbn) 将为 true

empty($xml->title) 将为 true
isset($xml->title) 将为 false
17
ie dot raymond at gmail dot com
14 年前
如果需要在响应中输出有效的 xml,请不要忘记在输出 asXML() 的结果之外将您的标头内容类型设置为 xml

<?php

$xml
=simplexml_load_file('...');
...
...
xml 内容
...

//在您的响应中输出 xml:
header('Content-Type: text/xml');
echo
$xml->asXML();
?>
10
gkokmdam at zonnet dot nl
13 年前
关于 xpath 查询和默认命名空间的一个快速提示。看起来 SimpleXML 背后的 XML 系统与我相信 .NET 使用的 XML 系统的工作原理相同:当需要处理默认命名空间中的某些内容时,必须使用 registerXPathNamespace 声明命名空间,然后使用其前缀来处理否则位于默认命名空间中的元素。

<?php
$string
= <<<XML
<?xml version='1.0'?>
<document xmlns="http://www.w3.org/2005/Atom">
<title>Forty What?</title>
<from>Joe</from>
<to>Jane</to>
<body>
我知道那是答案——但问题是什么?
</body>
</document>
XML;

$xml = simplexml_load_string($string);
$xml->registerXPathNamespace("def", "http://www.w3.org/2005/Atom");

$nodes = $xml->xpath("//def:document/def:title");

?>
8
kdos
13 年前
使用类似:is_object($xml->module->admin) 来检查是否存在名为“admin”的节点,似乎无法按预期工作,因为 SimpleXML 始终返回一个对象——在这种情况下为空对象——即使特定节点不存在。
对我来说,传统的 empty() 函数在这种情况下似乎工作得很好。

干杯
5
Max K.
14 年前
来自 README 文件

SimpleXML 旨在成为一种访问 XML 数据的简单方法。

SimpleXML 对象遵循四个基本规则

1) 属性表示元素迭代器
2) 数字索引表示元素
3) 非数字索引表示属性
4) 字符串转换允许访问文本数据

当迭代属性时,扩展始终迭代
所有具有该元素名称的节点。因此必须调用 children() 方法
以迭代子节点。但也可以执行以下操作
foreach ($obj->node_name as $elem) {
// 对 $elem 执行某些操作
}
始终导致迭代“node_name”元素。因此无需进一步
检查以区分该类型节点的数量。

当通过属性访问元素的文本数据时
则结果不包括子元素的文本数据。

已知问题
============

由于引擎问题,目前无法访问
索引为 0 的子元素:$object->property[0]。
-1
php at keith tyler dot com
14 年前
[编辑注:但是,SimpleXMLIterator 类确实实现了这些方法。]

虽然 SimpleXMLElement 声称是可迭代的,但它似乎没有正确实现标准的 Iterator 接口函数,如 ::next 和 ::reset。因此,虽然 foreach() 可以工作,但 next()、current() 或 each() 等函数似乎无法按预期工作——指针似乎从未移动或一直被重置。
To Top