序列化 XML 个具有属性的文档
Serialize XML document with attributes
我正在尝试序列化包含要插入到 Doctrine MySQL 数据库中的实体的 XML 文档。
例如,我的实体中有这两个属性:
- $公司编号
- $公司名称
问题是我的 XML 文档中没有这样的东西:
<company>
<id>8888</id>
<name>MyCompany</name>
</company>
我得到了这样的东西:
<company id="8888" name="MyCompany"/>
XML 是由我合作的一家独立公司生成的;所以我不能改变它。
所以 Symfony2 序列化器正在创建一个空的 $company
属性 :(
有没有一种简单的方法可以像我想要的那样定制序列化过程?还是我必须实现一个完整的独立方法?
非常感谢。
我会创建一个简单的 Denormalizer because attributes are already parsed by default 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,但我的情况太复杂了。我得到了许多具有多个 ManyToOne 关系的实体;我在 XML.
中获得了机器人标准和属性值
所以我会使用你的想法:创建我完整的整个 Denormalizer。它将使用解码后的 XML 并逐行读取它,做它必须做的事情(用 Doctrine 创建实体)。
这将是一个巨大的过程,但也是最简单的过程。
谢谢。
[编辑] 我终于找到了一个很好的解决方案。
我将 XML 和我的实体 setters 之间的链接注册到 yaml table
company:
@id: setCompanyId
@name : setCompanyName
address:
@city: setAddressCity
@street: setAddressStreet
...
多亏了它,我可以轻松地读取整个 XML,并且对于每个 node/attribute 值,在 table 中找到 setter 名称,然后执行以下操作:
$company = new Company;
$company->setterNameFromTable($value);
现在 更容易序列化 XML 属性,方法是使用带有“@”的 @SerializeName 注释。
在您的 Company 实体中,定义 $name 时,添加
/**
* @ORM\Column(type="string", length=255)
* @SerializedName('@name')
*/
private $name;
现在,当您序列化为 XML 时,它会像预期的那样作为 属性 出现。
我知道 OP 实际上是在询问反序列化,但希望这对正在搜索的人有所帮助。
很老,但我在 SerializedName
注释中使用 Serializator
+ xpath
得到了一个更简单的解决方案,所以这可能对某些人有用。
例如这个条目 XML:
<root>
<company id="123456"/>
</root>
反序列化为对象时,您可以使用此注释将公司 ID 填充到“id”中 属性:
/**
* @Serializer\SerializedName(name="company/@id")
*/
public ?int $id = null;
PS:在 Symfony 5.4
上测试
我正在尝试序列化包含要插入到 Doctrine MySQL 数据库中的实体的 XML 文档。
例如,我的实体中有这两个属性:
- $公司编号
- $公司名称
问题是我的 XML 文档中没有这样的东西:
<company>
<id>8888</id>
<name>MyCompany</name>
</company>
我得到了这样的东西:
<company id="8888" name="MyCompany"/>
XML 是由我合作的一家独立公司生成的;所以我不能改变它。
所以 Symfony2 序列化器正在创建一个空的 $company
属性 :(
有没有一种简单的方法可以像我想要的那样定制序列化过程?还是我必须实现一个完整的独立方法?
非常感谢。
我会创建一个简单的 Denormalizer because attributes are already parsed by default 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,但我的情况太复杂了。我得到了许多具有多个 ManyToOne 关系的实体;我在 XML.
中获得了机器人标准和属性值所以我会使用你的想法:创建我完整的整个 Denormalizer。它将使用解码后的 XML 并逐行读取它,做它必须做的事情(用 Doctrine 创建实体)。
这将是一个巨大的过程,但也是最简单的过程。
谢谢。
[编辑] 我终于找到了一个很好的解决方案。 我将 XML 和我的实体 setters 之间的链接注册到 yaml table
company:
@id: setCompanyId
@name : setCompanyName
address:
@city: setAddressCity
@street: setAddressStreet
...
多亏了它,我可以轻松地读取整个 XML,并且对于每个 node/attribute 值,在 table 中找到 setter 名称,然后执行以下操作:
$company = new Company;
$company->setterNameFromTable($value);
现在 更容易序列化 XML 属性,方法是使用带有“@”的 @SerializeName 注释。
在您的 Company 实体中,定义 $name 时,添加
/**
* @ORM\Column(type="string", length=255)
* @SerializedName('@name')
*/
private $name;
现在,当您序列化为 XML 时,它会像预期的那样作为 属性 出现。
我知道 OP 实际上是在询问反序列化,但希望这对正在搜索的人有所帮助。
很老,但我在 SerializedName
注释中使用 Serializator
+ xpath
得到了一个更简单的解决方案,所以这可能对某些人有用。
例如这个条目 XML:
<root>
<company id="123456"/>
</root>
反序列化为对象时,您可以使用此注释将公司 ID 填充到“id”中 属性:
/**
* @Serializer\SerializedName(name="company/@id")
*/
public ?int $id = null;
PS:在 Symfony 5.4
上测试