我想使用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
实体,反序列化适用于rcs
和name
,但对于main
,我必须创建一个Main
包含OneToOne
实体的Adr1
关系的实体,其中包含type
,street
和zip
属性。这很重。有没有办法告诉序列化剂水合物的路径?类似的东西:
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来保护一个独特的实体。
答案 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');