问题
I want to deserialize an XML file into an Entity using JMS Serializer. It works pretty well for direct properties. But when it comes to nested properties, I can't make it work without creating related entities. For example :
<idt>
<rcs>XXXXXXX</rcs>
<name>NAME</name>
<main>
<adr_1>
<type>YYYYY</type>
<street>YYYYYYY</street>
<zip>XXXXX</zip>
</adr_1>
</main>
</idt>
I need to create an Idt
entity, and the deserialization will work fine for rcs
and name
, but for main
I have to create a Main
entity with a OneToOne
relation that contains a Adr1
entity that contains type
, street
and zip
properties. This is pretty heavy. Is there any way to tell the serializer the path to hydrate a property? Something of the like :
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;
So I can hydrate a unique entity from the XML.
回答1:
JMS Serializer imposes quite strict expectations on the way how deserialized data are mapped to the resulting objects. I would suggest using some more flexible library for scenarios like this.
However, I managed to deserialize the given XML to the given flat object even with JMS Serializer. The solution uses a pre_deserialize
event listener, modifying the parsed XML data:
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');
来源:https://stackoverflow.com/questions/50294500/deserialize-xml-to-entity-with-nested-nodes-using-jms-serializer