Reference an element based on one of its attributes in mapValueObject

23 views
Skip to first unread message

dandy.w...@gmail.com

unread,
Jan 6, 2017, 1:35:54 PM1/6/17
to SabreDAV Discussion
Hi Evert,

I have been working with Sabre-XML for most of the day, but I'm stuck now.

I have a nested XML file and I would like to map that into a PHP class, for which I am using the mapValueObject system. This works pretty well so far.

At one point my XML file lists elements called "Category". Each category has an attribute "Number", which defines the category. Within each Category element, there are various sub-elements.

          <Category Number="03">
            .......
         
</Category>

         
<Category Number="04">
            ......
         
</Category>

          <Category Number="05">
            ......
         
</Category>


However, the subelements in "Category 3" have absolutely nothing to do with those in "Category 4", and they both have nothing in common with the sub-elements in "Category 5". Therefore, I would like to create a custom class for each Category:

Class Category3 {
....
}

Class Category4 {
....
}

Class Category5 {
....
}


However, here's the catch: I am not able to define the "Number" attribute for the Category in the mapValueObject call. In very simple terms, I am trying to accomplish something like this:

$this->mapValueObject($atom . 'Category'[Number='03'], Element\Category3::class);

Is there any way to do this? I'm sorry if I'm being a pest, but I'd appreciate if you could point me towards the right direction. I've been stuck at this point for hours.



Evert Pot

unread,
Jan 7, 2017, 8:41:50 PM1/7/17
to SabreDAV Discussion
Hi!

mapValueObject can only map 1 element to 1 class. It's really designed for the simplest use-cases. As soon as your needs are a bit more advanced, you need to write your own deserializers.
This particular problem I would solve as follows:

use Sabre\Xml;

$service
->elementMap[$atom . 'Category'] = function(Xml\Reader $reader) use ($atom) {

  $number
= $reader->getAttribute('Number');
 
switch($number) {
     
case '03' :
       
return Xml\Deserializer\valueObject($reader, 'Category3', $atom);
     case '04' :
       
return Xml\Deserializer\valueObject($reader, 'Category4', $atom);

 
}
};

Remember that a custom deserializer like this really just a function that gets a Reader as an argument and returns 'something'. In this case we are calling the valueObject deserializer function (that's also used by mapValueObject) to create a specific class based on this argument.

Evert

Reply all
Reply to author
Forward
0 new messages