List Info

Thread: Re: XmlParser errors and help




Re: XmlParser errors and help
country flaguser name
United States
2007-03-03 15:09:25

Hi Jacob,

I found the bug.  I've included changes below.
1) This is very poorly structured code for a recursive routine.
2) There are really only two 'cases' that are dealt with (open and complete).  So I changed from if()/else statements to a switch($type).
3) I added a function to 'peek' at the next element's type.
4) Finally -- I do not think this is an elegant solution but do not have time to rewrite the UpdateRecursive() routine so it could in itself be elegant.  Maybe one of the hot-shots at Google can do that. ; I have not done extensive testing.

The Problem:

On an 'open' type element, the function loops and calls itself until it sees a 'close' type. ; It accumulates the results of the recursion in an array which it later unwinds to build the $params array (for that 'open' and subsequent 'levels').  This picks up all elements at higher levels and captures them into the accumulated array ($new_arr).

If the 'close' type is followed by a 'complete' type at the same level, the 'complete' type was skipped.  That's because $this->global_index is incremented within the if( $type == 'open') condition.  After $this->global_index is incremented, it points to the next element.  When the accumulation is unwound, the 'complete' tag was missed because it was associated with an 'else' (I.e. else not open).

So there were multiple problems:

  1. 'complete' associated with an else
  2. Not picking up a 'complete' tag as the next tag at the same level
My changed routines (note: added function of peek():
    /* Look at the next type and compare */
    function peek($type, &$vals) {
        $idx = $this->global_index + 1;
 &nbsp; &nbsp; &nbsp;  if( $idx&nbsp; < count($vals) )
 &nbsp; &nbsp; &nbsp; &nbsp;   ; return( $vals[$idx]['type'] == $type ? $idx : 0 );
 &nbsp; &nbsp; &nbsp; &nbsp; return(0);
  ; }
 
  /* Converts the output of SAX parser into a PHP associative array similar to the
 &nbsp;  * DOM parser output
&nbsp;   */
 &nbsp;  function UpdateRecursive($vals) {
 &nbsp; &nbsp; // $params accumulates through this level
&nbsp; &nbsp; &nbsp; $params = array();
 &nbsp;   ; $this-&gt;global_index++;
&nbsp; &nbsp; &nbsp; //Reached end of array
&nbsp; &nbsp;   if($this-&gt;global_index >= count($vals))
 ; &nbsp; &nbsp; &nbsp; return;
 
 &nbsp;  $tag = strtolower($vals[$this->global_index]['tag']);
&nbsp; &nbsp; // TB 3/2/07 - Added to prevent value from being an Undefined index.
&nbsp;   ;$value = isset($vals[$this-&gt;global_index]['value']) ? trim($vals[$this-&gt;global_index]['value']) : '';
&nbsp; &nbsp; $type = $vals[$this->global_index]['type'];
 &nbsp; 
 &nbsp;  //Add attributes
 &nbsp; &nbsp;if(isset($vals[$this->global_index]['attributes'])) {
   ; &nbsp; &nbsp; foreach($vals[$this->global_index]['attributes'] as $key=>$val) {
   ; &nbsp; &nbsp; &nbsp; &nbsp; $key = strtolower($key);
&nbsp;   ; &nbsp; &nbsp; &nbsp;  $params[$tag][$key] = $val;
&nbsp; &nbsp; &nbsp; &nbsp; }
   ; }
&nbsp; 
 &nbsp; switch($type) {
   ; &nbsp;  case 'open':
  ; &nbsp; &nbsp; &nbsp; &nbsp; $new_arr = array();
 
&nbsp; &nbsp; &nbsp;   ; &nbsp; //Read all elements at the next levels and add to an array
&nbsp; &nbsp;   ; &nbsp; &nbsp; while($vals[$this->global_index]['type'] != 'close' &&amp; 
&nbsp; &nbsp;   ; &nbsp; &nbsp; &nbsp;  $this-&gt;global_index < count($vals)) {
   ; &nbsp; &nbsp; &nbsp; &nbsp;   ; &nbsp;  $arr = $this-&gt;UpdateRecursive($vals);
 &nbsp;   ; &nbsp; &nbsp; &nbsp; &nbsp;   ;  if(count($arr) > 0) {
   ; &nbsp; &nbsp; &nbsp; &nbsp;   ; &nbsp; &nbsp; &nbsp; &nbsp;  $new_arr[] = $arr;
&nbsp; &nbsp;   ; &nbsp; &nbsp; &nbsp; &nbsp;   }
   ; &nbsp; &nbsp; &nbsp; &nbsp;}
&nbsp;
 &nbsp; &nbsp;   ; &nbsp; &nbsp;// First unwind the recursive accumulation for this prior element (if it had depth)
&nbsp;   ; &nbsp; &nbsp; &nbsp; foreach($new_arr as $arr) {
   ; &nbsp; &nbsp; &nbsp; &nbsp;  foreach($arr as $key=>$val) {
   ; &nbsp; &nbsp; &nbsp; &nbsp;   ; &nbsp;if(isset($params[$tag][$key])) {
   ; &nbsp; &nbsp; &nbsp; &nbsp;   ; &nbsp;  //If this key already exists
&nbsp;   ; &nbsp; &nbsp; &nbsp; &nbsp;   ; &nbsp; if($this->is_associative_array($params[$tag][$key])) {
   ; &nbsp; &nbsp; &nbsp; &nbsp;   ; &nbsp; &nbsp; &nbsp; //If this is an associative array and not an indexed array
&nbsp; &nbsp;   ; &nbsp; &nbsp; &nbsp; &nbsp;   ; &nbsp; &nbsp;// remove existing value and convert to an indexed array
&nbsp; &nbsp;   ; &nbsp; &nbsp; &nbsp; &nbsp;   ; &nbsp; &nbsp;$val_key = $params[$tag][$key];
 &nbsp; &nbsp; &nbsp;   ; &nbsp; &nbsp; &nbsp; &nbsp;   ; array_splice($params[$tag][$key], 0);
&nbsp; &nbsp; &nbsp; &nbsp;   ; &nbsp; &nbsp; &nbsp; &nbsp;   ;$params[$tag][$key][0] =  $val_key;
 &nbsp; &nbsp; &nbsp;   ; &nbsp; &nbsp; &nbsp; &nbsp;   ; $params[$tag][$key][] =  $val;
&nbsp; &nbsp;   ; &nbsp; &nbsp; &nbsp; &nbsp;   ; } else {
   ; &nbsp; &nbsp; &nbsp; &nbsp;   ; &nbsp; &nbsp; &nbsp; // not an associative array
&nbsp; &nbsp;   ; &nbsp; &nbsp; &nbsp; &nbsp;   ; &nbsp; &nbsp;$params[$tag][$key][] =  $val;&nbsp;
 &nbsp;   ; &nbsp; &nbsp; &nbsp; &nbsp;   ;  }
   ; &nbsp; &nbsp; &nbsp; &nbsp;   ;  } else { 
  ; &nbsp; &nbsp; &nbsp; &nbsp;   ; &nbsp; &nbsp; &nbsp; &nbsp; // didn't exist, just use it
 ; &nbsp; &nbsp; &nbsp; &nbsp;   ; &nbsp; &nbsp; &nbsp; &nbsp;  $params[$tag][$key] =  $val;
&nbsp; &nbsp;   ; &nbsp; &nbsp; &nbsp; &nbsp;  }
&nbsp; &nbsp; &nbsp;   ; &nbsp; &nbsp; }
   ; &nbsp;  }
   ; &nbsp;  // TB 3/2/07 - Added to catch skipped elements
 &nbsp; &nbsp; &nbsp; // Look to see if the next index is valid and if it's 'complete'
 &nbsp; &nbsp; &nbsp; if( $idx = $this->peek('complete', $vals) ) {
   ; &nbsp; &nbsp; &nbsp; &nbsp; // Yep, set it here (and by definition) at this level
&nbsp; &nbsp;   ; &nbsp; &nbsp; &nbsp;$params[strtolower($vals[$idx]['tag'])]['VALUE'] = trim($vals[$idx]['value']);
&nbsp; &nbsp; &nbsp;  } 
  ; &nbsp; &nbsp; $this->global_index++;
 &nbsp; &nbsp; &nbsp; break;

 &nbsp; &nbsp; &nbsp;case 'complete':
 &nbsp;   ; &nbsp; &nbsp;  if( $value != '' )
   ; &nbsp; &nbsp; &nbsp; &nbsp;   $params[$tag]['VALUE'] = $value;
  ; &nbsp; &nbsp; &nbsp; &nbsp; break;
&nbsp;  }
   return($params);&nbsp; &nbsp;
 }

--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups "API Integration Basics&quot; group.
To post to this group, send email to google-checkout-api-integrationgooglegroups.com
To unsubscribe from this group, send email to google-checkout-api-integration-unsubscribegooglegroups.com
For more options, visit this group at http://groups.google.com/group/google-checkout-api-integration?hl=en
-~----------~----~----~----~------~----~------~--~---
Re: XmlParser errors and help
country flaguser name
United States
2007-03-03 23:44:34
Tony,

Your post makes perfect sense. I ran your code and could see
that it's
working as intended. 

I also found the cause of this bug this morning and plan to
rewrite
the UpdateRecursive() function from scratch.


Thanks!
Jacob

On Mar 3, 1:09 pm, "Tony Birnseth" <t...1sit.com> wrote:
> Hi Jacob,
>
> I found the bug.  I've included changes below.
> 1) This is very poorly structured code for a recursive
routine.
> 2) There are really only two 'cases' that are dealt
with (open and
> complete).  So I changed from if()/else statements to a
switch($type).
> 3) I added a function to 'peek' at the next element's
type.
> 4) Finally -- I do not think this is an elegant
solution but do not have
> time to rewrite the UpdateRecursive() routine so it
could in itself be
> elegant.  Maybe one of the hot-shots at Google can do
that.  I have not
> done extensive testing.
>
> The Problem:
>
>         On an 'open' type element, the function loops
and calls itself
> until it sees a 'close' type.  It accumulates the
results of the
> recursion in an array which it later unwinds to build
the $params array
> (for that 'open' and subsequent 'levels').  This picks
up all elements
> at higher levels and captures them into the accumulated
array
> ($new_arr).
>
>         If the 'close' type is followed by a 'complete'
type at the same
> level, the 'complete' type was skipped.  That's
because
> $this->global_index is incremented within the if(
$type == 'open')
> condition.  After $this->global_index is
incremented, it points to the
> next element.  When the accumulation is unwound, the
'complete' tag was
> missed because it was associated with an 'else' (I.e.
else not open).
>
>         So there were multiple problems:
>
>         1.      'complete' associated with an else
>         2.      Not picking up a 'complete' tag as the
next tag at the
> same level
>
> My changed routines (note: added function of peek():
>     /* Look at the next type and compare */
>     function peek($type, &$vals) {
>         $idx = $this->global_index + 1;
>         if( $idx  < count($vals) )
>             return( $vals[$idx]['type'] == $type ? $idx
: 0 );
>          return(0);
>    }
>
>   /* Converts the output of SAX parser into a PHP
associative array
> similar to the
>     * DOM parser output
>     */
>     function UpdateRecursive($vals) {
>      // $params accumulates through this level
>       $params = array();
>       $this->global_index++;
>       //Reached end of array
>       if($this->global_index >= count($vals))
>         return;
>
>     $tag =
strtolower($vals[$this->global_index]['tag']);
>     // TB 3/2/07 - Added to prevent value from being an
Undefined index.
>     $value =
isset($vals[$this->global_index]['value']) ?
> trim($vals[$this->global_index]['value']) : '';
>     $type = $vals[$this->global_index]['type'];
>
>     //Add attributes
>    
if(isset($vals[$this->global_index]['attributes'])) {
>        
foreach($vals[$this->global_index]['attributes'] as
$key=>$val)
> {
>             $key = strtolower($key);
>             $params[$tag][$key] = $val;
>         }
>     }
>
>    switch($type) {
>        case 'open':
>            $new_arr = array();
>
>            //Read all elements at the next levels and
add to an array
>            while($vals[$this->global_index]['type']
!= 'close' &&
>               $this->global_index < count($vals))
{
>                   $arr =
$this->UpdateRecursive($vals);
>                   if(count($arr) > 0) {
>                         $new_arr[] = $arr;
>                  }
>            }
>
>            // First unwind the recursive accumulation
for this prior
> element (if it had depth)
>            foreach($new_arr as $arr) {
>              foreach($arr as $key=>$val) {
>                 if(isset($params[$tag][$key])) {
>                   //If this key already exists
>                  
if($this->is_associative_array($params[$tag][$key])) {
>                      //If this is an associative array
and not an
> indexed array
>                      // remove existing value and
convert to an indexed
> array
>                      $val_key = $params[$tag][$key];
>                      array_splice($params[$tag][$key],
0);
>                      $params[$tag][$key][0] = 
$val_key;
>                      $params[$tag][$key][] =  $val;
>                   } else {
>                      // not an associative array
>                      $params[$tag][$key][] =  $val;
>                   }
>                 } else {
>                       // didn't exist, just use it
>                       $params[$tag][$key] =  $val;
>                 }
>              }
>        }
>        // TB 3/2/07 - Added to catch skipped elements
>        // Look to see if the next index is valid and if
it's 'complete'
>        if( $idx = $this->peek('complete', $vals) )
{
>             // Yep, set it here (and by definition) at
this level
>            
$params[strtolower($vals[$idx]['tag'])]['VALUE'] =
> trim($vals[$idx]['value']);
>        }
>        $this->global_index++;
>        break;
>
>       case 'complete':
>            if( $value != '' )
>               $params[$tag]['VALUE'] = $value;
>            break;
>    }
>    return($params);
>  }


--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the
Google Groups "API Integration Basics" group.
To post to this group, send email to
google-checkout-api-integrationgooglegroups.com
To unsubscribe from this group, send email to
google-checkout-api-integration-unsubscribegooglegroups.com
For more options, visit this group at http://groups.google.com/group/google-checko
ut-api-integration?hl=en
-~----------~----~----~----~------~----~------~--~---


[1-2]

about | contact  Other archives ( Real Estate discussion Medical topics )