使用属性序列化 XML 文档


Serialize XML document with attributes

我正在尝试序列化一个XML文档,其中包含要插入到Doctrine MySQL数据库中的实体。

例如,我在我的实体中获得了这两个属性:

  • $companyId
  • $companyName

问题是我的XML文档不是这样的东西:

<company>
    <id>8888</id>
    <name>MyCompany</name>
</company>

我得到了这样的东西:

<company id="8888" name="MyCompany"/>

XML是由我合作的一家独立公司生成的,所以我无法更改它。因此,Symfony2 序列化程序正在创建一个空的 $company 属性:(

有没有一种简单的方法可以像我想要的那样对锯齿化过程进行修饰?还是我必须实现一个完全独立的方法?

多谢。

现在,

通过使用带有"@"的@SerializeName注释来序列化 XML 属性要容易得多

在您的公司实体中,定义$name时,添加

    /**
     * @ORM'Column(type="string", length=255)
     * @SerializedName('@name')
     */
    private $name;

现在,当您序列化为 XML 时,它将按预期作为属性出现。

我知道 OP 实际上是在询问反序列化,但希望这对正在搜索的人有所帮助。

我会创建一个简单的反规范化程序,因为默认情况下 XmlEncoder 已经解析了属性。它会在密钥的开头添加一个特殊字符@

无需进行大量调整,即可添加自定义非规范化程序可以理解的上下文参数,例如use_attributes。下面是一个示例

use Symfony'Component'Serializer'Normalizer'DenormalizerInterface;
class AttributesDenormalizer implements DenormalizerInterface
{
    public function __construct(DenormalizerInterface $delegate)
    {
        $this->delegate = $delegate;
    }
    public function denormalize($data, $class, $format = null, array $context = array())
    {
        if (!is_array($data) || !isset($context['use_attributes']) || true !== $context['use_attributes']) {
            return $this->delegate->denormalize($data, $class, $format, $context);
        }
        $attributes = array();
        foreach ($data as $key => $value) {
            if (0 === strpos($key, '@')) {
                $attributes[substr($key, 1)] = $value;
            }
        }
        if (empty($attributes)) {
            $attributes = $data;
        }
        return $this->delegate->denormalize($attributes, $class, $format, $context);
    }
    public function supportsDenormalization($data, $type, $format = null)
    {
        return $this->delegate->supportsDenormalization($data, $type, $format);
    }
}

这是一个用法示例

use Symfony'Component'Serializer'Serializer;
use Symfony'Component'Serializer'Encoder'XmlEncoder;
use Symfony'Component'Serializer'Normalizer'GetSetMethodNormalizer;
$xml = '<company id="8888" name="MyCompany"/>';
$encoders = array(new XmlEncoder());
$normalizers = array(new AttributesDenormalizer(new GetSetMethodNormalizer));
$serializer = new Serializer($normalizers, $encoders);
$serializer->deserialize($xml, 'Company', 'xml', array('use_attributes' => true));

这导致

class Company#13 (2) {
  protected $id =>
  string(4) "8888"
  protected $name =>
  string(9) "MyCompany"
}
好的,

最后我尝试使用 JMSSerializerBundle,但我的情况太复杂了。我得到了许多具有多个多对一关系的实体;我在我的 XML 中获得了机器人标准和属性值。

所以我会用你的想法:创建我完整的去规范化器。它将使用解码的XML并逐行读取它,做它必须做的事情(使用Doctrine创建实体)。

这将是一个巨大的过程,但却是最简单的过程。

谢谢。

[编辑] 我终于找到了一个很好的解决方案。我将 XML 和我的实体资源库之间的链接注册到 yaml 表中

company:
    @id: setCompanyId
    @name : setCompanyName
    address:
        @city: setAddressCity
        @street: setAddressStreet
...

多亏了这一点,我可以轻松地读取我的整个 XML,对于每个节点/属性值,在表中找到 setter 名称,然后执行以下操作:

$company = new Company;
$company->setterNameFromTable($value);

很老了,但我在注释中使用 Serializator + xpath得到了一个更简单的解决方案SerializedName所以这对某人可能很有用。

例如,具有此条目 XML:

<root>
    <company id="123456"/>
</root>

在反序列化为对象时,您可以使用此注释将公司 ID 填充到"id"属性中:

/**
 * @Serializer'SerializedName(name="company/@id")
 */
public ?int $id = null;

PS:在Symfony 5.4上测试