使用属性序列化XML文档

时间:2015-01-05 10:30:53

标签: php xml symfony serialization

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

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

  • $ companyId
  • $的companyName

问题在于,而不是像我这样的XML文档:

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

我有这样的事情:

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

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

是否有一种简单的方法可以像我想要的那样使封闭过程成本化?或者我必须实现完全独立的方法吗?

非常感谢。

3 个答案:

答案 0 :(得分:4)

我创建了一个简单的Denormalizer因为默认情况下已经解析了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"
}

答案 1 :(得分:1)

通过使用带有@的@SerializeName批注,现在更容易序列化XML属性。

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

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

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

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

答案 2 :(得分:0)

好的,所以最后我尝试使用JMSSerializerBundle,但我的情况太复杂了。我有许多实体与几个ManyToOne关系;我在我的XML中获得了bot标准和属性值。

所以我会用你的想法:创建我完整的整个Denormalizer。它将使用已解码的XML并逐行读取,执行它必须执行的操作(使用Doctrine创建实体)。

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

谢谢。

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

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

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

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