Symfony Serializer反序列化含对象数组的XML遇问题求助
解决Symfony Serializer反序列化XML数组到对象集合的问题
核心问题分析
你的XML结构中,<COMPONENT>节点下包含多个<item>子节点,Symfony Serializer默认无法自动识别这种嵌套结构需要映射为Component对象数组,尤其是单个<item>时会出现层级丢失的情况。需要通过注解配置或上下文参数明确XML节点与对象属性的映射规则,同时确保Serializer能正确读取类型信息。
解决方案步骤
1. 安装必要依赖
确保安装doctrine/annotations以支持注解解析:
composer require doctrine/annotations
2. 给实体类添加序列化注解
在实体类中使用Symfony的序列化注解,明确XML节点与属性的映射关系:
MyObject类
use Symfony\Component\Serializer\Annotation\SerializedName; use Symfony\Component\Serializer\Annotation\XmlList; class MyObject { /** * @SerializedName("RETURN") */ private Return $return; /** * @var array<Component> * @SerializedName("COMPONENT") * @XmlList(entry="item") // 指定数组元素对应的XML子节点名称 */ private array $component = []; // 生成对应的getter/setter方法 public function getReturn(): Return { return $this->return; } public function setReturn(Return $return): void { $this->return = $return; } public function getComponent(): array { return $this->component; } public function setComponent(array $component): void { $this->component = $component; } }
Return类
use Symfony\Component\Serializer\Annotation\SerializedName; class Return { /** * @SerializedName("TYPE") */ private string $type; public function getType(): string { return $this->type; } public function setType(string $type): void { $this->type = $type; } }
Component类
use Symfony\Component\Serializer\Annotation\SerializedName; class Component { /** * @SerializedName("ID") */ private int $id; public function getId(): int { return $this->id; } public function setId(int $id): void { $this->id = $id; } }
3. 配置Serializer以支持注解和类型提取
修改Serializer实例的配置,添加注解加载器和复合类型提取器,确保能读取注解规则和属性类型:
use Symfony\Component\Serializer\Serializer; use Symfony\Component\Serializer\Normalizer\ArrayDenormalizer; use Symfony\Component\Serializer\Normalizer\ObjectNormalizer; use Symfony\Component\Serializer\Encoder\XmlEncoder; use Symfony\Component\PropertyInfo\Extractor\ReflectionExtractor; use Symfony\Component\PropertyInfo\Extractor\PhpDocExtractor; use Symfony\Component\PropertyInfo\PropertyInfoExtractor; use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactory; use Symfony\Component\Serializer\Mapping\Loader\AnnotationLoader; use Doctrine\Common\Annotations\AnnotationReader; // 初始化注解读取器与类元数据工厂 $classMetadataFactory = new ClassMetadataFactory( new AnnotationLoader(new AnnotationReader()) ); // 组合PhpDoc和反射提取器,确保能识别数组元素类型 $propertyInfoExtractor = new PropertyInfoExtractor( typeExtractors: [new PhpDocExtractor(), new ReflectionExtractor()] ); // 创建Serializer实例 $serializer = new Serializer( [ new ArrayDenormalizer(), new ObjectNormalizer( classMetadataFactory: $classMetadataFactory, propertyTypeExtractor: $propertyInfoExtractor ), ], [new XmlEncoder()] );
4. 执行反序列化
现在可以正常反序列化XML内容,无论是多个<item>还是单个<item>,都会正确映射为Component对象数组:
$xmlContent = <<<XML <?xml version="1.0"?> <ROOT> <RETURN> <TYPE>test</TYPE> </RETURN> <COMPONENT> <item> <ID>1</ID> </item> <item> <ID>2</ID> </item> </COMPONENT> </ROOT> XML; /** @var MyObject $myObject */ $myObject = $serializer->deserialize($xmlContent, MyObject::class, 'xml'); // 验证结果 var_dump($myObject->getComponent()); // 输出包含2个Component对象的数组
替代方案:使用上下文参数(无需注解)
如果不想用注解,可以在反序列化时通过上下文参数指定映射规则:
$myObject = $serializer->deserialize( $xmlContent, MyObject::class, 'xml', [ XmlEncoder::ROOT_NODE_NAME => 'ROOT', ObjectNormalizer::ATTRIBUTES => [ 'return' => ['SerializedName' => 'RETURN'], 'component' => [ 'SerializedName' => 'COMPONENT', 'XmlList' => ['entry' => 'item'], ], ], ObjectNormalizer::PROPERTY_TYPE_EXTRACTOR => $propertyInfoExtractor, ] );
内容的提问来源于stack exchange,提问作者Select0r
相关产品推荐
相关产品推荐

