symfony - 使用 Symfony Serialiser 创建 XML 时如何控制标签排序?

标签 symfony xmlserializer serialization

我有以下测试用例,但我发现 XML 部分没有按照我需要的顺序出现。我正在使用的 SOAP API 发出了此消息:

<Search Type="Error">
    <ErrorCode>150</ErrorCode>
    <ErrorMessage>Invalid Entry : Invalid content was found starting with element &apos;Telephones&apos;. One of &apos;{Addresses}&apos; is expected. </ErrorMessage>
</Search 

如果我编辑 XML 并首先使用地址提交它,那么每个人都会很高兴。

所以我需要将地址标签放在数字标签之前。这是我必须在规范化阶段或 XmlEncoding 阶段控制的事情吗?

任何人都可以解释我如何使用下面的简单示例来实现这一点,在该示例中我可以在生成的 xml 中将 Address 标记置于 Numbers 标记之前?

<?php
/**
* Symfony Serializer experiment  
*/
require $_SERVER['DOCUMENT_ROOT'].'/libraries/symfony/vendor/autoload.php';

use Symfony\Component\Serializer\Serializer;
use Symfony\Component\Serializer\Encoder\XmlEncoder;
use Symfony\Component\Serializer\Encoder\JsonEncoder;
use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
use Symfony\Component\Serializer\Normalizer\ArrayDenormalizer;

Class Number {
    private $Number;

    // Getters    
    public function getNumber()
    {
        return $this->Number;
    }
    // Setters    
    public function setNumber($number)
    {
        $this->Number = $number;

        return $this;  // for chaining
    }    

}

Class Address {
    private $Premise;
    Private $Postcode;

    // Getters    
    public function getPremise()
    {
        return $this->Premise;
    }
    public function getPostcode()
    {
        return $this->Postcode;
    }    
    // Setters    
    public function setPremise($premise)
    {
        $this->Premise = $premise;

        return $this; // for chaining
    }
    public function setPostcode($postcode)
    {
        $this->Postcode = $postcode;

        return $this; // for chaining
    }              
} 

class Contact
{
    private $Name;
    private $Numbers;
    private $Address;

    // Getters
    public function getName()
    {
        return $this->Name;
    }
    public function getNumbers()
    {
        return $this->Numbers;
    }
    public function getAddress()
    {
        return $this->Address;
    }        
    // Setters
    public function setName($name)
    {
        $this->Name = $name;

        return $this;  // for chaining       
    }
    public function setNumbers($numbers)
    {
        $this->Numbers = $numbers;

        return $this;  // for chaining       
    }
    public function setAddress($address)
    {
        $this->Address = $address;

        return $this;  // for chaining       
    }    
    public function addNumber($number) {
        $this->Numbers['Number'][] = $number;

        return $this;  // for chaining
    }    
}

// Serializer setup

// The default Root tag for the XmlEncode is <response>. Not what we want so let's change it to <Contact>
$xmlEncoder = new XmlEncoder();
$xmlEncoder->setRootNodeName('Contact');                
$encoders = array($xmlEncoder, new JsonEncoder());       
$normalizers = array(new ObjectNormalizer(), new ArrayDenormalizer());
$serializer = new Serializer($normalizers, $encoders);
// The default Root tag for the XmlEncode is <response>. Not what we want so let's change it to <Contact>
$xmlEncoder = new XmlEncoder();
$xmlEncoder->setRootNodeName('Contact');                
$encoders = array($xmlEncoder, new JsonEncoder());
$normalizers = array(new ObjectNormalizer(), new ArrayDenormalizer());
$serializer = new Serializer($normalizers, $encoders);

// First test we can get from php data structure to xml

$address = new Address();
$address->setPremise('11')
->setPostcode('ZZ99 9ZZ');

$contact = new Contact();
$contact->setName('baa')
->addNumber('9876543210')
->addNumber('9876543212')
->setAddress($address);

$xmlContent = $serializer->serialize($contact, 'xml');

echo "<pre lang=xml>";
echo htmlentities($xmlContent);
echo "</pre><br><br>";     

// Next lets test we can get from xml to php

$data = <<<EOF
<Contact>
    <Name>foo</Name>
    <Address>
        <Premise>12</Premise>
        <Postcode>YY88 8YY</Postcode>
    </Address>
    <Numbers>
        <Number>02378415326</Number>
        <Number>07865412354</Number>        
    </Numbers>        
</Contact>
EOF;

//$jsonContent = $serializer->serialize($searchId, 'json');

$contact = $serializer->deserialize($data, Contact::class, 'xml');

$contact->addNumber('01234567890');

$xmlContent = $serializer->serialize($contact, 'xml');

echo "<pre lang=xml>";
echo htmlentities($xmlContent);
echo "</pre>";     
    ?>

输出:

<Contact>
    <Name>baa</Name>
    <Numbers>
        <Number>9876543210</Number>
        <Number>9876543212</Number>
    </Numbers>
    <Address>
        <Premise>11</Premise>
        <Postcode>ZZ99 9ZZ</Postcode>
    </Address>
</Contact>

<?xml version="1.0"?>
<Contact>
    <Name>foo</Name>
    <Numbers>
        <Number>02378415326</Number>
        <Number>07865412354</Number>
        <Number>01234567890</Number>
    </Numbers>
    <Address>
        <Premise>12</Premise>
        <Postcode>YY88 8YY</Postcode>
    </Address>
</Contact>

最佳答案

快速而肮脏:

您需要做的就是在 Contact 类中更改属性和/或 getter 方法的顺序(具体取决于您的属性访问器类型)。

现在清除序列化器和/或 opcache 缓存并享受 XML 输出中更改后的顺序。

关于symfony - 使用 Symfony Serialiser 创建 XML 时如何控制标签排序?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48442716/

相关文章:

php - 显示真实内容,而不是 HTML 标签和内联 CSS 包裹的内容

php - 使用学说的 Symfony 4 工作人员无法正常工作 : SQLSTATE[HY000] [2002] Connection timed out

c# - XmlSerializer 没有序列化我的类中的所有内容

C# XmlSerializer 绑定(bind)失败

c# - 在不使用 $type 的情况下在 JSON.NET 中序列化字节数组

php - Symfony3 自定义验证约束与参数抛出异常

symfony - 在 Vagrant 上使用 Composer 时出现错误 "could not delete"

c# - char 的数据契约反序列化问题 - C#

c# - 序列化时出现 JSON.NET StackOverflowException

java - 是否可以使用我的自定义序列化或使用外部化来序列化类的 transient 字段?