|
|
CVIII. SimpleXML関数警告 | このモジュールは、
実験的なものです。これは、これらの関数の動作、関
数名は、このドキュメントに書かれて事項と同様に告知なく将来的なPHPのリ
リースで変更される可能性があります。注意を喚起するとともに、このモジュー
ルは使用者のリスクで使用して下さい。 |
SimpleXML拡張モジュールは、
XMLをオブジェクトにとても簡単かつ容易に変換するための機能を
提供します。変換後のオブジェクトでは、
通常のプロパティセレクタや配列反復子を用いて処理を行うことが
可能です。
この拡張モジュールは、PHPの configure に
--enable-simplexml を
指定して実行された場合のみ利用可能です。PHPのconfigureスクリプト
はデフォルトでこれを行います。
このリファレンスの多くの例ではXML文字列を必要とします。各例で
この文字列をくり返す代わりに、あるファイルにこの文字列を保存して、
各例で読みこむことにします。この読みこまれるファイルは、以下の例
に関するセクションで使用されます。
もしくは、XMLドキュメントを作成し、
simplexml_load_file() により読みこむことも
可能です。
例 1. XML文字列を設定するインクルードファイル example.php
<?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Ó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>
<rating type="thumbs">7</rating>
<rating type="stars">5</rating>
</movie>
</movies>
XML;?>
|
|
SimpleXMLの容易さが最も明確に現われるのは、
簡単なXMLドキュメントから文字列または数字を展開する時です。
例 2. <plot> を取得する
<?php
include 'example.php';
$xml = simplexml_load_string($xmlstr);
echo $xml->movie[0]->plot; ?>
|
|
例 3. SimpleXMLでユニークでない要素にアクセスする
単一の親要素の子要素としてある要素のインスタンスが複数存在する時、
通常の反復処理を適用することができます。
<?php
include 'example.php';
$xml = simplexml_load_string($xmlstr);
foreach ($xml->movie as $movie) {
echo $movie->plot, '<br />';
}
?>
|
|
例 4. 属性を使用する
ここまでは、要素の名前と値を読む方法のみを扱って来ました。
SimpleXMLは要素の属性にアクセスすることも可能です。
要素の属性にアクセスする方法は、配列 の要素に
アクセスするのと全く同じです。
<?php
include 'example.php';
$xml = simplexml_load_string($xmlstr);
foreach ($xml->movie[0]->rating as $rating) {
switch((string) $rating['type']) { case 'thumbs':
echo $rating, ' thumbs up';
break;
case 'stars':
echo $rating, ' stars';
break;
}
}
?>
|
|
例 5. 要素および属性をテキストと比較する
要素または属性を文字列と比較する、もしくは、文字列を引数とする関数に
渡すには、(string) により文字列にキャストする
必要があります。さもないと、PHPはこの要素をオブジェクトとして扱います。
<?php
include 'example.php';
$xml = simplexml_load_string($xmlstr);
if ((string) $xml->movie->title == 'PHP: Behind the Parser') {
print 'My favorite movie.';
}
htmlentities((string) $xml->movie->title);
?>
|
|
例 6. Xpathの使用
SimpleXMLには、Xpathをサポートしています。
<character> 要素を全て見つけるには、
以下のようにします。
<?php
include 'example.php';
$xml = simplexml_load_string($xmlstr);
foreach ($xml->xpath('//character') as $character) {
echo $character->name, 'played by ', $character->actor, '<br />';
}
?>
|
'//' はワイルドカードとして動作します。絶対パスを指定するには、
スラッシュを一つだけにします。
|
例 7. 値を設定する
SimpleXMLの中のデータは、定数とすることができません。
オブジェクトは、その全ての要素について変更が可能です。
<?php
include 'example.php';
$xml = simplexml_load_string($xmlstr);
$xml->movie[0]->actor[0]->age = '21';
echo $xml->asXML();
?>
|
上のコードは、元のXMLドキュメントと全く同じXMLドキュメントを新規に
出力しますが、新しいXMLファイルでは、Ms. Coderの年齢が21と定義されている
ところが異なります。
|
例 8. DOMとの相互運用性
PHPは、SimpleXML形式とDOM形式の間でXMLノードを変換する機構を有しています。
この例では、DOM要素をSimpleXMLに変換することができます。
<?php
$dom = new domDocument;
$dom->loadXML('<books><book><title>blah</title></book></books>');
if (!$dom) {
echo 'Error while parsing the document';
exit;
}
$s = simplexml_import_dom($dom);
echo $s->book[0]->title;
?>
|
|
nelson_menezes at yahoo dot co dot uk
01-Mar-2005 01:05
Note that SimpleXML expects to both read and output XML in UTF-8 encoding. You'll need to add a line such as this at the top of your input XML file if it isn't saved in UTF-8 (adjust to whatever encoding used):
<?xml version="1.0" encoding="ISO-8859-1" ?>
On the output side of things, if you're not serving/handling UTF-8, you'll need to use utf8_decode(). Common mistake:
webmarks
14-Feb-2005 05:57
I'm new to PHP and XML, but I think others might pull their hair out over this too. I forgot about XML and whitespace when I was populating an array with node values, and was getting what appeared to be duplicate values despite using array_unique(). Use trim() when populating an array or assigning a variable.
<?php
$xml_array = array();
foreach ($resource->xpath($node_match) as $option){
$xml_array[$i] = trim($option);
$i++;
}
$xml_unique_array = array_unique($xml_array);
?>
roland dot swingler at transversal dot com
08-Feb-2005 10:24
Just a quick note - if you wish to get the name of the tag you are operating on, use the the key bit of foreach, i.e in the example:
<?php
foreach($xml->movie[0]->children() as $tag => $child){
echo $tag;
}
?>
This might seem obvious but it stumped me for a bit.
yannis dot haralambous at enst-bretagne dot fr
29-Jan-2005 08:44
Sometimes tag names do not respect PHP variable name syntax. For example I have a file like this:
<livre>
<�ditorial>
<�dition-originale ref="123">
bla bla bla
</�dition-originale>
</�ditorial>
</livre>
It's a perfectly valid XML file, but
$livre->�ditorial[0]->�dition-originale[0]->attributes()
will not work because of the hyphen.
The only solution I found is to write:
$livre->�ditorial[0]->{"�dition-originale"}[0]->attributes()
$livre->xpath("/livre/�ditorial/�dition-originale/@ref") doesn't work either but for that one I don't know how to solve the problem...
Daniel FAIVRE - geomaticien.com
14-Jan-2005 11:46
I've searched a while for a convenient "to array" function, and finally wrote it. These one provide at least 5 cool features:
- the MOST IMPORTANT: return a correct structure when several childs nodes have the same name: nodes are numbered properly
- read CDATA values
- returned array is very easy-to-use
- attributes returned in sub-arrays with key [@]
- very fast
When you create a "xml2array" function, you need to manage nodes with attributes, but without children: i've choosed to ignore their attributes to avoid a "virtual ['value'] node" for such nodes in the returned array.
<?php
function simplexml2array($xml) {
if (get_class($xml) == 'SimpleXMLElement') {
$attributes = $xml->attributes();
foreach($attributes as $k=>$v) {
if ($v) $a[$k] = (string) $v;
}
$x = $xml;
$xml = get_object_vars($xml);
}
if (is_array($xml)) {
if (count($xml) == 0) return (string) $x; foreach($xml as $key=>$value) {
$r[$key] = simplexml2array($value);
}
if (isset($a)) $r['@'] = $a; return $r;
}
return (string) $xml;
}
?>
igor kraus
07-Jan-2005 06:37
A simple way to merge two SimpleXML objects.
<?php
function simplexml_merge (SimpleXMLElement &$xml1, SimpleXMLElement $xml2)
{
$dom1 = new DomDocument();
$dom2 = new DomDocument();
$dom1->loadXML($xml1->asXML());
$dom2->loadXML($xml2->asXML());
$xpath = new domXPath($dom2);
$xpathQuery = $xpath->query('/*/*');
for ($i = 0; $i < $xpathQuery->length; $i++)
{
$dom1->documentElement->appendChild(
$dom1->importNode($xpathQuery->item($i), true));
}
$xml1 = simplexml_import_dom($dom1);
}
$xml1 = simplexml_load_string('<root><child>child 1</child></root>');
$xml2 = simplexml_load_string('<root><child>child 2</child></root>');
simplexml_merge($xml1, $xml2);
echo($xml1->asXml());
?>
Will output:
<?xml version="1.0"?>
<root>
<child>child 1</child>
<child>child 2</child>
</root>
brcavanagh AT NO SPAM hotmail.com
03-Jan-2005 05:18
If you are looking to use SimpleXML for anything but reading XML documents, you should really reconsider, and use the XML DOM library. By the time you get enough utilities implemented in DOM to handle all the set backs in SimpleXML, you will have defeated the purpose of using SimpleXML. There are a few reasons for this, and there are already many workrounds, but the primairy issues are this
1) No complex node assignment. You cannot switch nodes or replace them.
2) No appending new child nodes
3) Whenever you do something like $new_node = $xml_doc->node you will always get a reference even if you use a clone method, which will crash the script.
Other than that, its a great tool for reading docs.
aidan at php dot net
24-Dec-2004 08:42
SimpleXML does support namespaces, however their use is not as "simple".
This article explains much about SimpleXML, the limitations and problems in supporting namespaces, and possible solutions.
aidan at php dot net
22-Dec-2004 07:20
SimpleXML doesn't allow the creation of new elements (nodes). However, we can use DOM as an intermediary.
This function allows you to add elements with SimpleXML:
lajos dot arpasi at maxxlogic dot hu
08-Oct-2004 12:31
If you use PHP4 and miss the features of SimpleXML try MiniXML ().
MiniXML is a PHP class library for generating and parsing XML.
MiniXML have similar abilities like creating XML files from Arrays and importing XML files into Arrays.
You can manipulate the XML files more easily than SimpleXML.
It saved my life:).
majkqball_gmail_com
25-Sep-2004 10:44
Converting SimpleXML objects to an array:
<?php
$sx = simplexml_load_string('your xml string here');
function recursive_obj2array($obj, &$subject_array=array()) {
foreach ((array) $obj as $key => $var) {
if (is_object($var)) {
if(count((array) $var) == 0) {
$subject_array[$key] = 'NULL';
}
else {
recursive_obj2array($var, $subject_array[$key]);
}
}
else {
$subject_array[$key] = $var;
}
}
}
$gimmie = array();
recursive_obj2array($sx, $gimmie);
?>
Then $gimmie is foreach friendly.
Quick and dirty, but rather effective.
farzan ath ifarzan dod com
25-Sep-2004 10:38
You can access XML elements in a SimpleXML object using variables:
<?
$xml = simplexml_loaf_file(...);
print $xml->$element;
?>
or use functions:
<?
print $xml->{getLanguage()};
?>
Note: You Must use { and } or PHP would think you are calling a member function.
You can use members of other objects as well:
<?
print $xml->{$obj->var};
?>
As a real life example; I have used this statement in one of my projects:
<?
$x = $xrules->listing->fieldtitles->$lang->{$obj->name}->title;
?>
As you see, using varialbes and functions as element names are posible in SimpleXML; Thanks to PHP5's object orientaion new features.
jam from Russia
24-Sep-2004 03:23
Example:
<?xml version="1.0"?>
<root status="ok">
<login status="logining"/>
<user:name xmlns:user="">jam</user:name>
</root>
You can get value from "user:name" element:
$user_name = $xml->xpath('/root/user:name');
You can get value from "status" attribute "root" element:
$status = $xml->xpath('/root/@status');
You can get value from "status" attribute "login" element:
$logined = $xml->xpath('/root/login/@status');
SimpleXML work with namespace :-)
cellog at php dot net
31-Aug-2004 11:11
simplexml does not simply handle CDATA sections in a foreach loop.
<?php
$sx = simplexml_load_string('
<test>
<one>hi</one>
<two><![CDATA[stuff]]></two>
<t>
<for>two</for>
</t>
<multi>one</multi>
<multi>two</multi>
</test>');
foreach((array) $sx as $tagname => $val) {
if (is_string($val)) {
} elseif (is_array($val)) {
} elseif (is_object($val)) {
}
}
?>
To test in the loop, do this
<?php
if (count((array) $val) == 0) {
$val = '' . $val;
}
?>
bb at nospam xnull dot de
20-Jul-2004 10:39
the simplexml_to_array function below has a bug, if there are 2 or more fields, it get's bit out of control, here is the right one:
<?
function simplexml_to_array($xml) {
$ar = array();
foreach($xml->children() as $k => $v) {
$child = simplexml_to_array($v);
if( count($child) == 0 ) {
$child = (string)$v;
}
foreach( $v->attributes() as $ak => $av ) {
if( !is_array( $child ) ) {
$child = array( "value" => $child );
}
$child[$ak] = (string)$av;
}
if (!in_array($k,array_keys($ar))) {
$ar[$k] = $child;
} elseif (@in_array(0,@array_keys($ar[$k]))) {
$ar[$k][] = $child;
} else {
$ar[$k] = array($ar[$k]);
$ar[$k][] = $child;
}
}
return $ar;
}
?>
rishad at kaluma dot com
01-Jul-2004 04:12
To test whether a child node exists I used the following code:
<?php
function child_exists($xml, $childpath)
{
$result = $xml->xpath($childpath);
if (count($result)) {
return true;
} else {
return false;
}
}
?>
philip
17-Jun-2004 10:58
A introductory tutorial on simplexml can be found here:
*
*
*
greg dot steffensen at spamless dot richmond dot edu
19-Feb-2004 11:04
Simplexml's simplicity can be deceptive. Simplexml elements behave either as objects or strings, depending on the context in which they're used (through overloading of the __toString() method, I assume). Statements implying conversion to string treat them as strings, while assignment operations treat them as objects. This can lead to unexpected behavior if, for example, you are trying to compare the values of two Simplexml elements. The expected syntax will not work. To force conversion to strings, just "typecast' whatever Simplexml element you're using. For example:
<?php
$s = simplexml_load_string('<foo>43</foo> <bar>43</bar>');
($s->foo == $s->bar);
((string)$s->foo == (string)$s->bar);
?>
[Ed. Note: Changed from quotes to casts because casts provide a quicker and more explicit conversion than do double quotes.]
| |