Symfony3: XML反序列化数组

3
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 字符串:

[{"name":"foo","age":99,"sportsman":false},{"name":"bar","age":33,"sportsman":true}]

所以我尝试用我的 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;

响应是默认的根节点名称。我有一个书籍实体,其字段定义完全相同。 我尝试像这样反序列化:

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');

当我对反序列化变量进行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 } }

当我期望有两个元素时,数据未被识别,而数组只有一个元素。
有人遇到过这样的问题吗?你能帮我找到解决方案吗?
提前感谢。

你能分享$data吗?还可以尝试移除<response>吗? - Joseph D.
$data 是上述的 XML 结构。如果我删除 <response>,我必须用另一个根节点来替换它。那么应该选择哪一个呢? 没有它,XML 结构将无法有效。 - Appyapp
1个回答

3

XML不是JSON,根元素也不仅仅是“数组的包装器”,因此您需要给它应有的尊重。有两种方法可以解决这个问题:

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

Original Answer

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实例,需要添加一个额外的功能来提取嵌套实体的类型信息。请参考递归反规范化和类型安全。最初的回答。
$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');

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接