Article
Instant XML with PHP and PEAR::XML_Serializer
Here's the reverse of the first example:
<?php
// Set error reporting to ignore notices
error_reporting(E_ALL ^ E_NOTICE);
// Include XML_Unserializer
require_once 'XML/Unserializer.php';
// The XML document
$doc = <<<EOD
<?xml version="1.0" encoding="ISO-8859-1"?>
<palette>
<color>red</color>
<color>green</color>
<color>blue</color>
</palette>
EOD;
// Instantiate the serializer
$Unserializer = &new XML_Unserializer();
// Serialize the data structure
$status = $Unserializer->unserialize($doc);
// Check whether serialization worked
if (PEAR::isError($status)) {
die($status->getMessage());
}
// Display the PHP data structure
echo '<pre>';
print_r($Unserializer->getUnserializedData());
echo '</pre>';
?>
Filename: upalette1.php
The resulting data structure looks like this:
Array
(
[color] => Array
(
[0] => red
[1] => green
[2] => blue
)
)
You see here the need for caution when working with XML_Serializer -- the original PHP data structure was as follows:
$palette = array('red', 'green', 'blue');
If you want to make sure you get back exactly the data structure you started with when dealing with indexed arrays, you need to switch 'typeHints' on when serializing them to XML.
Moving onto the second example, the code is essentially the same:
// Set error reporting to ignore notices
error_reporting(E_ALL ^ E_NOTICE);
// Include XML_Unserializer
require_once 'XML/Unserializer.php';
// The XML document
$doc = <<<EOD
<?xml version="1.0" encoding="ISO-8859-1"?>
<palette>
<red>45</red>
<green>240</green>
<blue>120</blue>
</palette>
EOD;
// Instantiate the serializer
$Unserializer = &new XML_Unserializer();
// Serialize the data structure
$status = $Unserializer->unserialize($doc);
// Check whether serialization worked
if (PEAR::isError($status)) {
die($status->getMessage());
}
// Display the PHP data structure
echo '<pre>';
print_r($Unserializer->getUnserializedData());
echo '</pre>';
?>
Filename: upalette2.php
The resulting PHP data structure is now:
Array
(
[red] => 45
[green] => 240
[blue] => 120
)
This time, it matches the original data structure, which also used an associative array (but note that the values of the array will be of type 'string', not of type 'integer'):
$palette = array(
'red' => 45,
'green' => 240,
'blue' => 120
);
The third example requires that I tell the unserializer to parse attributes:
<?php
// Set error reporting to ignore notices
error_reporting(E_ALL ^ E_NOTICE);
// Include XML_Unserializer
require_once 'XML/Unserializer.php';
// The XML document
$doc = <<<EOD
<?xml version="1.0" encoding="ISO-8859-1"?>
<palette blue="120" green="240" red="45" />
EOD;
// Array of options
$unserializer_options = array (
'parseAttributes' => TRUE
);
// Instantiate the serializer
$Unserializer = &new XML_Unserializer($unserializer_options);
// Serialize the data structure
$status = $Unserializer->unserialize($doc);
// Check whether serialization worked
if (PEAR::isError($status)) {
die($status->getMessage());
}
// Display the PHP data structure
echo '<pre>';
print_r($Unserializer->getUnserializedData());
echo '</pre>';
?>
The resulting PHP data structure is again more or less what I started with, although integers are now strings:
Array
(
[blue] => 120
[green] => 240
[red] => 45
)
Finally, when I unserialize the document containing type hints, I need to make sure the class ColorInformation is defined. In the original example, ColorInformation class used the constructor to pass external variables into its fields. Like PHP's unserialize() function, XML_Unserializer doesn't provide a mechanism for calling class methods when unserializing objects; rather, it sets the properties of an object directly (so, be careful):
<?php
// Set error reporting to ignore notices
error_reporting(E_ALL ^ E_NOTICE);
// Include XML_Unserializer
require_once 'XML/Unserializer.php';
// A class to store color information
class ColorInformation {
var $hue;
var $value;
function ColorInformation($hue = NULL, $value = NULL) {
$this->hue = $hue;
$this->value = $value;
}
}
// The XML document
$doc = <<<EOD
<?xml version="1.0" encoding="ISO-8859-1"?>
<palette _type="array">
<color _class="colorinformation"
_originalKey="0"
_type="object">
<hue _type="string">red</hue>
<value _type="integer">45</value>
</color>
<color _class="colorinformation"
_originalKey="1"
_type="object">
<hue _type="string">green</hue>
<value _type="integer">240</value>
</color>
<color _class="colorinformation"
_originalKey="2"
_type="object">
<hue _type="string">blue</hue>
<value _type="integer">120</value>
</color>
</palette>
EOD;
// Instantiate the serializer
$Unserializer = &new XML_Unserializer();
// Serialize the data structure
$status = $Unserializer->unserialize($doc);
// Check whether serialization worked
if (PEAR::isError($status)) {
die($status->getMessage());
}
// Display the PHP data structure
echo '<pre>';
print_r($Unserializer->getUnserializedData());
echo '</pre>';
?>
The resulting data structure is:
Array
(
[0] => colorinformation Object
(
[hue] => red
[value] => 45
)
[1] => colorinformation Object
(
[hue] => green
[value] => 240
)
[2] => colorinformation Object
(
[hue] => blue
[value] => 120
)
)
This matches the original data structure, ignoring the issue with the constructor:
$palette = array();
$palette[] = &new ColorInformation('red', 45);
$palette[] = &new ColorInformation('green', 240);
$palette[] = &new ColorInformation('blue', 120);
Notes on Serializing Objects:
As with PHP's in-built serialize() and unserialize() functions, when PEAR::XML_Serializer transforms to XML and back, it will attempt to call the __sleep() and __wakeup() functions on those objects, if they have been defined. This gives you a chance to perform operations, such as connecting or disconnecting from a database, by defining them within these methods. See the PHP manual on __sleep() and __wakeup() for more details.
When objects are unserialized by XML_Unserializer, it first attempts to re-build them using the original class, but to do so your code must make sure the class is available. If it fails to find the class definition, assuming you're using PHP4, it will use PHP's built-in stdClass definition instead. Last time I looked, PHP5 had dropped support for stdClass, so it remains to be seen what will happen in such instances.
Currently XML_Serializer has no way to represent objects that contain references to each other. The TODO list that comes with the package indicates support is planned in the near future.