作为XML文档的PHP对象

获取给定的PHP对象并将其序列化为XML的最佳方法是什么? 我正在看simple_xml,我用它来parsingXML到对象中,但是我不清楚它是如何工作的。

看看PEAR的XML_Serializer包。 我用它有相当好的结果。 你可以给它的数组,对象等,它会把它们变成XML。 它也有一些选项,如select根节点的名称等

应该做的伎俩

我同意使用PEAR的XML_Serializer,但是如果你想要一些简单的支持嵌套属性的对象/数组,你可以使用它。

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; } } 

不是一个原始问题的答案,但我解决我的问题的方式是通过声明我的对象为:

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

而不是:

 $object = new stdClass; 

在我开始添加任何值之前!

使用一个dom函数来做到这一点: http : //www.php.net/manual/en/function.dom-import-simplexml.php

导入SimpleXML对象,然后保存。 上面的链接包含一个例子。 🙂

简而言之:

 <?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); } ?> 

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

(如果安装了这个扩展)

它致力于:

http://www.openwddx.org/

看看我的版本

  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; } } 

我知道这是一个老问题,但最近我不得不生成复杂的XML结构。

我的方法包含高级面向对象的原则。 这个想法是序列化包含多个孩子和子孩子的父对象。

节点从类名中获取名称,但是在创build序列化对象时,可以使用第一个参数覆盖类名。

你可以创build:一个简单的节点,没有子节点,EntityList和ArrayList。 EntityList是同一个类的对象列表,但是ArrayList可能有不同的对象。

每个对象都必须扩展抽象类SerializeXmlAbstract ,以匹配类中的第一个input参数:Object2xml,方法serialize($object, $name = NULL, $prefix = FALSE)

默认情况下,如果不提供第二个参数,则根XML节点将具有给定对象的类名称。 第三个参数指示根节点名是否有前缀。 前缀在Export2xml类中被硬编码为一个私有属性。

 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; } } 

这是你需要能够从对象获得有效的XML的代码。 下一个示例产生这个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> 

这个XML所需的类是:

 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); } } 

最后,实例化对象的代码是:

 $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); 

希望它能帮助别人。

干杯,Siniša

这里是我的代码,用于将PHP对象序列化为由Microsoft .NET XmlSerializer.Deserialize“可理解”的XML

 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; } } 

例:

 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); 

结果是:

 <?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> 

虽然我赞同@philfreo和他的理由,你不应该依赖于梨,他的解决scheme仍然不是那里。 密钥可能是包含以下任何字符的string时,存在潜在的问题:

  • <
  • >
  • \(空间)

任何这些都会抛弃格式,因为XML在语法中使用这些字符。 所以,不要紧张,这是一个简单的解决scheme,很可能发生:

 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; } 

以下是一个示例用法:

 // 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> */ 

注意键名存储在varname属性(html编码)中,甚至存储了types,所以可以进行对称反序列化。 这只有一个问题:它不会序列化类,只是实例化的对象,它不包括类方法。 这只能用于来回传递“数据”。

我希望这可以帮助别人,尽pipe很久以前就已经回答了。

那么,虽然有点肮脏,你总是可以在对象的属性上运行一个循环…

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

使用fopen / fwrite / fclose你可以用$_xmlvariables生成一个XML文档作为内容。 这是丑陋的,但它会奏效。