SitePoint Sponsor

User Tag List

Results 1 to 8 of 8
  1. #1
    SitePoint Guru
    Join Date
    May 2003
    Location
    virginia
    Posts
    988
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    Need help with nested menu - HTMLSAX

    Hi. I'm trying to build an html list parser. There is a file that defines the list like this:

    <ul>
    <li>some text. A <a href="link">link</a></li>
    <li>
    nested items
    <ul>
    <li>a nested item</li>
    <li><a href="blah.html">a nested item</a></li>
    </ul>
    </li>
    </ul>

    I'm using HTMLSax3 to handle the parsing. The part I can't figure out is how to make it all nested. I need to be able to build different types of menus like collapsing, breadcrumbs etc.. from the same structure. My idea is to create a class called MenuElement and it would be populated/set by the custom parser class. I want to be able to do this type of thing:

    PHP Code:
    $menu =& new Menu('myUnorderedListFile.html');
    $menu->parse();
    while(
    $item =& $menu->next()) {
        if( 
    $item->isRoot() ) {
            
    //
        
    }
        if( 
    $link_data $item->getAttribute('a') ) {
            
    //
        
    }
       
    $item->getText();

    I have some code here that I've tried to use but can't get going. I'm getting all kinds of recurrsion errors when I print the array using print_r. Please any help? HarryF you out there?

    Thanks!

    PHP Code:
    require_once('xml/HTMLSax3.php');

    class 
    ULFullTree {
        
        var 
    $level = -1;
        var 
    $in_li;
        var 
    $output;
        var 
    $stack = array();
        
        function 
    ULFullTree(){}
        
        
    // Handles the writing of attributes - called from $this->openHandler()
        
    function writeAttrs ($attrs) {
            if ( 
    is_array($attrs) ) {
                foreach ( 
    $attrs as $name => $value ) {
                    
    $this->output .= ' ' $name '="' $value '"';
                }
            }
        }
        
        function 
    openHandler(& $parser$name$attrs) {
            if( 
    $name == 'ul' ) {
                ++
    $this->level;
            }
            if(! 
    $this->isValid()) {
                return;
            }
            if( 
    $name == 'li' || $name == 'ul' ) {
                
    $this->output .= '<span';
            } else {
                
    $this->output .= '<' $name;
            }
            
    $this->output .= $this->writeAttrs($attrs);
            
    $this->output .= '>';
        }
        
        function 
    dataHandler(& $parser$data) {
            if(! 
    $this->isValid()) {
                return;
            }
            
    $this->output .= $data;
        }
        
        function 
    closeHandler(& $parser$name) {
            if( 
    $name == 'ul' ) {
                --
    $this->level;
                return;
            }
            if(! 
    $this->isValid()) {
                return;
            }
            if( 
    $name == 'li' || $name == 'ul' ) {
                
    $this->output .= '</span>';
            } else {
                
    $this->output .= '</' $name '>';
            }
        }
        
        function 
    isValid() {
            return 
    $this->level >= 0;
        }
        
        function 
    escapeHandler(& $parser$data) {
           
        }
        
        function 
    piHandler(& $parser$target$data) {
            
        }
        
        function 
    jaspHandler(& $parser,$data) {
            
        }
    }

    // Instantiate the handler
    $handler =& new ULFullTree();

    // Instantiate the parser
    $parser =& new XML_HTMLSax3();

    // Register the handler with the parser
    $parser->set_object($handler);

    // Set a parser option
    $parser->set_option('XML_OPTION_TRIM_DATA_NODES');

    // Set the handlers
    $parser->set_element_handler('openHandler','closeHandler');
    $parser->set_data_handler('dataHandler');
    $parser->set_escape_handler('escapeHandler');
    $parser->set_pi_handler('piHandler');
    $parser->set_jasp_handler('jaspHandler');

    // Parse the document
    $doc file_get_contents('ul.html');
    $parser->parse($doc);
    echo 
    $handler->output
    Last edited by mwmitchell; Oct 5, 2004 at 17:58.

  2. #2
    Non-Member
    Join Date
    Sep 2004
    Location
    Florida
    Posts
    19
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    have you thought about using the dom extension for this sort of thing? just a thought

  3. #3
    SitePoint Guru
    Join Date
    May 2003
    Location
    virginia
    Posts
    988
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Hey. Thanks for the repsonse. I can't use DOM because the host doesn't provide it and the client wants to edit the file in a WYSIWYG editor: (Macromedia Contribute - which doesn't read XML!).

    It's a tough one. I'm making progress and I'll post back soon... Anyone with idea(s) yet?

    Matt

  4. #4
    SitePoint Wizard silver trophy kyberfabrikken's Avatar
    Join Date
    Jun 2004
    Location
    Copenhagen, Denmark
    Posts
    6,157
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    i made a dom-parser a while back, that is pure php. you could use that :
    http://www.phpclasses.org/browse/package/1328.html

  5. #5
    SitePoint Addict
    Join Date
    Mar 2003
    Location
    Germany
    Posts
    216
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Mmh, don't know if this helps, but if it's for menus, have you noticed the recent extensive nested menu thread we had going on? Why not store all menu items in a db? But if your requirement is really "define it in a plain html file" then obviously this won't be of much help... Another way might be some self-defined text file format where you indicate the level of an item and its name and you write a parser for that. But then again a db might be easier.

  6. #6
    SitePoint Guru
    Join Date
    May 2003
    Location
    virginia
    Posts
    988
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    OK. Just wanted to update the code that I posted. It's all working fine but now... How do I handle indenting to show the tree structure? I've tried using str_repeat() which would be ideal. But I can't figure out the logic of where it goes and when to break the lines??? Anyone? And by the way I'm checking out the other solutions you all posted. Thanks much and I'll get back to you!

    Matt

  7. #7
    SitePoint Wizard
    Join Date
    Aug 2004
    Location
    California
    Posts
    1,672
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    If you want indents it might be easier to either do it with a style for each indent level or use tables. Either of those ways will be easier than tracking the <ul></ul> pairs.

  8. #8
    SitePoint Guru
    Join Date
    May 2003
    Location
    virginia
    Posts
    988
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    OK. Here is what I have. Anyone have any improvements?

    PHP Code:
    require_once('xml/HTMLSax3.php');

    class 
    ULFullTree {
        
        var 
    $level = -1;
        var 
    $current_name;
        var 
    $output;
        
        function 
    ULFullTree(){}
        
        
    // Handles the writing of attributes - called from $this->openHandler()
        
    function writeAttrs ($attrs) {
            if ( 
    is_array($attrs) ) {
                foreach ( 
    $attrs as $name => $value ) {
                    
    $this->output .= ' ' $name '="' $value '"';
                }
            }
        }
        
        function 
    openHandler(& $parser$name$attrs) {
            if( 
    $name == 'ul' ) {
                if( 
    $this->level == -) {
                    
    $this->start true;
                } else {
                    
    $this->start false;
                }
                ++
    $this->level;
            }
            if(! 
    $this->isValid()) {
                return;
            }
            
            
    $this->current_name $name;
            
            if( 
    $name == 'li' || $name == 'ul' ) {
                
    // every li element except the first
                
    if( $name == 'li' && ! $this->start) {
                    
    $this->output .= '<br/>';
                    
    $this->break_set true;
                } else {
                    
    $this->break_set false;
                }
                
    $this->output .= str_repeat('&nbsp;&nbsp;'$this->level);
                
    $this->output .= '<span';
            } else {
                if( 
    $name == 'a' ) {
                    if( 
    $attrs['href'] !== $_SERVER['SCRIPT_NAME'] ) {
                        
    $this->output .= '<' $name;
                        
    $link_valid true;
                    } else {
                        
    $link_valid false;
                    }
                } else {
                    
    $this->output .= '<' $name;
                }
            }
            if( 
    $name !== 'a' || $link_valid ) {
                
    $this->output .= $this->writeAttrs($attrs);
                
    $this->output .= '>';
            }
        }
        
        function 
    dataHandler(& $parser$data) {
            if(! 
    $this->isValid()) {
                return;
            }
            
    $this->output .= $data;
            if( 
    $this->current_name == 'li' ) {
                
    // use $end_space if XML_OPTION_TRIM_DATA_NODES option is not set
                
    $end_space '';
                
    $this->output .= $end_space;
            }
        }
        
        function 
    closeHandler(& $parser$name) {
            if( 
    $name == 'ul' ) {
                --
    $this->level;
                return;
            }
            if(! 
    $this->isValid()) {
                return;
            }
            if( 
    $name == 'li' || $name == 'ul' ) {
                
    $this->output .= '</span>';
                if( 
    $name == 'li' && ! $this->break_set ) {
                    
    $this->output .= '<br>';
                }
            } else {
                
    // use $end_space if XML_OPTION_TRIM_DATA_NODES option is not set
                
    $end_space '';
                
    $this->output .= '</' $name '>' $end_space;
            }
        }
        
        function 
    isValid() {
            return 
    $this->level >= 0;
        }
        
        function 
    escapeHandler(& $parser$data) {
           
        }
        
        function 
    piHandler(& $parser$target$data) {
            
        }
        
        function 
    jaspHandler(& $parser,$data) {
            
        }
    }

    // Instantiate the handler
    $handler =& new ULFullTree();

    // Instantiate the parser
    $parser =& new XML_HTMLSax3();

    // Register the handler with the parser
    $parser->set_object($handler);

    // Set a parser option
    //$parser->set_option('XML_OPTION_TRIM_DATA_NODES');

    // Set the handlers
    $parser->set_element_handler('openHandler','closeHandler');
    $parser->set_data_handler('dataHandler');
    $parser->set_escape_handler('escapeHandler');
    $parser->set_pi_handler('piHandler');
    $parser->set_jasp_handler('jaspHandler');

    // Parse the document
    $doc file_get_contents('ul.html');
    $parser->parse($doc);
    echo 
    $handler->output
    And my UL (ul.html) file:

    <ul>
    <li>Menu <a href="#">0:1</a> Child</li>
    <li>Menu 0:2 Child
    <ul>
    <li>Menu 0:2:0 Child</li>
    <li><a href="ULFullTree.php">Menu 0:2:1 Child</a>
    <ul>
    <li>Menu 0:2:1:0 Child</li>
    <li>Menu 0:2:1:1 Child</li>
    </ul>
    </li>
    </ul>
    </li>
    <li>Menu 0:2 Child 1</li>
    </ul>


Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •