sabre-xml-atom not compatible with Sabre\XML 2.0.0

58 views
Skip to first unread message

dandy.w...@gmail.com

unread,
Jan 3, 2017, 3:09:11 PM1/3/17
to SabreDAV Discussion
Hi Evert,

I have to write a custom XML deserializer and wanted to learn from and build on your sample ATOM implemenation on GitHub and Packagist .

Unfortunately, sabre-xml-atom is not compatible with the latest version of Sabre\XML, version 2.0.0. Here's the message I get from composer when I try to install Sabre-XML-Atom (I am running on PHP 7.0.4 and sabre\xml 2.0.0):

composer require sabre/xml-atom

Your requirements could not be resolved to an installable set of packages.

 
Problem 1
   
- Installation request for sabre/xml-atom ^0.1.0 -> satisfiable by sabre/xml-atom[0.1.0].
   
- sabre/xml-atom 0.1.0 requires sabre/xml ^1.4.0 -> satisfiable by sabre/xml[1.4.0, 1.4.1, 1.4.2, 1.4.x-dev, 1.5.0, 1.5.x-dev] but these conflict with your requirements or minimum-stability.

Installation failed, reverting ./composer.json to its original content.


Would you be able to make your Atom sample implementation compatible with Sabre\XML 2.0.0.? A working reference implementation would be extremely useful for building a custom XML deserializer.

Thanks,
Christoph

Evert Pot

unread,
Jan 3, 2017, 6:36:52 PM1/3/17
to SabreDAV Discussion
I just release sabre/xml-atom 0.2.0 which requires sabre/xml 2 and php 7. No real changes were needed thankfully. Hope it helps!

Evert


dandy.w...@gmail.com

unread,
Jan 4, 2017, 3:50:49 PM1/4/17
to SabreDAV Discussion
Hi Evert,

thanks for the quick solution. I was able to download the updated package from GitHub and got it to work (however, I am still not able to install it via Composer - same error message as before).

I am looking at your sabre\xml-atom reference implementation now. I may be mistaken, but as far as I can see you are parsing either (1)  the values or (2) the attributes of elements. For exmpale:

(1) Value of an element
<title ">dive into mark</title>  

...where "dive into mark" is the value of the "title" element


(2) Attribute of an element

<link rel="alternate" type="text/html"
 
hreflang="en" href="http://example.org/"/>  

// where "http://example.org/" is the "href" attribute of the "link" element.


However, as far as I can see you are not parsing both (1) the VALUE and (2) all ATTRIBUTES of the same singular element. For example:

<title type="text">dive into mark</title>

// where "dive into mark" is the value of the "title" element and "text" is the "type" attribute of the "title" element.


I may miss the point somewhere, but that's my impression when I'm looking at "reading-test1.php" of your sabre/xml-atom package.

How can you parse both the value and the attributes of the same element?

Thanks!
Christoph

Evert Pot

unread,
Jan 4, 2017, 8:31:47 PM1/4/17
to SabreDAV Discussion
It depends a bit on what you are trying to parse it into. If your only goal is to get a PHP array, you can simply not map the title element. The default structure sabre/xml always give you for that element is this:

[
"name" => "title",
"value" => "dive into mark",
"attributes" => ["type" => "text"]
]

It's only when you use one of the default 'deserializers' that you get different structures. In the sabre/xml-atom example there's two major ones used:

1. The valueObject mapper, which is a standard sabre/xml built-in one that maps PHP classes and properties to XML elements and child elements.
2. An attributeReader/attributeWriter which in the case of sabre/xml-atom is a custom one.

So if you have an xml tag that you want to extract both an attribute and a value from, and you hypothetically would want to map that to a PHP class like this:

class Title {

    public $title;
    public $value;

}

The correct sabre/xml solution is to write a custom parser like this:

$server->elementMap['{myNamespace}title'] = function($reader) {
    $result = new Title();
    $result->type = $reader->getAttribute('type');
    $result->value = $reader->readText();
    $reader->next();
    return $result;
};




dandy.w...@gmail.com

unread,
Jan 5, 2017, 3:33:45 PM1/5/17
to SabreDAV Discussion
Thanks for your explanation. However, somehow I can't get it to work.

This is my adoption for your xml-atom parser.

feed.php

class Feed {

   
public $subtitle;

}

class Subtitle {

   
public $type;
   
public $value;

}




service.php

        $this
->mapValueObject($atom . 'subtitle', Element\Subtitle::class);

        $this
->elementMap[$atom . 'Subtitle'] = function($reader) {
           $result
= new Subtitle();

           $result
->type = $reader->getAttribute('type');
           $result
->value = $reader->readText();
           $reader
->next();
           
return $result;
         
};


However, I only get a blank result:

 
[subtitle] => Sabre\Xml\Atom\Element\Subtitle Object
 
(
 
[type] =>
 
[value] =>
 
)


what am I doing wrong?



dandy.w...@gmail.com

unread,
Jan 5, 2017, 3:34:43 PM1/5/17
to SabreDAV Discussion
btw. I am trying to parse the following element:

 <subtitle type="html">
   A &lt;em&gt;lot&lt;/em&gt; of effort
   went into making this effortless
 
</subtitle>





Evert Pot

unread,
Jan 5, 2017, 4:16:16 PM1/5/17
to sabredav...@googlegroups.com
There's a few issues left:

On Thu, Jan 5, 2017, at 03:33 PM, dandy.w...@gmail.com wrote:
> Thanks for your explanation. However, somehow I can't get it to work.
>
> This is my adoption for your xml-atom parser.
>
> *feed.php*
>
> class Feed {
>
> public $subtitle;
>
> }
>
> class Subtitle {
>
> public $type;
> public $value;
>
> }
>
>
>
>
> *service.php*
>
> $this->mapValueObject($atom . 'subtitle',
> Element\Subtitle::class);
>
> $this->elementMap[$atom . 'Subtitle'] = function($reader) {
> $result = new Subtitle();
> $result->type = $reader->getAttribute('type');
> $result->value = $reader->readText();
> $reader->next();
> return $result;
> };
>
>
> However, I only get a blank result:
>
> [subtitle] => Sabre\Xml\Atom\Element\Subtitle Object
> (
> [type] =>
> [value] =>
> )
>
>
>
> what am I doing wrong?

You are registering the 'subtitle' element as BOTH a valueObject as well
as in the elementMap. You can only do one. valueObject internally uses
the elementMap.

You only need to change 2 things:

1. Remove this line: $this->mapValueObject($atom . 'subtitle',
Element\Subtitle::class);

Fix the capitalization of 'subtitle' in this line:

$this->elementMap[$atom . 'Subtitle'] = function($reader) {

Evert



>
>
>
> --
> You received this message because you are subscribed to the Google Groups
> "SabreDAV Discussion" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to sabredav-discu...@googlegroups.com.
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/sabredav-discuss/efc264b0-0de7-401f-969c-683d3fcb1cf8%40googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.

dandy.w...@gmail.com

unread,
Jan 5, 2017, 5:47:42 PM1/5/17
to SabreDAV Discussion
Thanks Evert, but for some reason it still doesn' work.

I have removed this line:   $this->mapValueObject($atom . 'subtitle', Element\Subtitle::class);
I have also fixed the capitalisation of subtitle.

Here's what I've got now:

feed.php

class Feed {

//....

   
public $subtitle;

}

class Subtitle {

   
public $type;
   
public $value;

}


Service.php


       
// atom:subtitle
        $this
->elementMap[$atom . 'subtitle'] = function($reader) {

           $result
= new Subtitle();
           $result
->type = $reader->getAttribute('type');
           $result
->value = $reader->readText();
           $reader
->next();
           
return $result;
         
};


However, this returns the following error:


Fatal error: Uncaught Error: Class 'Sabre\Xml\Atom\Subtitle' not found in /home/he052rz5/www/home/sabre-xml-atom/lib/Service.php:94 Stack trace: #0 [internal function]: Sabre\Xml\Atom\Service->Sabre\Xml\Atom\{closure}(Object(Sabre\Xml\Reader)) #1 /home/he052rz5/www/home/vendor/sabre/xml/lib/Reader.php(229): call_user_func(Object(Closure), Object(Sabre\Xml\Reader)) #2 /home/he052rz5/www/home/vendor/sabre/xml/lib/Deserializer/functions.php(190): Sabre\Xml\Reader->parseCurrentElement() #3 /home/he052rz5/www/home/vendor/sabre/xml/lib/Service.php(220): Sabre\Xml\Deserializer\valueObject(Object(Sabre\Xml\Reader), 'Sabre\\Xml\\Atom\\...', 'http://www.w3.o...') #4 [internal function]: Sabre\Xml\Service->Sabre\Xml\{closure}(Object(Sabre\Xml\Reader)) #5 /home/he052rz5/www/home/vendor/sabre/xml/lib/Reader.php(229): call_user_func(Object(Closure), Object(Sabre\Xml\Reader)) #6 /home/he052rz5/www/home/vendor/sabre/xml/lib/Reader.php(71): Sabre\Xml\Reader->parseCurrentElement() #7 /home/he052rz5/www/home/vendor/sabre/xml/lib/Service.php in /home/he052rz5/www/home/sabre-xml-atom/lib/Service.php on line 94


Line 94 in Service.php is this one: $result = new Subtitle();

For your reference, I am also attaching the complete feed.php and Service.php files.

Thanks for your help!


atom_test.zip

m...@evertpot.com

unread,
Jan 5, 2017, 6:09:27 PM1/5/17
to sabredav...@googlegroups.com
At this point you should learn how PHP namespaces work. This goes a bit beyond the support I can offer you... 

--
You received this message because you are subscribed to the Google Groups "SabreDAV Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to sabredav-discu...@googlegroups.com.

dandy.w...@gmail.com

unread,
Jan 6, 2017, 2:41:21 AM1/6/17
to SabreDAV Discussion
Got it, the class 'Subtitle' is defined in the 'Sabre\Xml\Atom\Element\' namespace, but Service.php works in the 'Sabre\Xml\Atom\' namespace. So all I had to do was add the 'Element\' namespace:

        // atom:subtitle
        $this
->elementMap[$atom . 'subtitle'] = function($reader) {

           $result
= new Element\Subtitle();

           $result
->type = $reader->getAttribute('type');
           $result
->value = $reader->readText();
           $reader
->next();
           
return $result;
         
};

which produces:

    [subtitle] => Sabre\Xml\Atom\Element\Subtitle Object
        (
            [type] => html
            [value] => 
   A lot of effort
   went into making this effortless
 
        )


Works like a charm now. Thanks!

Reply all
Reply to author
Forward
0 new messages