Symfony Serializer:如何将带属性的XML反序列化为对象数组?
PHP Symfony Serializer - 将XML反序列化为对象数组
问题描述
如何将带有属性的XML反序列化为对象数组?
现有代码
XML字符串:
$string = '<?xml version="1.0" encoding="UTF-8" ?> <response> <item flight="23"/> <item flight="24"/> </response>';
Serializer初始化逻辑:
$classMetadataFactory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader())); $metadataAwareNameConverter = new MetadataAwareNameConverter($classMetadataFactory); $serializer = new Serializer( [new ArrayDenormalizer(), new ObjectNormalizer($classMetadataFactory, $metadataAwareNameConverter)], [new XmlEncoder()] ); $objects = $serializer->deserialize($string, 'App\Entities\Item[]', 'xml');
Item实体类:
class Item { #[SerializedName('@flight')] public string $flight; }
当前错误结果
array:1 [ "item" => App\Entities\Item ]
问题原因
Symfony的XmlEncoder默认会将多个同名子节点包装在以节点名为键的关联数组中(即['item' => [Item实例1, Item实例2]]),但直接指定目标类型为Item[]时,序列化器无法自动识别该嵌套结构,只会提取item键下的单个对象(或仅处理第一个节点)。
解决方案
方案1:使用DTO包装数组
创建对应XML根节点的DTO类,用来承载Item对象数组:
class ResponseDTO { #[SerializedName('item')] /** @var Item[] */ public array $items; }
修改反序列化逻辑,先解析为DTO再提取目标数组:
$responseDto = $serializer->deserialize($string, ResponseDTO::class, 'xml'); $objects = $responseDto->items;
方案2:配置XmlEncoder的集合选项
在反序列化时通过上下文参数,明确告知编码器将item节点作为集合处理:
use Symfony\Component\Serializer\Encoder\XmlEncoder; $objects = $serializer->deserialize( $string, 'App\Entities\Item[]', 'xml', [XmlEncoder::AS_COLLECTION => ['item' => true]] );
也可以在创建XmlEncoder时直接设置默认集合规则:
use Symfony\Component\Serializer\Encoder\XmlEncoder; $encoder = new XmlEncoder(null, null, [XmlEncoder::AS_COLLECTION => ['item' => true]]); $serializer = new Serializer( [new ArrayDenormalizer(), new ObjectNormalizer($classMetadataFactory, $metadataAwareNameConverter)], [$encoder] ); $objects = $serializer->deserialize($string, 'App\Entities\Item[]', 'xml');
验证结果
修改后,$objects会变成包含两个Item实例的索引数组:
array:2 [ 0 => App\Entities\Item {#xxx +flight: "23" } 1 => App\Entities\Item {#xxx +flight: "24" } ]
内容的提问来源于stack exchange,提问作者Kanat
相关产品推荐
相关产品推荐

