PHP Conference Japan 2024

SimpleXMLIterator 类

(PHP 5 >= 5.1.3, PHP 7, PHP 8)

简介

SimpleXMLIterator 提供对 SimpleXMLElement 对象所有节点的递归迭代。

类概要

class SimpleXMLIterator extends SimpleXMLElement {
/* 继承的方法 */
public SimpleXMLElement::__construct(
    string $data,
    int $options = 0,
    bool $dataIsURL = false,
    string $namespaceOrPrefix = "",
    bool $isPrefix = false
)
public SimpleXMLElement::addAttribute(string $qualifiedName, string $value, ?string $namespace = null): void
public SimpleXMLElement::addChild(string $qualifiedName, ?string $value = null, ?string $namespace = null): ?SimpleXMLElement
public SimpleXMLElement::attributes(?string $namespaceOrPrefix = null, bool $isPrefix = false): ?SimpleXMLElement
public SimpleXMLElement::children(?string $namespaceOrPrefix = null, bool $isPrefix = false): ?SimpleXMLElement
public SimpleXMLElement::getDocNamespaces(bool $recursive = false, bool $fromRoot = true): array|false
}

变更日志

版本 描述
8.0.0 迭代器方法(SimpleXMLIterator::hasChildren()SimpleXMLIterator::getChildren()SimpleXMLIterator::current()SimpleXMLIterator::key()SimpleXMLIterator::next()SimpleXMLIterator::rewind()SimpleXMLIterator::valid())已移至 SimpleXMLElement
8.0.0 现在,SimpleXMLIterator实现了Stringable接口。
添加注释

用户贡献的注释 7 条注释

ratfactor at gmail dot com
15 年前
SimpleXmlIterator 的文档有点简略。以下是一个示例,展示了其方法的使用。xml2Array 和 sxiToArray 协同工作,将 XML 文档转换为关联数组结构。

cats.xml 的内容
======================================
<cats>
<cat>
<name>Jack</name>
<age>2</age>
<color>grey</color>
<color>white</color>
</cat>
<cat>
<name>Maxwell</name>
<age>12</age>
<color>orange</color>
<color>black</color>
</cat>
</cats>
======================================

<?php
function xml2array($fname){
$sxi = new SimpleXmlIterator($fname, null, true);
return
sxiToArray($sxi);
}

function
sxiToArray($sxi){
$a = array();
for(
$sxi->rewind(); $sxi->valid(); $sxi->next() ) {
if(!
array_key_exists($sxi->key(), $a)){
$a[$sxi->key()] = array();
}
if(
$sxi->hasChildren()){
$a[$sxi->key()][] = sxiToArray($sxi->current());
}
else{
$a[$sxi->key()][] = strval($sxi->current());
}
}
return
$a;
}

// 读取 cats.xml 并打印结果:
$catArray = xml2array('cats.xml');
print_r($catArray);
?>

结果(为了简洁和清晰,重新格式化了一下)
======================================
Array(
[cat] => Array(
[0] => Array(
[name] => Array( [0] => Jack )
[age] => Array( [0] => 2 )
[color] => Array( [0] => grey,
[1] => white )
)
[1] => Array(
[name] => Array( [0] => Maxwell )
[age] => Array( [0] => 12 )
[color] => Array( [0] => orange
[1] => black )
)
)
)
hezll at msn dot com
11 年前
大多数情况下,我们需要将 XML 转换为数组或 JSON,但我现在必须完成将 XML 转换为 XPath 的需求,这使得我们的模板能够轻松地从 XML 数据源获取数据,因为使用了 XPath 映射。这是该函数:

<?php

function sxiToXpath($sxi, $key = null, &$tmp = null)
{
$keys_arr = array();
// 获取键计数数组
for ($sxi->rewind(); $sxi->valid(); $sxi->next())
{
$sk = $sxi->key();
if (
array_key_exists($sk, $keys_arr))
{
$keys_arr[$sk]+=1;
$keys_arr[$sk] = $keys_arr[$sk];
}
else
{
$keys_arr[$sk] = 1;
}
}
// 创建 XPath
for ($sxi->rewind(); $sxi->valid(); $sxi->next())
{
$sk = $sxi->key();
if (!isset($
$sk))
{
$
$sk = 1;
}
if (
$keys_arr[$sk] >= 1)
{
$spk = $sk . '[' . $$sk . ']';
$keys_arr[$sk] = $keys_arr[$sk] - 1;
$
$sk++;
}
else
{
$spk = $sk;
}
$kp = $key ? $key . '/' . $spk : '/' . $sxi->getName() . '/' . $spk;
if (
$sxi->hasChildren())
{
sxiToXpath($sxi->getChildren(), $kp, $tmp);
}
else
{
$tmp[$kp] = strval($sxi->current());
}
$at = $sxi->current()->attributes();
if (
$at)
{
$tmp_kp = $kp;
foreach (
$at as $k => $v)
{
$kp .= '/@' . $k;
$tmp[$kp] = $v;
$kp = $tmp_kp;
}
}
}
return
$tmp;
}

function
xmlToXpath($xml)
{
$sxi = new SimpleXmlIterator($xml);
return
sxiToXpath($sxi);
}

/**
* 如何使用该函数
*/
$xml = <<<EOT
<?xml version="1.0" encoding="utf8" ?>
<data>
<item ID="30001">
<Company>Navarro Corp.</Company>
</item>
<item ID="30002" IDd="30002">
<Company>Performant Systems</Company>
</item>
<item ID="30003">
<Company id='id_test'><g id='id_g'>glove</g></Company>
</item>
<item>
</item>
</data>
EOT;

$rs = xmlToXpath($xml);
print_r($rs);

/**
* 结果可能如下所示:
Array
(
[/data/item[1]/Company[1]] => Navarro Corp.
[/data/item[1]/@ID] => SimpleXMLIterator Object
(
[0] => 30001
)
[/data/item[2]/Company[1]] => Performant Systems
[/data/item[2]/@ID] => SimpleXMLIterator Object
(
[0] => 30002
)

[/data/item[2]/@IDd] => SimpleXMLIterator Object
(
[0] => 30002
)

[/data/item[3]/Company[1]/g[1]] => glove
[/data/item[3]/Company[1]/g[1]/@id] => SimpleXMLIterator Object
(
[0] => id_g
)

[/data/item[3]/Company[1]/@id] => SimpleXMLIterator Object
(
[0] => id_test
)

[/data/item[3]/@ID] => SimpleXMLIterator Object
(
[0] => 30003
)

[/data/item[4]] =>

)
*/

echo "总数: " . count($rs);

echo
"<hr>";
/* 可以像这样检查 XPath 结果 */
$xml = new SimpleXMLElement($xml);
foreach (
$rs as $k => $v)
{
echo
"XPath: " . $k . " |值: " . $v . " ";
var_dump($xml->xpath($k));
echo
"<br>";
}
centy2010 at hotmail dot com
10 年前
我从大约 1260 KB 的 XML 文件中填充了我的数据库。
我将我的处理过程缩短到不到一秒。只需使用 SimpleXML。

我将提供一个填充数据库用法的简单示例。
给定表格 universe。
包含 4 列:Coords、Planet_Name、Player_id、Moon_Size。

现在你有一个名为 universe.xml 的 XML 文件,包含以下数据。
我把数据放在 php 标签内,但这只是一个文件 :p
<?php
$xml
= <<<EOT
<?xml version="1.0" encoding="UTF-8"?>
<universe xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" -
xsi:noNamespaceSchemaLocation="http://s127-fr.ogame.gameforge.com/api/xsd/universe.xsd" -
timestamp="1405413350" serverId="fr127">
<planet id="1" player="1" name="Arakis" coords="1:1:2">
<moon id="2" name="Mond" size="4998"/>
</planet>
<planet id="33620176" player="100000" name="GameAdmin" coords="1:1:3"/>
<planet id="33620179" player="100003" name="Heimatplanet" coords="1:1:1"/>
<planet id="33620186" player="100004" name="OGame Team" coords="6:250:1"/>
<planet id="33620242" player="100058" name="KnS" coords="9:1:6">
<moon id="33668391" name="Lune" size="8831"/>
</planet>
</universe>
EOT;
?>

现在如何将这些数据导入我的 4 列表格中?

<?php
$newfname
= $path."Universe.XML";
$mydata = new SimpleXmlIterator($newfname, 0, true);
$myquery = "INSERT INTO `".$tablename."` (`coords`,`planet_name`, `player_id`, `moon_size`) VALUES ";
for (
$mydata->rewind();$mydata->valid();$mydata->next()) {
$myquery.= " ('".$mydata->current()->attributes()['coords']
_."','".utf8_decode($mydata->current()->attributes()['name'])
_."','".utf8_decode($mydata->current()->attributes()['player'])
_."','";
if (
$mydata->haschildren()) {
$myquery.= $mydate->current()->children()->attributes()['size']."'),";
} else {
$myquery.= "'),";
}
}
$myquery = rtrim($myquery, ",");
$datatosql = mysql_query($myquery);
?>
[email protected]
5年前
我认为值得一提的是,在进行任何其他操作之前,你需要在初始化后立即调用 SimpleXMLIterator 对象上的 rewind() 方法。示例如下:

<?php
$xml
= new SimpleXMLIterator('file.xml', null, true);

// 由于未调用 rewind() 方法,$x 将设置为 null
$x = $xml->current();

$xml->rewind();

// 现在 $x 将设置为第一个元素
$x = $xml->current();

?>
[email protected]
9年前
将 SimpleXMLElement 数据提取到数组的函数。

function extract($sxe = null) {
if (!$sxe instanceof SimpleXMLElement)
return array();

$extract = array();

foreach ($sxe->children() as $key => $value) {
if (array_key_exists($key, $extract)) {
if (!isset($extract[$key][0])) {
$tmp_extract = $extract[$key];
$extract[$key] = array();
$extract[$key][0] = $tmp_extract;
} else
$extract[$key] = (array) $extract[$key];
}

if ($value->count()) {
if (isset($extract[$key]) && is_array($extract[$key]))
$extract[$key][] = $this->extract($value);
else
$extract[$key] = $this->extract($value);
} else {
if (isset($extract[$key]) && is_array($extract[$key]))
$extract[$key][] = empty(strval($value)) ? null : strval($value);
else
$extract[$key] = empty(strval($value)) ? null : strval($value);
}
}

return $extract;
}
[email protected]
4年前
<?php
=======================================================
$index =
<?
xml version="1.0" encoding="UTF-8"?>
<root>
<article id="8" visibility="true" filename="2020-10-08" fileExtension="xml">
<tag>xml</tag>
<tag>php</tag>
<tag>experiment</tag>
</article>
<article id="7" visibility="true" filename="2020-10-07" fileExtension="xml">
<tag>xml</tag>
<tag>php</tag>
<tag>experiment</tag>
</article>
<article id="6" visibility="true" filename="2020-10-02" fileExtension="xml">
<tag>xml</tag>
<tag>php</tag>
<tag>experiment</tag>
</article>
<article id="5" visibility="true" filename="2020-09-30" fileExtension="xml">
<tag>xml</tag>
<tag>php</tag>
<tag>experiment</tag>
</article>
<article id="4" visibility="true" filename="2020-09-26" fileExtension="xml">
<tag>xml</tag>
<tag>php</tag>
<tag>experiment</tag>
</article>
<article id="3" visibility="true" filename="2020-09-22" fileExtension="xml">
<tag>xml</tag>
<tag>php</tag>
<tag>experiment</tag>
</article>
<article id="2" visibility="true" filename="2020-09-20" fileExtension="xml">
<tag>xml</tag>
<tag>php</tag>
<tag>experiment</tag>
</article>
<article id="1" visibility="true" filename="hello world" fileExtension="xml">
Hello World
<tag>xml</tag>
<tag>php</tag>
<tag>experiment</tag>
</article>
</root>
====================================================================
?>
如果你必须使用迭代器来解析你的 XML
并且需要获取此迭代器标签的属性,那么
使用函数
->current()
在你的对象上使用 simpleXMLIterator 之前
->attributes()->{'attibute name'}
<?php
$file
="";
try{
$index = new SimpleXMLIterator ( file_get_contents ( FILEDIRECTORY. 'index.xml' ) );}
catch(
Exception $e) {你需要处理的错误}

for(
$index->rewind(); $index->valid(); $index->next() ) {
try {
$file = file_get_contents(FILESDIRECTORY.$index->current()->attributes()->{'fileName'}. '.xml' );
} catch (
Exception $e) {你需要处理的错误}
$article = new Article ();
$article->setXMLArticle ($file);
array_push( $this->articles, $article );
$file ="";
}
}
?>
此示例使用自定义的 Article 对象,该对象本身会解析给定的文件以初始化其属性。
这里我们打开一个文件(是的,我使用常量表示我的目录)
将其转换为 simpleXMLIterator 并解析 article 元素以获取 filename 属性,以便将其用于打开另一个 XML 文件以进行数据收集。
不要忘记!!!在 PHP 中,由 new ClassName() 创建的对象始终通过引用传递,这就是为什么 new Article() 在循环内部而不是外部的原因。
(是的,我犯过这个错误)
XMLIterator 功能强大,但本身更难理解,但一旦过去了这一点。
它们比普通数组更容易使用。
[email protected]
13年前
这是一个将 XML 字符串转换为数组的简单函数:

<?php
// 仅限 PHP5.3 及更高版本
function parse($str) {
$f = function($iter) {
foreach(
$iter as $key=>$val)
$arr[$key][] = ($iter->hasChildren())?
call_user_func (__FUNCTION__, $val)
:
strval($val);
return
$arr;
};
return
$f(new SimpleXmlIterator($str, null));
}
?>

PHP 5.2 及以下版本不支持匿名函数。
但是您可以创建一个辅助函数来实现相同的功能:

<?php
function parse($str) {
return
parseHelper(new SimpleXmlIterator($str, null));
}
function
parseHelper($iter) {
foreach(
$iter as $key=>$val)
$arr[$key][] = ($iter->hasChildren())?
call_user_func (__FUNCTION__, $val)
:
strval($val);
return
$arr;
}
?>

使用方法很简单:

<?php

$xml
= '
<movies>
<movie>abcd</movie>
<movie>efgh</movie>
<movie>hijk</movie>
</movies>'
;
var_dump(parse($xml));

?>

输出结果为:

数组
'movie' =>
数组
0 => 字符串 'abcd' (长度=4)
1 => 字符串 'efgh' (长度=4)
2 => 字符串 'hijk' (长度=4)
To Top