【问题标题】:How set encoding UTF-8 and the xmlns attribute in Symfony XmlEncoder如何在 Symfony XmlEncoder 中设置编码 UTF-8 和 xmlns 属性
【发布时间】:2018-05-11 11:03:34
【问题描述】:

我使用 Symfony 3 Serializer 并通过 XmlEncoder 将我的对象转换为 XML。但是 XmlEncoder 在 xml prolog 中没有编码类型。如何解决这个问题?

我可以在根元素之后添加带有参数的自定义属性吗?

有没有办法在根元素中设置 xmlns?

我需要这样的 XML 输出:

<?xml version="1.0" encoding="utf-8"?>
<realty-feed xmlns="http://webmaster.yandex.ru/schemas/feed/realty/2010-06">
<generation-date>2010-10-05T16:36:00+04:00</generation-date> 
...
</realty-feed>

现在我明白了:

<?xml version="1.0"?>
<realty-feed>
...
</realty-feed>

我的序列化代码片段:

$xmlEncoder = new XmlEncoder('realty-feed');
$normalizer = new CustomNormalizer();
$serializer = new Serializer(array($normalizer),array($xmlEncoder));
$output = $serializer->serialize($objectData, 'xml');

【问题讨论】:

    标签: xml symfony xmlserializer serialization


    【解决方案1】:
    <?php
    $xmlEncoder = new XmlEncoder('realty-feed');
    $xml = $xmlEncoder->encode([
        '@xmlns'          => 'http://webmaster.yandex.ru/schemas/feed/realty/2010-06',
        'generation-date' => '2010-10-05T16:36:00+04:00',
    ], 'xml');
    echo $xml;
    

    【讨论】:

    • 这个可行,但是如果你需要在根下嵌套多个同名节点怎么办?
    • 你能举个XML例子吗?
    • 就我而言,我需要的是这样的 XML:&lt;?xml version="1.0" encoding="utf-8"?&gt; &lt;shares xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"&gt; &lt;Share&gt; &lt;.../&gt; &lt;/Share&gt; &lt;Share&gt; &lt;.../&gt; &lt;/Share&gt; &lt;/shares&gt;
    • $xmlEncoder = new XmlEncoder('shares'); $xml = $xmlEncoder-&gt;encode([ '@xmlns:xsi' =&gt; 'http://www.w3.org/2001/XMLSchema-instance', 'Share' =&gt; [ '...', '...', ], ], 'xml');
    • 啊非常酷,这比我建议的要干净得多。谢谢!
    【解决方案2】:

    首先使用根节点名称创建 XmlEncoder(在您的情况下,它将是“realty-feed”):

    $encoder = new XmlEncoder("realty-feed");
    

    比生成Xml文件:

    $xml = $encoder->encode([], 'xml', ['xml_encoding' => 'utf-8']);
    

    第一个参数在哪里: - 包含您的 xml 结构和数据的数组

    第二: - 格式

    第三: - 上下文属性(在您的情况下为 xml_enxoding)

    UPD

    为 xls 根元素设置属性的方法。完美工作。 !考虑返回类型提示(仅适用于 PHP 7+)

    /**
     * Add params to xml root element
     *
     * @param $xml
     * @return SimpleXMLElement
     */
    private function setXmlParams(SimpleXMLElement $xml): SimpleXMLElement
    {
        $xml = new \SimpleXMLElement($xml);
        $xml->addAttribute('xmlns:xmlns:xsi', "http://www.w3.org/2001/XMLSchema-instance");
        $xml->addAttribute('xmlns:xmlns:xsd', "http://www.w3.org/2001/XMLSchema");
        $xml->addAttribute('xmlns', "http://localhost/example");
    
        return $xml;
    }
    

    输出根元素:

    <Root 
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xmlns:xsd="http://www.w3.org/2001/XMLSchema"
         xmlns="http://localhost/example"
    >
    

    【讨论】:

    • 这不允许像 OP 要求的那样添加自定义属性。
    • 您可以添加任何以逗号分隔的属性
    • 你的意思是这样的? $encoder = new XmlEncoder('realty-feed'); $xml = $encoder->encode([], 'xml', [ 'xml_encoding' => 'utf-8', 'xmlns' => 'webmaster.yandex.ru/schemas/feed/realty/2010-06' ]);不幸的是,这只是返回 。额外的属性被忽略。 XmlEncoder 在上下文中查找 4 个特定键(xml_format_output、xml_version、xml_encoding 和 xml_standalone)。其他一切都被忽略。如果您只想添加编码,这绝对是最干净的方法。
    【解决方案3】:

    我解决了我的问题。 我创建了自己的类并编写了与默认类 XmlEncoder 中相同的方法,但对一些标准的公共和私有方法进行了一些更改。

        class N1XmlEncoder extends SerializerAwareEncoder implements EncoderInterface, DecoderInterface, NormalizationAwareInterface
        {
            ...
    
            /**
             * {@inheritdoc}
             */
            public function encode($data, $format, array $context = array())
            {
                if ($data instanceof \DOMDocument) {
                    return $data->saveXML();
                }
    
                $xmlRootNodeName = $this->resolveXmlRootName($context);
    
                $this->dom = $this->createDomDocument($context);
                $this->format = $format;
                $this->context = $context;
    
                if (null !== $data && !is_scalar($data)) {
                    $root = $this->dom->createElementNS('http://webmaster.yandex.ru/schemas/feed/realty/2010-06', $xmlRootNodeName);
                    $dateTime = new \DateTime('now');
                    $dateTimeStr = $dateTime->format(DATE_ATOM);
                    $rootDate = $this->dom->createElement('generation-date', $dateTimeStr);
                    $this->dom->appendChild($root);
                    $root->appendChild($rootDate);
                    $this->buildXml($root, $data, $xmlRootNodeName);
                } else {
                    $this->appendNode($this->dom, $data, $xmlRootNodeName);
                }
    
                return $this->dom->saveXML();
            }
    ...
    private function createDomDocument(array $context)
        {
            $document = new \DOMDocument('1.0','utf-8');
    
            // Set an attribute on the DOM document specifying, as part of the XML declaration,
            $xmlOptions = array(
                // nicely formats output with indentation and extra space
                'xml_format_output' => 'formatOutput',
                // the version number of the document
                'xml_version' => 'xmlVersion',
                // the encoding of the document
                'xml_encoding' => 'encoding',
                // whether the document is standalone
                'xml_standalone' => 'xmlStandalone',
            );
            foreach ($xmlOptions as $xmlOption => $documentProperty) {
                if (isset($context[$xmlOption])) {
                    $document->$documentProperty = $context[$xmlOption];
                }
            }
    
            return $document;
        }
    

    【讨论】:

    【解决方案4】:

    {"symfony/serializer": "^5.0"} 版本中,我可以通过以下方式添加这些属性:

    $encoder = new XmlEncoder();
    $nodes = ['@xmlns' => 'http://webmaster.yandex.ru/schemas/feed/realty/2010-06',
              'generation-date' => '2010-10-05T16:36:00+04:00'];
    $xmlString = $encoder->encode($nodes, 'xml', [
        XmlEncoder::ROOT_NODE_NAME => 'realty-feed',
        XmlEncoder::ENCODING       => 'UTF-8',
    ]); 
    echo $xmlString;
    

    还尝试了以下不起作用的方法:

    $encoder = new XmlEncoder([
    XmlEncoder::ROOT_NODE_NAME => $rootNodeName,
    XmlEncoder::ENCODING       => $encoding,
    '@xmlns' => 'http://webmaster.yandex.ru/schemas/feed/realty/2010-06',
    ]);
    
    echo $encoder->encode($nodes, 'xml');
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-03-08
      • 2010-10-26
      • 2017-01-02
      • 1970-01-01
      • 1970-01-01
      • 2018-02-17
      相关资源
      最近更新 更多