Symfony3:XML反序列化数组

问题描述 投票:1回答:1

Symfony 3.4文档说明了反序列化数组的以下内容:

use Symfony\Component\Serializer\Encoder\JsonEncoder;
use Symfony\Component\Serializer\Normalizer\ArrayDenormalizer;
use Symfony\Component\Serializer\Normalizer\GetSetMethodNormalizer;
use Symfony\Component\Serializer\Serializer;

$serializer = new Serializer(
array(new GetSetMethodNormalizer(), new ArrayDenormalizer()),
array(new JsonEncoder())
);

$data = ...; // The serialized data from the previous example
$persons = $serializer->deserialize($data, 'Acme\Person[]', 'json');

json字符串如下:

[{ “名称”: “foo” 的, “年龄”:99, “运动员”:假},{ “名称”: “棒”, “年龄”:33, “运动员”:真}]

所以我尝试用我的XML结构做同样的事情。这不是一个真实的结构,因为我正在测试这个东西。

XML结构:

<<<EOF
<response>
 <book>
  <titulo>foo</titulo>
  <isbn>99</isbn>
  <autor>Autor</autor>
  <editor>Editor</editor>
 </book>
 <book>
  <titulo>foo2</titulo>
  <isbn>100</isbn>
  <autor>Autor2</autor>
  <editor>Editor2</editor>
 </book>
</response>
EOF;

Response是默认的根节点名称。我有一个Book实体,其字段定义相同。我尝试反序列化:

use AppBundle\Entity\Book;
use Symfony\Component\Serializer\Serializer;
use Symfony\Component\Serializer\Encoder\XmlEncoder;
use Symfony\Component\Serializer\Encoder\JsonEncoder;
use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
use Symfony\Component\PropertyAccess\PropertyAccess;
use Symfony\Component\Serializer\Normalizer\ArrayDenormalizer;
use Symfony\Component\Serializer\Normalizer\GetSetMethodNormalizer;

$encoders = array(new XmlEncoder(), new JsonEncoder());
$normalizers = array(new GetSetMethodNormalizer(), new ArrayDenormalizer());
$serializer = new Serializer($normalizers, $encoders);

 $serializer->deserialize($data,  'AppBundle\Entity\Book[]', 'xml');

当我执行deserialize变量的var_dump时,输出如下:

array(1){[“book”] => object(AppBundle \ Entity \ Book)#385(11){[“isbn”:protected] => NULL [“autor”:protected] => NULL [“titulo” :protected] => NULL [“fecha_ini”:protected] => NULL [“fecha_fin”:protected] => NULL [“editor”:protected] => NULL [“imgUrl”:protected] => NULL [“cod_autor” :protected] => NULL [“cod_editorial”:protected] => NULL [“cod_coleccion”:protected] => NULL [“cod_mat”:protected] => NULL}}

当我期望2个元素时,数据不被识别,并且数组只有一个元素。

有人经历过这样的事吗?你能帮我在哪里寻找解决方案吗?

提前致谢。

php xml xml-deserialization symfony-3.4
1个回答
0
投票

XML不是JSON,根元素不是“只是数组的包装器”,所以你必须付出适当的尊重。有两种方法可以解决这个问题:

1.为根元素引入反序列化模型 - 类似于

class Response
{
    /**
     * @var Book[]
     */
    protected $book;

    /**
     * @return Book[]
     */
    public function getBook(): array
    {
        return $this->book;
    }

    /**
     * @param Book[] $book
     */
    public function setBook(array $book): void
    {
        $this->book = $book;
    }
}

然后访问像这样的书

$response = $serializer->deserialize($xml,  'App\Entity\Response', 'xml');
$books = $response->getBook();

但是,在这种情况下,您的简单序列化程序配置是不够的 - 为了将书籍正确地反序列化为Book实例,有必要为extract type information for the nested entities添加额外的功能:

$encoders = array(new XmlEncoder());
$normalizers = array(new GetSetMethodNormalizer(null, null, new PhpDocExtractor()), new ArrayDenormalizer()); // <- PhpDocExtractor
$serializer = new Serializer($normalizers, $encoders);

PhpDocExtractor从PhpDoc评论中提取类型信息。

2.引入自定义非规范化器

或者,您可以使用自定义的非规范化器直接挂钩到反序列化过程

use App\Entity\Book;
use Symfony\Component\Serializer\Normalizer\ArrayDenormalizer;

class BookArrayDenormalizer extends ArrayDenormalizer
{
    public function supportsDenormalization($data, $type, $format = null, array $context = [])
    {
        // only support deserialization of Book[]
        return Book::class.'[]' === $type;
    }

    public function denormalize($data, $class, $format = null, array $context = [])
    {
        return parent::denormalize(
            $data['book'], // this is the magic to ignore the root element
            $class, $format, $context
        );
    }
}

并且喜欢在没有包装对象的情况下反序列化一系列Books:

$normalizers = array(new GetSetMethodNormalizer(), new BookArrayDenormalizer(), new ArrayDenormalizer()); // add the new denormalizer
$encoders = array(new XmlEncoder());
$serializer = new Serializer($normalizers, $encoders);

$books = $serializer->deserialize($xml,  'App\Entity\Book[]', 'xml');
© www.soinside.com 2019 - 2024. All rights reserved.