Symfony3:XML反序列化数组

时间:2018-03-02 11:50:08

标签: php xml xml-deserialization symfony-3.4

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”] =&gt; object(AppBundle \ Entity \ Book)#385(11){[“isbn”:protected] =&gt; NULL [“autor”:protected] =&gt; NULL [“titulo”:protected] =&gt; NULL [“fecha_ini”:protected] =&gt; NULL [“fecha_fin”:protected] =&gt; NULL [“editor”:protected] =&gt; NULL [“imgUrl”:protected] =&gt; NULL [“cod_autor”:protected] =&gt; NULL [“cod_editorial”:protected] =&gt; NULL [“cod_coleccion”:protected] =&gt; NULL [“cod_mat”:protected] =&gt; NULL}}

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

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

提前致谢。

1 个答案:

答案 0 :(得分: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添加一些功能: / p>

$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
        );
    }
}

并享受在不使用包装对象的情况下反序列化一系列Book的功能:

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