PHP Conference Japan 2024

SimpleXMLIterator 類別

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

簡介

SimpleXMLIterator 提供對 SimpleXMLElement 物件所有節點的遞迴迭代。

類別概要

class SimpleXMLIterator extends SimpleXMLElement {
/* 繼承的方法 */
public SimpleXMLElement::__construct(
    字串 $data,
    整數 (int) $options = 0,
    布林值 (bool) $dataIsURL = false (假),
    字串 (string) $namespaceOrPrefix = "",
    布林值 (bool) $isPrefix = 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>灰色</color>
<color>白色</color>
</cat>
<cat>
<name>Maxwell</name>
<age>12</age>
<color>橘色</color>
<color>黑色</color>
</cat>
</cats>
======================================

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

函式
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);
?>

結果 (為了簡潔和清晰,重新排版過)
======================================
陣列(
[cat] => 陣列(
[0] => 陣列(
[name] => 陣列( [0] => Jack )
[age] => 陣列( [0] => 2 )
[color] => 陣列( [0] => 灰色,
[1] => 白色 )
)
[1] => 陣列(
[name] => 陣列( [0] => Maxwell )
[age] => 陣列( [0] => 12 )
[color] => 陣列( [0] => 橘色
[1] => 黑色 )
)
)
)
hezll at msn dot com
11 年前
大多數時候,我們需要將 XML 轉換為陣列或 JSON,但現在我必須完成將 XML 轉換為 XPath 的需求,這使得我們的模板由於 Xpath 映射而更容易從 XML 資料來源獲取資料。以下是函式

<?php

function sxiToXpath($sxi, $key = null, &$tmp = null)
{
$keys_arr = array();
//get the keys count 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;
}
}
//create the 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);
}

/**
* How to use the function
*/
$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);

/**
* the results may lkie this:
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 "Total:" . count($rs);

echo
"<hr>";
/* You can check the xpath result like this */
$xml = new SimpleXMLElement($xml);
foreach (
$rs as $k => $v)
{
echo
"Xpath:" . $k . " |Value:" . $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 .= $mydata->current()->children()->attributes()['size']."'),";
} else {
$myquery .= "'),";
}
}
$myquery = rtrim($myquery, ",");
$datatosql = mysql_query($myquery);
?>
rukkykf at gmail dot com
5 年前
我想值得一提的是,您需要在初始化 SimpleXMLIterator 物件後立即呼叫 rewind() 方法,才能開始對該物件執行任何其他操作。一個例子

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

// $x 此時會被設為 null,因為尚未呼叫 rewind() 方法
$x = $xml->current();

$xml->rewind();

// $x 此時會被設為第一個元素
$x = $xml->current();

?>
php-lover at live dot com
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;
}
prouchetvincent at free dot fr
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
並且需要取得此迭代器標籤的屬性,則
請在
->attributes()->{屬性名稱}
之前,於您的物件上使用 simpleXMLIterator 的
->current() 函式
<?php
$file
="";
try{
$index = new SimpleXMLIterator ( file_get_contents ( FILEDIRECTORY. 'index.xml' ) );}
catch(
Exception $e) {whatever you want to do on error}}

for(
$index->rewind(); $index->valid(); $index->next() ) {
try {
$file = file_get_contents(FILESDIRECTORY.$index->current()->attributes()->{'fileName'}. '.xml' );
} catch (
Exception $e) {whatever you want to do on error}
$article = new Article ();
$article->setXMLArticle ($file);
array_push( $this->articles, $article );
$file ="";
}
}
?>
這個例子使用了一個自訂的 Article 物件,它會解析傳入的檔案來初始化其屬性。
這裡我們打開一個檔案(是的,我使用常數來表示我的目錄)
將其轉換為 SimpleXMLIterator 並解析文章元素以取得 fileName 屬性,用它來打開另一個 XML 檔案以收集資料。
別忘了!!!在 PHP 中,使用 new ClassName() 建立的物件「永遠」是傳遞 by reference 的,這就是為什麼 new Article() 要放在迴圈內部而不是外部的原因
(是的,我犯了那個錯誤)
XMLIterator 功能強大,但本身難以理解,但一旦過了那個點…
它們比普通的陣列更容易使用。
ajnsit dot NOSPAM at gmail dot com
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
函式 parse($str) {
返回
parseHelper(new SimpleXmlIterator($str, null));
}
函式
parseHelper($iter) {
foreach(
$iter as $key=>$val)
$arr[$key][] = ($iter->hasChildren())?
call_user_func (__FUNCTION__, $val)
:
strval($val);
返回
$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