You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Symfony Serializer反序列化含属性XML失败求助

问题排查与解决

为啥反序列化出来是空的?

核心问题出在注解路径错误和反序列化目标类型不匹配:

  1. 你给Issue实体的#[SerializedName]加了issue/前缀,但实际反序列化时,Serializer已经聚焦到<issue>节点内部了,不需要再指定外层的issue路径。
  2. XML根节点是<issues>,里面包着<issue>,直接反序列化为Issue::class,Serializer找不到对应的数据映射关系。

一步步解决

1. 修正Issue和Page的注解

把注解里的issue/前缀删掉,直接用节点内部的属性/节点名:

// Issue类
class Issue
{
    #[ORM\Id]
    #[ORM\Column]
    #[SerializedName('@id')] // 对应<issue id="1">的id属性
    private ?int $id = null;

    #[ORM\Column(length: 255, nullable: true)]
    #[SerializedName('@name')] // 对应<issue name="test">的name属性
    private ?string $name = null;

    #[ORM\OneToMany(mappedBy: 'issue', targetEntity: Page::class)]
    #[SerializedName('page')] // 对应<issue>下的多个<page>节点
    private Collection $pages;

    // 必须在构造函数初始化集合!
    public function __construct()
    {
        $this->pages = new ArrayCollection();
    }

    // 省略getter/setter
}
// Page类
class Page
{
    #[ORM\Id]
    #[ORM\Column]
    #[SerializedName('@id')]
    private ?int $id = null;

    #[ORM\Column(length: 255, nullable: true)]
    #[SerializedName('@name')]
    private ?string $name = null;

    #[ORM\ManyToOne(inversedBy: 'pages')]
    private ?Issue $issue = null;

    // 省略getter/setter
}

2. 调整反序列化逻辑

因为XML根是<issues>,里面是<issue>,直接反序列化为Issue::class会错位,推荐用包裹类来适配结构:

// 新建一个Issues包裹类
class Issues
{
    #[SerializedName('issue')]
    private ?Issue $issue = null;

    // 生成getter/setter
    public function getIssue(): ?Issue
    {
        return $this->issue;
    }

    public function setIssue(?Issue $issue): self
    {
        $this->issue = $issue;
        return $this;
    }
}

然后修改反序列化代码:

$issuesWrapper = $serializer->deserialize($xml, Issues::class, 'xml');
$issue = $issuesWrapper->getIssue();

如果不想新建包裹类,也可以先转成数组再提取:

// 先把XML转成数组
$arrayData = $serializer->deserialize($xml, 'array', 'xml');
// 取出<issue>节点的数据
$issueData = $arrayData['issue'];
// 再把数组转成Issue对象
$issue = $serializer->deserialize(json_encode($issueData), Issue::class, 'json');

3. 检查Serializer配置

确保ObjectNormalizer支持集合和关联关系,调整配置:

$classMetadataFactory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader()));
$metadataAwareNameConverter = new MetadataAwareNameConverter($classMetadataFactory);

$normalizers = [
    new ArrayDenormalizer(),
    new ObjectNormalizer(
        $classMetadataFactory,
        $metadataAwareNameConverter,
        null,
        new ReflectionExtractor(),
        null,
        null,
        ['enable_max_depth' => true] // 开启深度支持,处理关联集合
    )
];
$encoders = [new XmlEncoder()];

$serializer = new Serializer($normalizers, $encoders);

验证效果

做完上面的修改后,再反序列化就能正确拿到Issue的id、name,以及pages集合里的所有Page对象了。

内容的提问来源于stack exchange,提问作者23nr1

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 04:31:02