sabre-io / xml

sabre/xml is an XML library that you may not hate.
http://sabre.io/xml/
BSD 3-Clause "New" or "Revised" License
516 stars 77 forks source link

Custom parser for 3 level identation elements (list of list of items) #140

Closed FrancescoQ closed 6 years ago

FrancescoQ commented 6 years ago

Hi i'm trying to parse with custom parsers as the attached example:

parsers.classes.txt example.txt

my problem is when i'm trying to parse the children in my "Title" class, i receive this error.

0: We hit the end of the document prematurely. This likely means that some parser "eats" too many elements. Do not attempt to continue parsing.

I'm trying to base my code on the example "Using the XmlDeserializable interface" visible here http://sabre.io/xml/reading/

But maybe i don'understand well what's under the hood, because it fails with 3 custom deserializator when two of them use

$children = $reader->parseInnerTree(); foreach($children as $child) { if ($child['value'] instanceof Performance) { $title->performances[] = $child['value']; } }

How can parse a list of list of items?

Thank you so much!

EDIT: oh, the code where i use my custom parser is like that:

      $service = new Sabre\Xml\Service();  
      $service->elementMap = array(  
        '{}tit_info_venue' => "MyParser\Venue",  
        '{}tit_info_title' => "MyParser\Title",  
        '{}tit_info_perform' => 'MyParser\Performance',  
      )
FrancescoQ commented 6 years ago

It seems that the problem is using the KeyValue along the parseInnerTree to get both the subelement that repeat AND the actual value of the node.. at the moment i resolved in this way, removing the keyvalue part. Is there a better way to do this?

    $children = $reader->parseInnerTree();
    foreach($children as $child) {
      if ($child['value'] instanceof Performance) {
        $title->performances[] = $child['value'];
      }
      else {
        if ($child['name'] == '{}editName') {
          $title->editName = $child['value'];
        }
        if ($child['name'] == '{}sottoCat') {
          $title->sottoCat = $child['value'];
        }
        if ($child['name'] == '{}categoria') {
          $title->categoria = $child['value'];
        }
        if ($child['name'] == '{}numPerf') {
          $title->numPerf = $child['value'];
        }
      }
evert commented 6 years ago

XMLReader and XMLWriter are streaming readers/writers. The implication is that you can only read once. You can't really rewind.

Your solution seems pretty reasonable though. Basically, if custom parses (like KeyValue) don't get you the information you need, you need to fall back on parseInnerTree (or the PHP XmlReader interface).

FrancescoQ commented 6 years ago

Yeah, everything's clear now, thanks so much!