如何将XML反序列化为包含php Symfony中的数组集合的对象

问题描述 投票:0回答:3

我有格式的XML

<POS>
    <Source PseudoCCode="BOA" ISOCountry="US" AgentDutyCode="J114N">
        <RequestorID Type="11" ID="T921">
            <CompanyName Code="CP" CodeContext="123T"/>
        </RequestorID>
    </Source>
    <Source>
        <RequestorID Type="1" ID="34778"/>  
    </Source>
    <Source>
        <RequestorID Type="9" ID="ZF"/>
    </Source>
    <Source>
        <RequestorID Type="17" ID="mabaan"/>
    </Source>
</POS>

`

我有一个我要反序列化的php对象。

  class POS
  {
 /**
   * @ORM\OneToMany(targetEntity="POS_Source", mappedBy="POS", orphanRemoval=true)
 * @Groups("Include")
 */
private $Source;

public function __construct()
{
     $this->Source = new ArrayCollection();
}
/**
 * @return ArrayCollection|OTA_POS_Source[]
 */
public function getSource(): ArrayCollection
{
    return $this->Source;
}

public function addSource(POS_Source $source): self
{
    if (!$this->Source->contains($source)) {
        $this->Source[] = $source;
        $source->setPOS($this);
    }

    return $this;
}

public function removeSource(POS_Source $source): self
{
    if ($this->Source->contains($source)) {
        $this->Source->removeElement($source);
        // set the owning side to null (unless already changed)
        if ($source->getPOS() === $this) {
            $source->setPOS(null);
        }
    }

    return $this;
}

当我做

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

    $metadataAwareNameConverter = new MetadataAwareNameConverter($classMetadataFactory);

    $normalizers = [new DateTimeNormalizer(), new ArrayDenormalizer(),
        new PropertyNormalizer(), new ObjectNormalizer($classMetadataFactory, $metadataAwareNameConverter)];
    $encoders = [new XmlEncoder(), new JsonEncoder()];

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

    $encoder = new XmlEncoder();

    $output[] = $encoder->decode($data,'xml');

    dump($output);


    /**
     * @var OTA_POS $pos
     */
    $pos = $serializer->deserialize($data,POS::class,'xml');

    $posSourceArray = $serializer->deserialize($pos->getSource(),'App\POS_Source[]','xml');

    dump($posSourceArray);

它给了我POS对象,而不是它给出的POS_Source对象的集合是下面的数组。

 POS {#839 ▼
   -id: null
   -Source: array:5 [▼
     0 => array:4 [▶]
     1 => array:1 [▶]
     2 => array:1 [▶]
     3 => array:1 [▶]
     4 => array:1 [▶]
   ]
 }

如何使这项工作将对象树一直填充到底部。当我从对象结构序列化到XML时,它工作得很好。

php symfony deserialization arraycollection
3个回答
0
投票

下面是一个最小的工作示例,将XML反序列化为单个POS实例,其中包含ArrayCollectionPOS_Source实例。我抛弃了所有规范化器等,这对于反序列化这个特定的XML并不重要。

use Doctrine\Common\Collections\ArrayCollection;
use Symfony\Component\Serializer\Encoder\XmlEncoder;
use Symfony\Component\Serializer\Normalizer\ArrayDenormalizer;
use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
use Symfony\Component\Serializer\Serializer;
use Symfony\Component\PropertyInfo\Extractor\ReflectionExtractor;

class POS
{
    // ... just as in the question ...
}

/**
 * Minimal implementation of POS_Source for purposes of this deserialization example.
 */
class POS_Source
{
    private $RequestorID;

    public function setPOS(POS $POS)
    {
    }

    public function getRequestorID()
    {
        return $this->RequestorID;
    }

    public function setRequestorID($RequestorID)
    {
        $this->RequestorID = $RequestorID;
    }
}

$data = '<POS>
    <!-- ... the same XML as in the question ... -->
</POS>';

$normalizers = [
    new ArrayDenormalizer(),
    new ObjectNormalizer(null, null, null, new ReflectionExtractor())
];
$encoders = [new XmlEncoder()];

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

$pos = $serializer->deserialize($data,POS::class,'xml');
dump($pos);

打印:

POS {#14
  -Source: Doctrine\Common\Collections\ArrayCollection {#11
    -elements: array:4 [
      0 => POS_Source {#17
        -RequestorID: array:3 [
          "@Type" => 11
          "@ID" => "T921"
          "CompanyName" => array:3 [
            "@Code" => "CP"
            "@CodeContext" => "123T"
            "#" => ""
          ]
        ]
      }
      1 => POS_Source {#27
        -RequestorID: array:3 [
          "@Type" => 1
          "@ID" => 34778
          "#" => ""
        ]
      }
      2 => POS_Source {#22
        -RequestorID: array:3 [
          "@Type" => 9
          "@ID" => "ZF"
          "#" => ""
        ]
      }
      3 => POS_Source {#25
        -RequestorID: array:3 [
          "@Type" => 17
          "@ID" => "mabaan"
          "#" => ""
        ]
      }
    ]
  }
}

0
投票

这是部分答案而不是解决方案。

因此看起来反序列化不支持嵌入式php对象,并且您已创建自定义反序列化方法。

我仍在使用解决方案,但简短的回答是你必须遍历规范化的数组,然后尝试匹配属性名称。我正在尝试找到一种方法来查询对象,只查找序列化组doc块注释中包含的那些属性。


0
投票

反序列化包含其他对象的对象时,必须为ObjectNormalizer提供一个类型提取器,用于确定嵌套对象的类型。

use Symfony\Component\PropertyInfo\Extractor\ReflectionExtractor;
// ...
$normalizers = [
  new DateTimeNormalizer(),
  new ArrayDenormalizer(),
  new PropertyNormalizer(),
  new ObjectNormalizer($classMetadataFactory, $metadataAwareNameConverter, null, new ReflectionExtractor()), // added type extractor as fourth argument
];

另见the official documentation on this topic

© www.soinside.com 2019 - 2024. All rights reserved.