The Symfony 3.4 documentation states the following for deserializing arrays:
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');
The json string is the following:
[{"name":"foo","age":99,"sportsman":false},{"name":"bar","age":33,"sportsman":true}]
So I tried to do the same with my XML structure. It's not a real structure as I'm testing the thing.
XML Structure:
<<<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 is the default root node name. I have a Book entity with the fields defined identically. I try to deserialize like that:
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');
When I do a var_dump of the deserialize variable, the output is the following:
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 are not recognized and the array has only one element when I expect 2 elements.
Does someone experience something like that? Can you help me where to look for the solution ?
Thanks in advance.
XML is not JSON and the root element is not "just a wrapper for an array", so you have to pay it a due respect. There are two ways to approach this:
1. Introduce a deserialization model for the root element - something like
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;
}
}
and then access books like
$response = $serializer->deserialize($xml, 'App\Entity\Response', 'xml');
$books = $response->getBook();
In this case, however, your simple serializer configuration won't suffice - in order to get books properly deserialized as Book
instances it is necessary to add an additional bit of functionality to 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
extracts type information from PhpDoc comments.
2. Introduce a custom denormalizer
Alternatively you can hook directly into the deserialization process with a custom denormalizer
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
);
}
}
And enjoy deserializing an array of Books without a wrapping object:
$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');
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.