PHP object as an XML document

What is the best way to take a given PHP object and serialize it as XML? I look at simple_xml and I used it to parse XML in objects, but I don’t understand how it works in a different way.

+45
xml php xml-serialization
Sep 26 '08 at 0:05
source share
10 answers

take a look at the PEAR XML_Serializer package. I used it with good results. You can feed it with arrays, objects, etc., And that will turn them into XML. It also has many options, such as choosing the root name of the node, etc.

Gotta do the trick

+37
Sep 26 '08 at 0:15
source share

I would agree using PEAR XML_Serializer, but if you need something simple that supports objects / arrays with nested properties, you can use this.

class XMLSerializer { // functions adopted from http://www.sean-barton.co.uk/2009/03/turning-an-array-or-object-into-xml-using-php/ public static function generateValidXmlFromObj(stdClass $obj, $node_block='nodes', $node_name='node') { $arr = get_object_vars($obj); return self::generateValidXmlFromArray($arr, $node_block, $node_name); } public static function generateValidXmlFromArray($array, $node_block='nodes', $node_name='node') { $xml = '<?xml version="1.0" encoding="UTF-8" ?>'; $xml .= '<' . $node_block . '>'; $xml .= self::generateXmlFromArray($array, $node_name); $xml .= '</' . $node_block . '>'; return $xml; } private static function generateXmlFromArray($array, $node_name) { $xml = ''; if (is_array($array) || is_object($array)) { foreach ($array as $key=>$value) { if (is_numeric($key)) { $key = $node_name; } $xml .= '<' . $key . '>' . self::generateXmlFromArray($value, $node_name) . '</' . $key . '>'; } } else { $xml = htmlspecialchars($array, ENT_QUOTES); } return $xml; } } 
+46
Feb 03 '10 at 7:21
source share

not quite the answer to the original question, but the way I solved my problem was to declare my object as:

 $root = '<?xml version="1.0" encoding="UTF-8"?><Activities/>'; $object = new simpleXMLElement($root); 

Unlike:

 $object = new stdClass; 

before I started adding any values!

+9
Jan 21 '10 at 9:35 on
source share

Use the dom function for this: http://www.php.net/manual/en/function.dom-import-simplexml.php

Import the SimpleXML object, and then save. The link above is an example. :)

In a nutshell:

 <?php $array = array('hello' => 'world', 'good' => 'morning'); $xml = simplexml_load_string("<?xml version='1.0' encoding='utf-8'?><foo />"); foreach ($array as $k=>$v) { $xml->addChild($k, $v); } ?> 
+5
Sep 26 '08 at 0:10
source share

use WDDX: http://uk.php.net/manual/en/wddx.examples.php

(if this extension is installed)

he is dedicated to this:

http://www.openwddx.org/

+2
Sep 27 '08 at 10:01
source share

take a look at my version

  class XMLSerializer { /** * * The most advanced method of serialization. * * @param mixed $obj => can be an objectm, an array or string. may contain unlimited number of subobjects and subarrays * @param string $wrapper => main wrapper for the xml * @param array (key=>value) $replacements => an array with variable and object name replacements * @param boolean $add_header => whether to add header to the xml string * @param array (key=>value) $header_params => array with additional xml tag params * @param string $node_name => tag name in case of numeric array key */ public static function generateValidXmlFromMixiedObj($obj, $wrapper = null, $replacements=array(), $add_header = true, $header_params=array(), $node_name = 'node') { $xml = ''; if($add_header) $xml .= self::generateHeader($header_params); if($wrapper!=null) $xml .= '<' . $wrapper . '>'; if(is_object($obj)) { $node_block = strtolower(get_class($obj)); if(isset($replacements[$node_block])) $node_block = $replacements[$node_block]; $xml .= '<' . $node_block . '>'; $vars = get_object_vars($obj); if(!empty($vars)) { foreach($vars as $var_id => $var) { if(isset($replacements[$var_id])) $var_id = $replacements[$var_id]; $xml .= '<' . $var_id . '>'; $xml .= self::generateValidXmlFromMixiedObj($var, null, $replacements, false, null, $node_name); $xml .= '</' . $var_id . '>'; } } $xml .= '</' . $node_block . '>'; } else if(is_array($obj)) { foreach($obj as $var_id => $var) { if(!is_object($var)) { if (is_numeric($var_id)) $var_id = $node_name; if(isset($replacements[$var_id])) $var_id = $replacements[$var_id]; $xml .= '<' . $var_id . '>'; } $xml .= self::generateValidXmlFromMixiedObj($var, null, $replacements, false, null, $node_name); if(!is_object($var)) $xml .= '</' . $var_id . '>'; } } else { $xml .= htmlspecialchars($obj, ENT_QUOTES); } if($wrapper!=null) $xml .= '</' . $wrapper . '>'; return $xml; } /** * * xml header generator * @param array $params */ public static function generateHeader($params = array()) { $basic_params = array('version' => '1.0', 'encoding' => 'UTF-8'); if(!empty($params)) $basic_params = array_merge($basic_params,$params); $header = '<?xml'; foreach($basic_params as $k=>$v) { $header .= ' '.$k.'='.$v; } $header .= ' ?>'; return $header; } } 
+1
Apr 04 '13 at
source share

I know this is an old question, but lately I had to create complex XML structures.

My approach contains OOP best practices. The idea is to serialize a parent that contains several children and children.

Nodes get names from class names, but you can override the class name with the first parameter when creating an object for serialization.

You can create: a simple node, without child nodes, EntityList and ArrayList. EntityList is a list of objects of one class, but an ArrayList can have different objects.

Each object must extend the abstract class SerializeXmlAbstract to match the first input parameter in the class: Object2xml, method serialize($object, $name = NULL, $prefix = FALSE) .

By default, if you did not specify the second parameter, the root XML node will have the class name for this object. The third parameter indicates whether the root node has a prefix name or not. The prefix is ​​hard-coded as a private property in the Export2xml class.

 interface SerializeXml { public function hasAttributes(); public function getAttributes(); public function setAttributes($attribs = array()); public function getNameOwerriden(); public function isNameOwerriden(); } abstract class SerializeXmlAbstract implements SerializeXml { protected $attributes; protected $nameOwerriden; function __construct($name = NULL) { $this->nameOwerriden = $name; } public function getAttributes() { return $this->attributes; } public function getNameOwerriden() { return $this->nameOwerriden; } public function setAttributes($attribs = array()) { $this->attributes = $attribs; } public function hasAttributes() { return (is_array($this->attributes) && count($this->attributes) > 0) ? TRUE : FALSE; } public function isNameOwerriden() { return $this->nameOwerriden != NULL ? TRUE : FALSE; } } abstract class Entity_list extends SplObjectStorage { protected $_listItemType; public function __construct($type) { $this->setListItemType($type); } private function setListItemType($param) { $this->_listItemType = $param; } public function detach($object) { if ($object instanceOf $this->_listItemType) { parent::detach($object); } } public function attach($object, $data = null) { if ($object instanceOf $this->_listItemType) { parent::attach($object, $data); } } } abstract class Array_list extends SerializeXmlAbstract { protected $_listItemType; protected $_items; public function __construct() { //$this->setListItemType($type); $this->_items = new SplObjectStorage(); } protected function setListItemType($param) { $this->_listItemType = $param; } public function getArray() { $return = array(); $this->_items->rewind(); while ($this->_items->valid()) { $return[] = $this->_items->current(); $this->_items->next(); } // print_r($return); return $return; } public function detach($object) { if ($object instanceOf $this->_listItemType) { if (in_array($this->_items->contains($object))) { $this->_items->detach($object); } } } public function attachItem($ob) { $this->_items->attach($ob); } } class Object2xml { public $rootPrefix = "ernm"; private $addPrefix; public $xml; public function serialize($object, $name = NULL, $prefix = FALSE) { if ($object instanceof SerializeXml) { $this->xml = new DOMDocument('1.0', 'utf-8'); $this->xml->appendChild($this->object2xml($object, $name, TRUE)); $this->xml->formatOutput = true; echo $this->xml->saveXML(); } else { die("Not implement SerializeXml interface"); } } protected function object2xml(SerializeXmlAbstract $object, $nodeName = NULL, $prefix = null) { $single = property_exists(get_class($object), "value"); $nName = $nodeName != NULL ? $nodeName : get_class($object); if ($prefix) { $nName = $this->rootPrefix . ":" . $nName; } if ($single) { $ref = $this->xml->createElement($nName); } elseif (is_object($object)) { if ($object->isNameOwerriden()) { $nodeName = $object->getNameOwerriden(); } $ref = $this->xml->createElement($nName); if ($object->hasAttributes()) { foreach ($object->getAttributes() as $key => $value) { $ref->setAttribute($key, $value); } } foreach (get_object_vars($object) as $n => $prop) { switch (gettype($prop)) { case "object": if ($prop instanceof SplObjectStorage) { $ref->appendChild($this->handleList($n, $prop)); } elseif ($prop instanceof Array_list) { $node = $this->object2xml($prop); foreach ($object->ResourceGroup->getArray() as $key => $value) { $node->appendChild($this->object2xml($value)); } $ref->appendChild($node); } else { $ref->appendChild($this->object2xml($prop)); } break; default : if ($prop != null) { $ref->appendChild($this->xml->createElement($n, $prop)); } break; } } } elseif (is_array($object)) { foreach ($object as $value) { $ref->appendChild($this->object2xml($value)); } } return $ref; } private function handleList($name, SplObjectStorage $param, $nodeName = NULL) { $lst = $this->xml->createElement($nodeName == NULL ? $name : $nodeName); $param->rewind(); while ($param->valid()) { if ($param->current() != null) { $lst->appendChild($this->object2xml($param->current())); } $param->next(); } return $lst; } } 

This is the code you need to get valid xml from objects. The following sample creates this xml:

 <InsertMessage priority="high"> <NodeSimpleValue firstAttrib="first" secondAttrib="second">simple value</NodeSimpleValue> <Arrarita> <Title>PHP OOP is great</Title> <SequenceNumber>1</SequenceNumber> <Child> <FirstChild>Jimmy</FirstChild> </Child> <Child2> <FirstChild>bird</FirstChild> </Child2> </Arrarita> <ThirdChild> <NodeWithChilds> <FirstChild>John</FirstChild> <ThirdChild>James</ThirdChild> </NodeWithChilds> <NodeWithChilds> <FirstChild>DomDocument</FirstChild> <SecondChild>SplObjectStorage</SecondChild> </NodeWithChilds> </ThirdChild> </InsertMessage> 

The classes needed for this xml are:

 class NodeWithArrayList extends Array_list { public $Title; public $SequenceNumber; public function __construct($name = NULL) { echo $name; parent::__construct($name); } } class EntityListNode extends Entity_list { public function __construct($name = NULL) { parent::__construct($name); } } class NodeWithChilds extends SerializeXmlAbstract { public $FirstChild; public $SecondChild; public $ThirdChild; public function __construct($name = NULL) { parent::__construct($name); } } class NodeSimpleValue extends SerializeXmlAbstract { protected $value; public function getValue() { return $this->value; } public function setValue($value) { $this->value = $value; } public function __construct($name = NULL) { parent::__construct($name); } } 

And finally, the code that creates the object objects:

 $firstChild = new NodeSimpleValue("firstChild"); $firstChild->setValue( "simple value" ); $firstChild->setAttributes(array("firstAttrib" => "first", "secondAttrib" => "second")); $secondChild = new NodeWithArrayList("Arrarita"); $secondChild->Title = "PHP OOP is great"; $secondChild->SequenceNumber = 1; $firstListItem = new NodeWithChilds(); $firstListItem->FirstChild = "John"; $firstListItem->ThirdChild = "James"; $firstArrayItem = new NodeWithChilds("Child"); $firstArrayItem->FirstChild = "Jimmy"; $SecondArrayItem = new NodeWithChilds("Child2"); $SecondArrayItem->FirstChild = "bird"; $secondListItem = new NodeWithChilds(); $secondListItem->FirstChild = "DomDocument"; $secondListItem->SecondChild = "SplObjectStorage"; $secondChild->attachItem($firstArrayItem); $secondChild->attachItem($SecondArrayItem); $list = new EntityListNode("NodeWithChilds"); $list->attach($firstListItem); $list->attach($secondListItem); $message = New NodeWithChilds("InsertMessage"); $message->setAttributes(array("priority" => "high")); $message->FirstChild = $firstChild; $message->SecondChild = $secondChild; $message->ThirdChild = $list; $object2xml = new Object2xml(); $object2xml->serialize($message, "xml", TRUE); 

Hope this helps someone.

Cheers, Siniša

0
Jun 30. '17 at 17:40
source share

Here is my code used to serialize PHP objects into XML "understandable" using Microsoft.NET XmlSerializer.Deserialize

 class XMLSerializer { /** * Get object class name without namespace * @param object $object Object to get class name from * @return string Class name without namespace */ private static function GetClassNameWithoutNamespace($object) { $class_name = get_class($object); return end(explode('\\', $class_name)); } /** * Converts object to XML compatible with .NET XmlSerializer.Deserialize * @param type $object Object to serialize * @param type $root_node Root node name (if null, objects class name is used) * @return string XML string */ public static function Serialize($object, $root_node = null) { $xml = '<?xml version="1.0" encoding="UTF-8" ?>'; if (!$root_node) { $root_node = self::GetClassNameWithoutNamespace($object); } $xml .= '<' . $root_node . ' xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">'; $xml .= self::SerializeNode($object); $xml .= '</' . $root_node . '>'; return $xml; } /** * Create XML node from object property * @param mixed $node Object property * @param string $parent_node_name Parent node name * @param bool $is_array_item Is this node an item of an array? * @return string XML node as string * @throws Exception */ private static function SerializeNode($node, $parent_node_name = false, $is_array_item = false) { $xml = ''; if (is_object($node)) { $vars = get_object_vars($node); } else if (is_array($node)) { $vars = $node; } else { throw new Exception('Coś poszło nie tak'); } foreach ($vars as $k => $v) { if (is_object($v)) { $node_name = ($parent_node_name ? $parent_node_name : self::GetClassNameWithoutNamespace($v)); if (!$is_array_item) { $node_name = $k; } $xml .= '<' . $node_name . '>'; $xml .= self::SerializeNode($v); $xml .= '</' . $node_name . '>'; } else if (is_array($v)) { $xml .= '<' . $k . '>'; if (count($v) > 0) { if (is_object(reset($v))) { $xml .= self::SerializeNode($v, self::GetClassNameWithoutNamespace(reset($v)), true); } else { $xml .= self::SerializeNode($v, gettype(reset($v)), true); } } else { $xml .= self::SerializeNode($v, false, true); } $xml .= '</' . $k . '>'; } else { $node_name = ($parent_node_name ? $parent_node_name : $k); if ($v === null) { continue; } else { $xml .= '<' . $node_name . '>'; if (is_bool($v)) { $xml .= $v ? 'true' : 'false'; } else { $xml .= htmlspecialchars($v, ENT_QUOTES); } $xml .= '</' . $node_name . '>'; } } } return $xml; } } 

Example:

 class GetProductsCommandResult { public $description; public $Errors; } class Error { public $id; public $error; } $obj = new GetProductsCommandResult(); $obj->description = "Teścik"; $obj->Errors = array(); $obj->Errors[0] = new Error(); $obj->Errors[0]->id = 666; $obj->Errors[0]->error = "Sth"; $obj->Errors[1] = new Error(); $obj->Errors[1]->id = 666; $obj->Errors[1]->error = null; $xml = XMLSerializer::Serialize($obj); 

leads to:

 <?xml version="1.0" encoding="UTF-8"?> <GetProductsCommandResult xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <description>Teścik</description> <Errors> <Error> <id>666</id> <error>Sth</error> </Error> <Error> <id>666</id> </Error> </Errors> </GetProductsCommandResult> 
0
Nov 02 '17 at 11:30
source share

Well, although a little dirty, you can always start the object's property loop ...

 $_xml = ''; foreach($obj as $key => $val){ $_xml .= '<' . $key . '>' . $val . '</' . $key . ">\n"; } 

Using fopen / fwrite / fclose, you can create an XML document with the variable $_xml as content. It is ugly, but it will work.

-one
Sep 26 '08 at 0:12
source share

While I agree with @philfreo and his reasoning that you should not depend on PEAR, his solution is still not quite there. There are potential problems when the key can be a string containing any of the following characters:

  • <<Lithium →
  • \ s (space)
  • "

Any of these will discard the format, since XML uses these characters in its grammar. So, without further ado, here is a simple solution to this very possible case:

 function xml_encode( $var, $indent = false, $i = 0 ) { $version = "1.0"; if ( !$i ) { $data = '<?xml version="1.0"?>' . ( $indent ? "\r\n" : '' ) . '<root vartype="' . gettype( $var ) . '" xml_encode_version="'. $version . '">' . ( $indent ? "\r\n" : '' ); } else { $data = ''; } foreach ( $var as $k => $v ) { $data .= ( $indent ? str_repeat( "\t", $i ) : '' ) . '<var vartype="' .gettype( $v ) . '" varname="' . htmlentities( $k ) . '"'; if($v == "") { $data .= ' />'; } else { $data .= '>'; if ( is_array( $v ) ) { $data .= ( $indent ? "\r\n" : '' ) . xml_encode( $v, $indent, $verbose, ($i + 1) ) . ( $indent ? str_repeat("\t", $i) : '' ); } else if( is_object( $v ) ) { $data .= ( $indent ? "\r\n" : '' ) . xml_encode( json_decode( json_encode( $v ), true ), $indent, $verbose, ($i + 1)) . ($indent ? str_repeat("\t", $i) : ''); } else { $data .= htmlentities( $v ); } $data .= '</var>'; } $data .= ($indent ? "\r\n" : ''); } if ( !$i ) { $data .= '</root>'; } return $data; } 

Here is a usage example:

 // sample object $tests = Array( "stringitem" => "stringvalue", "integeritem" => 1, "floatitem" => 1.00, "arrayitems" => Array("arrayvalue1", "arrayvalue2"), "hashitems" => Array( "hashkey1" => "hashkey1value", "hashkey2" => "hashkey2value" ), "literalnull" => null, "literalbool" => json_decode( json_encode( 1 ) ) ); // add an objectified version of itself as a child $tests['objectitem'] = json_decode( json_encode( $tests ), false); // convert and output echo xml_encode( $tests ); /* // output: <?xml version="1.0"?> <root vartype="array" xml_encode_version="1.0"> <var vartype="integer" varname="integeritem">1</var> <var vartype="string" varname="stringitem">stringvalue</var> <var vartype="double" varname="floatitem">1</var> <var vartype="array" varname="arrayitems"> <var vartype="string" varname="0">arrayvalue1</var> <var vartype="string" varname="1">arrayvalue2</var> </var> <var vartype="array" varname="hashitems"> <var vartype="string" varname="hashkey1">hashkey1value</var> <var vartype="string" varname="hashkey2">hashkey2value</var> </var> <var vartype="NULL" varname="literalnull" /> <var vartype="integer" varname="literalbool">1</var> <var vartype="object" varname="objectitem"> <var vartype="string" varname="stringitem">stringvalue</var> <var vartype="integer" varname="integeritem">1</var> <var vartype="integer" varname="floatitem">1</var> <var vartype="array" varname="arrayitems"> <var vartype="string" varname="0">arrayvalue1</var> <var vartype="string" varname="1">arrayvalue2</var> </var> <var vartype="array" varname="hashitems"> <var vartype="string" varname="hashkey1">hashkey1value</var> <var vartype="string" varname="hashkey2">hashkey2value</var> </var> <var vartype="NULL" varname="literalnull" /> <var vartype="integer" varname="literalbool">1</var> </var> </root> */ 

Note that the key names are stored in the varname (html encoded) attribute, and even the type is saved, so symmetric de-serialization is possible. There is only one problem: it will not serialize classes, but only an instance of an object that will not include class methods. This only works for transferring "data" back and forth.

I hope this helps someone, although it has long been answered.

-one
Jul 26 '11 at 23:59
source share



All Articles