使用JMS Serializer将XML反序列化为具有嵌套节点的实体

时间:2018-05-11 14:24:51

标签: xml symfony nodes jms-serializer

我想使用JMS Serializer将XML文件反序列化为实体。 它对于直接属性非常有效。但是当谈到嵌套属性时,如果不创建相关实体,我就无法工作。例如:

<idt>
    <rcs>XXXXXXX</rcs>
    <name>NAME</name>
    <main>
        <adr_1>
            <type>YYYYY</type>
            <street>YYYYYYY</street>
            <zip>XXXXX</zip>
        </adr_1>
    </main>
</idt>

我需要创建一个Idt实体,反序列化适用于rcsname,但对于main,我必须创建一个Main包含OneToOne实体的Adr1关系的实体,其中包含typestreetzip属性。这很重。有没有办法告诉序列化剂水合物的路径?类似的东西:

class XmlRawExecutive
{
    /**
     * @var integer
     *
     * @ORM\Column(name="rcs", type="string", length=3, nullable=false)
     * @JMS\Type("string")
     */
    private $rcs;

    /**
     * @var integer
     *
     * @ORM\Column(name="main_adr1_street", type="integer", nullable=false)
     * @JMS\Type("string")
     */
    private $mainAdr1Street;

所以我可以用XML来保护一个独特的实体。

1 个答案:

答案 0 :(得分:1)

JMS序列化器对将反序列化的数据映射到结果对象的方式提出了非常严格的要求。我建议在这种情况下使用一些more flexible library

但是,即使使用JMS序列化程序,我也设法将给定的XML反序列化为给定的平面对象。该解决方案使用pre_deserialize event listener,修改已解析的XML数据:

use JMS\Serializer\EventDispatcher\EventDispatcher;
use JMS\Serializer\EventDispatcher\PreDeserializeEvent;
use JMS\Serializer\SerializerBuilder;
use JMS\Serializer\Annotation as JMS;

class Idt
{
    /**
     * @JMS\Type("string")
     */
    protected $rcs;

    /**
     * @JMS\Type("string")
     */
    protected $mainAdr1Street;
}

/**
 * turns nested elements into children of the root element
 * with names combining names of all the ancestors
 */
function recursiveChildrenInliner (\SimpleXMLElement $root, \SimpleXMLElement $child, $stack = []) {
    if ($child->count() === 0) {
        // produces element name like 'main_adr1_street'
        $name = join('_', array_map(
            function ($n) { return str_replace('_', '', $n); },
            $stack
        ));
        $root->addChild($name, $child->__toString());
    } else {
        foreach ($child->children() as $child) {
            $stackCopy = $stack;
            array_push($stackCopy, $child->getName());

            recursiveChildrenInliner(
                $root,
                $child,
                $stackCopy
            );
        }
    }
};

// build custom serializer instance with a listener registered
$serializer = SerializerBuilder::create()
    ->configureListeners(function (EventDispatcher $dispatcher) {
        $dispatcher->addListener('serializer.pre_deserialize',
            function (PreDeserializeEvent $event) {
                $data = $event->getData();

                recursiveChildrenInliner($data, $data->main, ['main']);
            }
        );
    })
    ->build();

$result = $serializer->deserialize($xml, Idt::class, 'xml');