Я знаю, что это старый вопрос, но недавно мне пришлось генерировать сложные XML-структуры.
Мой подход содержит передовые принципы ООП. Идея состоит в том, чтобы сериализовать родительский объект, который содержит несколько дочерних элементов и дочерних элементов.
Узлы получают имена из имен классов, но вы можете переопределить имя класса первым параметром при создании объекта для сериализации.
Вы можете создать: простой узел, без дочерних узлов, EntityList и ArrayList. EntityList - это список объектов одного и того же класса, но ArrayList может иметь разные объекты.
Каждый объект должен расширять абстрактный класс SerializeXmlAbstract , чтобы соответствовать первому входному параметру в классе: 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