Location: PHPKode > projects > jjfmapper > jjfmapper/lib/instruction_document_parser.class.php
<?php #-*-Mode: php; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
/*
    instruction_document_parser for PHP 4.
    Copyright (C) 2004  John J Foerch

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

/* Class instruction_document_parser parses a JJFMapper XML Instruction
 * Document.  This class was written based on xml_detail_parser, but has been
 * specialized for handling JJFMapper Instruction Documents to minimize on
 * memory requirements for the Instruction Document data structure.
*/

//It is here noted that the tagset for a jjfmapper config file
//is inclusive of all possible variations of alphabetic case.


if (!defined('LF')) define('LF',"\n");



//an enumeration of output formats
define ('JJFM_PNG',1);
define ('JJFM_JPEG',2);
define ('JJFM_RAW_OUTPUT',4);



class instruction_document_parser {
    //
    // Variables for parsing the XML
    //
    var $ok=true;
    var $error=false;
    var $content='';
    var $owner;
    var $supported_tags;
    var $level=0;
    var $ignore_level=false;
    var $current_tag_is_complete=false;
    var $open_element_for_current_end_element=false;
    var $current_index=0;
    var $tag_indices=array();


    //
    // Variables used by other parts of JJFMapper.
    //

    var $symbols;

    //cache
    var $cached_map;
    var $cached_projection;
    var $cache_dir=JJFM_CACHEDIR;
    var $name='';
    var $namecrc;

    //output
    var $output_file=false;
    var $output_format=false;
    var $output_flags=0;

    //layer
    var $layers=array();
    var $layer_names=array();

    //projection
    var $projection=array('imwidth' => JJFM_DEFAULT_WIDTH,
                          'imheight' => JJFM_DEFAULT_HEIGHT);
    var $fit=false;
    var $fit_spec=false;

    //debug
    var $debug_file = false;
    var $debug_output_mode = 'w';


    function instruction_document_parser (&$xmldata,&$symbols) {
        $this->content = $xmldata;
        $this->symbols = $symbols;
        $this->supported_tags = array('JJFMAPPER'=>0,'PROJECTION'=>0,
                                      'OUTPUT'=>0,'DEBUG'=>0,'CACHE'=>0,
                                      'LAYER'=>0);
        $parser = xml_parser_create();
        xml_set_object ($parser, $this);
        xml_set_element_handler ($parser,'start_element','end_element');
        $parse_success = xml_parse ($parser,$this->content,true);
        if ($parse_success === false)
        {
            $this->ok = false;
            $this->error = xml_error_string(xml_get_error_code($parser));
        }
        xml_parser_free ($parser);
        $this->validate();
    }


    function start_element (&$parser, $name, &$attr) {

        ++$this->level;

        $position = xml_get_current_byte_index ($parser);
        $fulltag = substr ($this->content, $position);
        $fulltag = substr ($fulltag, 0, strpos ($fulltag,'>')+1);
        $type = $fulltag[strlen ($fulltag) - 2] == '/' ? 'complete' : 'open';
        if ($type == 'complete') $this->current_tag_is_complete = true;


        if ($this->ignore_level == false &&
            isset ($this->supported_tags[$name]) == false)
        {
            $this->ignore_level = $this->level;
        }

        if ($this->ignore_level == false)
        {
            $method = 'start_element_'.$name;
            if (method_exists($this,$method))
            {
                call_user_func(array(&$this,$method),$parser,$attr);
            }

            $this->tag_indices[] = array('index' => $this->current_index);
            if (! $this->current_tag_is_complete)
            {
                $i = count($this->tag_indices) - 1;
                $this->tag_indices[$i]['cdatastart'] =
                    $position + strlen($fulltag);
            }

            ++$this->current_index;
        }
    }
    
    function end_element (&$parser, $name) {
        if ($this->ignore_level == false)
        {
            $this->open_element_for_current_end_element =
                array_pop ($this->tag_indices);
            $open_index = $this->open_element_for_current_end_element['index'];
        }

        if ($this->current_tag_is_complete)
        {
            $this->current_tag_is_complete = false;
            --$this->level;
            if ($this->level == $this->ignore_level)
                $this->ignore_level = false;
            return;
        }
        
        if ($this->ignore_level == false)
        {
            $position = xml_get_current_byte_index ($parser);
        
            $method = 'end_element_'.$name;
            if (method_exists($this,$method))
            {
                call_user_func(array(&$this,$method),$parser);
            }

            ++$this->current_index;
        }
        if ($this->level == $this->ignore_level) $this->ignore_level = false;
        --$this->level;
        
    }

    function start_element_JJFMAPPER (&$parser,&$attr) {
        if (isset ($attr['NAME']))
        {
            $this->name = $attr['NAME'];
            $this->namecrc = sprintf('%u',crc32 ($this->name));
        }
    }

    function start_element_DEBUG (&$parser,&$attr) {
        define ('DEBUG',true);
        //file
        if (isset ($attr['MODE']) && $attr['MODE'] == 'APPEND')
        {
            $this->debug_output_mode = 'a';
        }
        if (isset ($attr['FILE'])) $this->debug_file = $attr['FILE'];
        if (isset ($attr['NOIMAGE'])) define ('JJFM_NO_IMAGE_OUTPUT',1);
    }

    function start_element_CACHE (&$parser,&$attr) {
        define ('JJFM_CACHING',1);
        if (isset ($attr['DIR'])) $this->cache_dir =  $attr['DIR'];
        $sep = strlen ($this->cache_dir) - 1;
        if ($this->cache_dir{$sep} == '/')
            $this->cache_dir = substr($this->cache_dir,0,
                                      strlen ($jjfm_basedir) - 1);

        $this->cache_base_name = $this->cache_dir . '/' .
            $this->namecrc . sprintf('%u',crc32 ($this->content));

        $this->cached_map = $this->cache_base_name .'.png';
        $this->cached_projection = $this->cache_base_name .'.projection';
        if (file_exists ($this->cached_map))
        {
            define ('JJFM_HAVE_CACHED_MAP',1);
            if (file_exists ($this->cached_projection))
            {
                define ('HAVE_CACHED_PROJECTION',1);
            }
        }
    }

    function start_element_OUTPUT (&$parser,&$attr) {

        if (isset($attr['FORMAT']))
            $this->output_format = strtoupper($attr['FORMAT']);

        if ($this->output_format === false || $this->output_format == 'RETURN')
            define ('JJFM_RETURN',1);

        if ($this->output_format == 'PNG')
        {
            $this->output_flags = JJFM_PNG;
        } elseif ($this->output_format == 'JPG' ||
                  $this->output_format == 'JPEG') {
            $this->output_flags = JJFM_JPEG;
        }
        
        if (isset ($attr['WIDTH']))
            $this->projection['imwidth'] = $attr['WIDTH'];
        if (isset ($attr['HEIGHT']))
            $this->projection['imheight'] = $attr['HEIGHT'];

        if (isset ($attr['FILE']))
        {
            define ('JJFM_FILE_OUTPUT',1);
            $this->output_file = $attr('FILE');
            $this->output_flags |= JJFM_RAW_OUTPUT;
        }

    }

    function start_element_PROJECTION (&$parser,&$attr) {

        $latmin = isset($attr['LATMIN']) ? $attr['LATMIN'] : false;
        $latmax = isset($attr['LATMAX']) ? $attr['LATMAX'] : false;
        $lonmin = isset($attr['LONMIN']) ? $attr['LONMIN'] : false;
        $lonmax = isset($attr['LONMAX']) ? $attr['LONMAX'] : false;
        $latpoint = isset($attr['LAT']) ? $attr['LAT'] : false;
        $lonpoint = isset($attr['LON']) ? $attr['LON'] : false;
        $padding = isset($attr['PADDING'])? $attr['PADDING'] : 0;
        
        if ($latpoint !== false)
        {
            $latmin = $latmax = $latpoint;
            $lonmin = $lonmax = $lonpoint;
            if ($padding == 0) $padding += 10;
            $padlastchar = substr($padding,strlen($padding)-1);
            if ($padlastchar != '%' && $padlastchar != '°' &&
                $padlastchar != '*')
            {
                $padding .= '°';
            }
        }

        if (isset($attr['FIT']))
        {
            if (strpos($attr['FIT'],':') !== false)
            {
                list ($this->fit,$this->fit_spec) =
                    explode (':',$attr['FIT'],2);
            } else {
                $this->fit = $attr['FIT'];
            }
        }

        $this->projection['xmin'] = $lonmin;
        $this->projection['ymin'] = $latmin;
        $this->projection['xmax'] = $lonmax;
        $this->projection['ymax'] = $latmax;
        $this->projection['padding'] = $padding;

    }

    function start_element_LAYER (&$parser,&$attr) {
        $this->layers[] = $attr;
        if (! isset ($attr['FORMAT']))
        {
            $this->ok = false;
            $this->error = 'every layer element must have a format attribute.';
            return;
        }
        if (isset ($attr['NAME']))
        {
            if (isset ($this->layer_names[$attr['NAME']]))
            {
                $this->ok = false;
                $this->error = 'layer names must be unique.';
            }
            if (strrchr($attr['NAME'], ':') !== false)
            {
                $this->ok = false;
                $this->error = 'colon (:) is not allowed in layer names.';
            }
            $this->layer_names[$attr['NAME']] = count ($this->layers) - 1;
        }
    }

    function end_element_LAYER (&$parser) {
        //is there cdata to save?
        $clip_start=$this->open_element_for_current_end_element['cdatastart'];
        $clip_end = xml_get_current_byte_index ($parser);

        $clip_length = $clip_end - $clip_start;
        if ($clip_length > 0) {
            $i = count($this->layers) - 1;
            $this->layers[$i]['cdata'] =
                substr ($this->content, $clip_start, $clip_length);
        }
    }


    /* validate does very simple validation on the data structure that has
     * been created.
     */
    function validate () {
        // $this->fit must be a key in $this->layer_names
        if ($this->fit !== false && ! isset ($this->layer_names[$this->fit]))
        {
            $this->ok = false;
            $this->error = 'projection fit attribute '.
                'does not match the name of any layer.';
        }
        // if caching there must be a name attribute in the root node
        if (defined ('JJFM_CACHING') && $this->name == '')
        {
            $this->ok = false;
            $this->error = 'the root node must have a name attribute '.
                'when caching.';
        }
    }

}

?>
Return current item: jjfmapper