Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Attributes for root elements #148

Open
ilyachase opened this issue Oct 8, 2018 · 3 comments
Open

Attributes for root elements #148

ilyachase opened this issue Oct 8, 2018 · 3 comments

Comments

@ilyachase
Copy link

Hi guys. Awesome library. But I've faced problem - how can I set attributes for root elements?

Let me give you and example. I needed to build XML with following structure:

<?xml version="1.0" encoding="utf-8" ?>
<uclassify xmlns="http://api.uclassify.com/1/server/RequestSchema" version="1.00">
 <texts>
    <text id="text_1">I am happy sad bad</text>
  </texts>
  <readCalls>
    <classify id="call_1" username="uClassify" classifierName="IAB Taxonomy V2" textId="text_1" />
  </readCalls>
</uclassify>

And I didn't found the way to do two things:

  1. Set encoding attribute for <?xml version="1.0" encoding="utf-8" ?>
  2. Set version for uclassify element. This caused me problems, because server-side validator tells it's required.

I noticed that second argument of \Sabre\Xml\Service::write() function can take and render a lot of things, but as first argument it only takes a string so I couldn't set attributes for it.

@evert
Copy link
Member

evert commented Oct 20, 2018

Hi @ilyachase ,

The library is optimized for the 'happy path', while still allowing more complex features if needed.
What this means is that the common thing should be easy, but the uncommon thing should still be possible.

Writing encoding="utf-8"

This is not done, because it's the default for XML and thus unnecessary. Parsers should not need this, so we won't add a way to add this by default.

To implement this yourself, you can subclass the write() method of the Service class and call $writer->startDocument('1.0', 'utf-8'), or you can choose to use the Writer class directly instead of using the Service class.

Adding an attribute to the root element.

The easiest way to solve this is to not write a PHP array in your write() function, but pass an object instead.

Example class:

class MyRootElem implements \Sabre\Xml\XmlSerializable {
  
    public $value;

    function __construct($value) {
       $this->value = $value;
    }

    public function xmlSerialize(\Sabre\Xml\Writer $writer) {
       $writer->writeAttribute('version', '1.00');
       $writer->write($value);
    }
}

If you called this before:

$service->write('uclassify', $value);

Now you would call:

$service->write('uclassify', new MyRootElem($value));

You don't have to implement Sabre\Xml\XmlSerializable, you could alternatively also give it any other class, and use the classMap as such:

$service->classMap['MyRootElem2'] = function( $writer, $value) {
   $writer->writeAttribute('version', '1.00');
   $writer->write($value);
}
$service->write('uclassify', new MyRootElem2($value));

The difference between these 2 cases is with the classMap the serializer can live outside the class itself.

I think a nice feature request for this library could be to allow callbacks to be passed directly to the serializer, but this does NOT work today:

$service->write('uclassify', function ($writer) {
   $writer->writeAttribute('version', '1.00');
   $writer->write($value);
});

@ilyachase
Copy link
Author

I see. Thanks for the explanation. I can try to do pull request for callback if you want.

@ilyachase
Copy link
Author

@evert do you want me to try to do Pull Request?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants