Level42 / NotJaxbBundle

A Symfony 2 bundle to bind XML to PHP objects or PHP objects to XML using annotations
MIT License
3 stars 2 forks source link

XmlElement et namespaces #14

Open yann-eugone opened 10 years ago

yann-eugone commented 10 years ago

Soit le XML suivant :

<?xml version="1.0"?>
<foo:wrapper xmlns:foo="http://www.foo-bar.com/"
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xsi:schemaLocation="http://www.foo-bar.com/ http://www.foo-bar.com/schema.xsd">
<foo:bar>BAR</foo:bar>
<object id="1">
    <title>Test 1</title>
    <description>Test description 1</description>
</object>
</foo:wrapper>

Et les règles de sérialisation suivantes :

use Level42\NotJaxbBundle\Annotation as Serialize;

/**
 * @Serialize\XmlObject(ns="http://www.foo-bar.com/")
 */
class Test_Wrapper
{
    /**
     * @Serialize\XmlElement
     */
    private $bar;

    /**
     * @Serialize\XmlElement(type="Test_Object")
     */
    private $object;

    //...
}
use Level42\NotJaxbBundle\Annotation as Serialize;

/**
 * @Serialize\XmlObject(name="object")
 */
class Test_Object
{
    /**
     * @Serialize\XmlAttribute
     */
    private $id;

    /**
     * @Serialize\XmlElement
     */
    private $title;

    /**
     * @Serialize\XmlElement
     */
    private $description;

    //...
}

La sérialisation de la propriété object ne se fait pas (la valeur est toujours NULL), à cause des problématiques de namespaces sur l'objet root.

A mon sens, il s'agit d'un soucis au niveau de l'utilisation de l'objet SimpleXmlElement, couplé aux namespaces.


La correction suivante règle le problème :

namespace Level42\NotJaxbBundle\Manager;

class XmlUnmarshalling
{
    //...

    protected function parseEmbeds(\SimpleXmlElement $xml, ClassMetadata $metadata, $obj)
    {
        foreach ($metadata->getEmbeds() as $nodeName => $info)
        {
            $property = $info[0];
            $tempMetaData = $info[1];
            $namespace = $tempMetaData->getNamespace();

            $tempXml = $xml->children($namespace);
            $tempXml = $tempXml->$nodeName;

            if ($tempXml != null)
            {
                $tempObj = $this->parseObject($tempXml, $tempMetaData);
                if ($tempObj != null)
                {
                    $setter = 'set' . ucfirst($property);
                    $obj->$setter($tempObj);
                }
            }
        }
    }

    //...
}

Mais peut-elle être source de regression ?

yann-eugone commented 10 years ago

Et le problème est à priori le même sur tous les parse*

Exemples :

protected function parseElements(\SimpleXmlElement $xml, ClassMetadata $metadata, $obj)
    {
        foreach ($metadata->getElements() as $name => $properties)
        {
            $property = $properties[0];
            $namespace = $properties[1];

            if ($namespace == null)
            {
                $elements = $xml->children();
                $value = (string) $elements->$name;
            }
            else
            {
                $elements = $xml->children($namespace);
                $value = (string) $elements->$name;
            }

            $setter = 'set' . ucfirst($property);
            $obj->$setter($value);
        }
    }

ou

    protected function parseRow(\SimpleXmlElement $xml, ClassMetadata $metadata, $obj)
    {
        foreach ($metadata->getRows() as $nodeName => $info)
        {
            $property = $info[0];
            $namespace = $info[1];
            if ($namespace == null) {
                $node = $xml->children();
                $node = $node->$nodeName;
            } else {
                $node = $xml->children($namespace);
                $node = $node->$nodeName;
            }

            $value = $node->asXML();
            if ($value != null)
            {
                $setter = 'set' . ucfirst($property);
                $obj->$setter($value);
            }
        }
    }