web-dev-qa-db-fra.com

PHP Objet en tant que document XML

Quel est le meilleur moyen de prendre un objet PHP donné et de le sérialiser en XML? Je regarde simple_xml et je l'ai utilisé pour analyser XML en objets, mais je ne vois pas très bien comment cela fonctionne.

47
Sam McAfee

jetez un oeil à PEAR's XML_Serializer package. Je l'ai utilisé avec de très bons résultats. Vous pouvez nourrir des tableaux, des objets, etc. et les transformer en XML. Il a également un tas d'options comme choisir le nom du nœud racine, etc. 

Devrait faire l'affaire

39
phatduckk

Je suis d'accord avec l'utilisation de XML_Serializer de PEAR, mais si vous voulez quelque chose de simple qui supporte les objets/tableaux avec des propriétés imbriquées, vous pouvez l'utiliser.

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

}
49
philfreo

pas tout à fait une réponse à la question initiale, mais la façon dont j'ai résolu mon problème avec ceci était en déclarant mon objet comme:

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

par opposition à:

$object = new stdClass;

avant que je commence à ajouter des valeurs!

9
significance

Utilisez une fonction dom pour le faire: http://www.php.net/manual/fr/function.dom-import-simplexml.php

Importez l'objet SimpleXML puis enregistrez. Le lien ci-dessus contient un exemple. :)

En un mot:

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

regarde ma 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;
    }    
}
2
Bulki S Maslom

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

(si cette extension est installée)

c'est dédié à ça:

http://www.openwddx.org/

2
user22960

Utilisez la méthode récursive, comme ceci:

private function ReadProperty($xmlElement, $object) {
    foreach ($object as $key => $value) {
        if ($value != null) {
            if (is_object($value)) {
                $element = $this->xml->createElement($key);
                $this->ReadProperty($element, $value);
                $xmlElement->AppendChild($element);
            } elseif (is_array($value)) {
                $this->ReadProperty($xmlElement, $value);
            } else {
                $this->AddAttribute($xmlElement, $key, $value);
            }
        }
    }
}

Voici l'exemple complet: http://www.tyrodeveloper.com/2018/09/convertir-clase-en-xml-con-php.html

0
tyrodeveloper

Voici mon code utilisé pour sérialiser les objets PHP en XML "compréhensible" par 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;
    }
}

exemple:

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

résulte en:

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

Je sais que c'est une vieille question, mais récemment, j'ai dû générer des structures XML complexes.

Mon approche contient des principes avancés OOP. L'idée est de sérialiser l'objet parent qui contient plusieurs enfants et sous-enfants. 

Les nœuds obtiennent des noms à partir des noms de classe, mais vous pouvez remplacer le nom de la classe par le premier paramètre lors de la création d'un objet pour la sérialisation.

Vous pouvez créer: un nœud simple, sans nœuds enfants, EntityList et ArrayList. EntityList est une liste d'objets de la même classe, mais un ArrayList peut avoir différents objets.

Chaque objet doit étendre la classe abstraite SerializeXmlAbstract afin de faire correspondre le premier paramètre d'entrée de la classe: Object2xml, méthode serialize($object, $name = NULL, $prefix = FALSE).

Par défaut, si vous ne fournissez pas le deuxième paramètre, le nœud XML racine aura le nom de classe de l'objet donné. Le troisième paramètre indique si le nom du noeud racine a un préfixe ou non. Le préfixe est codé en dur en tant que propriété privée dans la classe 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;
    }
}

C'est le code dont vous avez besoin pour pouvoir obtenir du XML valide à partir d'objets. Le prochain échantillon produit ce 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>

Les classes nécessaires pour ce XML sont:

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

Et enfin, le code qui instancie les objets est:

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

J'espère que ça va aider quelqu'un.

Cordialement, Siniša