【问题标题】:How do I add/update xml attributes with Symfony Serializer using my class/object?如何使用我的类/对象通过 Symfony Serializer 添加/更新 xml 属性?
【发布时间】:2018-01-26 10:43:42
【问题描述】:

我有以下代码示例,它定义了一个联系人类,该类可以保存姓名和电话号码列表。我想要做的是在所有数字上设置一个“primary”属性,其中一个任意一个的值为“1”,其余的为“0”。

我真的很想使用类方法来做到这一点,但找不到使用 setter 的方法 - 有没有可能?

这是我的代码。在里面我:

  1. 创建我的对象并设置它们的属性
  2. print_r 联系人对象以查看其存储方式
  3. 将我希望能够生成的 xml 反序列化到 相同的联系人对象
  4. print_r 联系人对象以查看其存储方式
  5. 使用 setter 添加另一个数字
  6. print_r 联系人对象以查看其存储方式
  7. 序列化为 xml,看看对象和数组的混合如何处理
  8. 打印xml

<?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;
    private $Type;
    // Getters    
    public function getNumber()
    {
        return $this->Number;
    }
    public function getType()
    {
        return $this->Type;
    }     
    // Setters    
    public function setNumber($number)
    {
        $this->Number = $number;

        return $this;
    } 
    public function setType($type)
    {
        $this->Type = $type;

        return $this;
    }                 
} 

class Contact
{
    private $Name;
    private $Numbers = array();

    function __construct() {
        ${@Primary} = 0;    
    }

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

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

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

// Serializer setup

$xmlEncoder = new XmlEncoder();
$xmlEncoder->setRootNodeName('Contact');                
$encoders = array($xmlEncoder, new JsonEncoder());
$normalizers = array(new ObjectNormalizer());
$serializer = new Serializer($normalizers, $encoders);

// Create my object

$contact = new Contact();
$contact->setName('baa');
$number = new Number();
$number->setNumber('07878386123')->setType('Mobile');
$contact->addNumber($number);

// take a look at how it's stored

echo "<pre lang=xml>";
print_r($contact);
echo "</pre><br><br>";

// deserialize my desired xml into the same object

$data = <<<EOF
<Contact>
    <Name>foo</Name>
    <Numbers>
        <Number primary='1'>
            <Number>07878386459</Number>
            <Type>Mobile</Type>
        </Number>    
        <Number primary='0'>
            <Number>02380860835</Number>
            <Type>Landline</Type>
        </Number>            
    </Numbers>        
</Contact>
EOF;

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

// take a look at how it's stored

echo "<pre lang=xml>";
print_r($contact);
echo "</pre><br><br>";

// Add another number

$number = new Number();
$number->setNumber('02387345123')->setType('Landline');
$contact->addNumber($number);

// take a look at how it's stored

echo "<pre lang=xml>";
print_r($contact);
echo "</pre><br><br>";

// serialize  to xml and see how the mixture of objects and arrays are treated

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

$dom = new domDocument( '1.0', 'utf-8' );
$dom->preserveWhiteSpace = false;
$dom->formatOutput = true;
$result = $dom->loadXML($xmlContent);
$xmlContentFormatted=htmlentities($dom->saveXML());
?>
<pre lang=xml><?= $xmlContentFormatted ?></pre>

我在输出中看到的是:

2)

Contact Object
(
    [Name:Contact:private] => baa
    [Numbers:Contact:private] => Array
        (
            [Number] => Array
                (
                    [0] => Number Object
                        (
                            [Number:Number:private] => 07878386123
                            [Type:Number:private] => Mobile
                        )   
                )   
        )   
)

4)

Contact Object
(
    [Name:Contact:private] => foo
    [Numbers:Contact:private] => Array
        (
            [Number] => Array
                (
                    [0] => Array
                        (
                            [@primary] => 1
                            [Number] => 07878386459
                            [Type] => Mobile
                        )    
                    [1] => Array
                        (
                            [@primary] => 0
                            [Number] => 02380860835
                            [Type] => Landline
                        )   
                )   

)

6) 对象和数组的混合。我可以对我的 Number 类进行编码,以便它使用数组而不是属性,并有另一种设置属性的方法吗? (例如

$number->setNumber('07878386123')->setType('Mobile')->addAttr(array('primary' => '1'));

Contact Object
(
    [Name:Contact:private] => foo
    [Numbers:Contact:private] => Array
        (
            [Number] => Array
                (
                    [0] => Array
                        (
                            [@primary] => 1
                            [Number] => 07878386459
                            [Type] => Mobile
                        )    
                    [1] => Array
                        (
                            [@primary] => 0
                            [Number] => 02380860835
                            [Type] => Landline
                        )

                    [2] => Number Object
                        (
                            [Number:Number:private] => 02387345123
                            [Type:Number:private] => Landline
                        )    
                )    
        )    
)    

8)

<?xml version="1.0"?>
<Contact>
  <Name>foo</Name>
  <Numbers>
    <Number primary="1">
      <Number>07878386459</Number>
      <Type>Mobile</Type>
    </Number>
    <Number primary="0">
      <Number>02380860835</Number>
      <Type>Landline</Type>
    </Number>
    <Number>
      <Number>02387345123</Number>
      <Type>Landline</Type>
    </Number>
  </Numbers>
</Contact>

当从具有使用属性的标签的 XML 反序列化时,php 对象使用数组,因此如果你想从一个可以被赋予属性的 php 表示开始,你需要使用数组。

【问题讨论】:

    标签: symfony xmlserializer serialization


    【解决方案1】:

    相当简单的黑客攻击,但设法找到了使其工作的方法。修改后的示例现在可以满足我的需要:

    <?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;
    
    // build datastructure as array
    Class Number { 
        private $data;
    
        public function __construct(array $attributes) {
            $data = ['Number'];
            foreach ($attributes as $name => $value) {
                $this->data['Number']['@'.$name] = $value;
            }
        }
    
        // Getters    
        public function getNumber()
        {
            return $this->data['Number']['Number'];
        }
        public function getType()
        {
            return $this->data['Number']['Type'];
        }
    
        public function get() 
        {
            return $this->data['Number'];    
        }         
        // Setters    
        public function setNumber($number)
        {
            $this->data['Number']['Number'] = $number;
    
            return $this;
        } 
        public function setType($type)
        {
            $this->data['Number']['Type'] = $type;
    
            return $this;
        }
    
    }
    
    class Contact
    {
        private $data;
    
        // Getters
        public function getName()
        {
            return $this->data['Contact']['Name'];
        }
        public function getNumbers()
        {
            return $this->data['Contact']['Numbers'];
        }
        public function get() 
        {
            return $this->data['Contact']; // this is the top level so return the Contact element, not data.    
        }      
        // Setters
        public function setName($name)
        {
            $this->data['Contact']['Name'] = $name;        
    
            return $this;        
        }
        public function setNumbers($numbers)
        {
            $this->data['Contact']['Numbers'] = $numbers;        
    
            return $this;        
        }
        public function addNumber($number) {
            $this->data['Contact']['Numbers']['Number'][] = $number;
        }    
    }
    
    // Serializer setup
    
    $xmlEncoder = new XmlEncoder();
    $xmlEncoder->setRootNodeName('Contact');                
    $encoders = array($xmlEncoder, new JsonEncoder());
    $normalizers = array(new ObjectNormalizer());
    $serializer = new Serializer($normalizers, $encoders);
    $encoder = new \Symfony\Component\Serializer\Encoder\XmlEncoder();
    
    // Create my object
    
    $contact = (new Contact)->setName('Foo Bar');
    $number = (new Number(array('primary'=>'1')))->setNumber('07878386123')->setType('Mobile');
    $number_data = $number->get();
    $contact->addNumber($number_data);
    $number = (new Number(array('primary'=>'0')))->setNumber('02380876345')->setType('Landline');
    $number_data = $number->get();
    $contact->addNumber($number_data);
    
    echo "<pre lang=xml>";
    print_r($contact);
    echo "</pre><br><br>";
    
    $xmlContent = $serializer->serialize($contact->get(), 'xml');
    
    $dom = new domDocument( '1.0', 'utf-8' );
    $dom->preserveWhiteSpace = false;
    $dom->formatOutput = true;
    $result = $dom->loadXML($xmlContent);
    $xmlContentFormatted=htmlentities($dom->saveXML());
    ?>
    <pre lang=xml><?= $xmlContentFormatted ?></pre> 
    

    输出:

    Contact Object
    (
        [data:Contact:private] => Array
            (
                [Contact] => Array
                    (
                        [Name] => Foo Bar
                        [Numbers] => Array
                            (
                                [Number] => Array
                                    (
                                        [0] => Array
                                            (
                                                [@primary] => 1
                                                [Number] => 07878386123
                                                [Type] => Mobile
                                            )
    
                                        [1] => Array
                                            (
                                                [@primary] => 0
                                                [Number] => 02380876345
                                                [Type] => Landline
                                            )
                                    )
                            )
                    )
            )
    )
    
    
    <?xml version="1.0"?>
    <Contact>
      <Name>Foo Bar</Name>
      <Numbers>
        <Number primary="1">
          <Number>07878386123</Number>
          <Type>Mobile</Type>
        </Number>
        <Number primary="0">
          <Number>02380876345</Number>
          <Type>Landline</Type>
        </Number>
      </Numbers>
    </Contact>
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-01-03
      • 2016-07-21
      • 1970-01-01
      • 2015-08-15
      • 1970-01-01
      • 1970-01-01
      • 2016-03-30
      • 1970-01-01
      相关资源
      最近更新 更多