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

时间:2018-01-25 12:18:50

标签: symfony xmlserializer serializer

我有以下测试用例,但我发现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并首先使用地址提交,那么每个人都很高兴。

所以我需要在Numbers标签之前添加Address标签。这是我必须在Normalizing阶段或XmlEncoding阶段控制的东西吗?

任何人都可以使用下面的简单示例解释我是如何做到这一点的,我可以在生成的xml中的Numbers标记之前获取Address标记吗?

<?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>

1 个答案:

答案 0 :(得分:2)

又快又脏:

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

现在清除序列化程序和/或opcache-cache,并享受XML输出中更改的顺序。