3

I use Symfony 3 Serializer and convert my objects to XML through XmlEncoder. But XmlEncoder don't have encoding type in xml prolog. How to solve this problem?

Can I add custom attribut with parameters after root element?

Is there any way to set xmlns in root element?

I need such XML output:

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

Now I get this:

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

My serializer code fragment:

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

4 Answers 4

5
<?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;
Sign up to request clarification or add additional context in comments.

5 Comments

This works, but what if you need to nest multiple nodes with the same name under the root?
Can you please put XML example?
In my case what I needed was XML like this: <?xml version="1.0" encoding="utf-8"?> <shares xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <Share> <.../> </Share> <Share> <.../> </Share> </shares>
$xmlEncoder = new XmlEncoder('shares'); $xml = $xmlEncoder->encode([ '@xmlns:xsi' => 'http://www.w3.org/2001/XMLSchema-instance', 'Share' => [ '...', '...', ], ], 'xml');
Ah very cool, that's much cleaner than what I suggested. Thank you!
4

First create XmlEncoder with root node name (in your case it would be "realty-feed"):

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

Than generate Xml file:

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

Where first argument: - array with your xml structure and data

Second: - format

Third: - context properties (in your case xml_enxoding)

UPD:

Method for setting attributes to xls root element. Work perfectly. !Take into consideration return type hinting (its only for 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;
}

Output root element:

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

3 Comments

This does not allow for adding custom attributes like the OP asked for.
You can add any attribute separated by a comma
You mean like this? $encoder = new XmlEncoder('realty-feed'); $xml = $encoder->encode([], 'xml', [ 'xml_encoding' => 'utf-8', 'xmlns' => 'webmaster.yandex.ru/schemas/feed/realty/2010-06' ]); Unfortunately that just returns <?xml version="1.0" encoding="utf-8"?><realty-feed/>. The extra attribute is ignored. XmlEncoder looks for 4 specific keys in context (xml_format_output, xml_version, xml_encoding and xml_standalone). Everything else is ignored. This is definitely the cleanest way if you just want to add the encoding though.
0

I solved my problem. I created my own class and write the same methods as in default class XmlEncoder with some changes in few standart public and private methods.

    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;
    }

1 Comment

and how you set "xmlns="webmaster.yandex.ru/schemas/feed/realty/2010-06"" context?
0

On {"symfony/serializer": "^5.0"} version I was able to add those attributes in the following way:

$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;

Also tried the following way which did NOT work:

$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');

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.