gwynne          Sun Jul 29 14:31:54 2007 UTC

  Modified files:              (Branch: GWYNNE_PLAYS_HERE)
    /phd        build.php 
    /phd/formats        xhtml.php 
    /phd/include        PhDReader.class.php 
  Log:
  Committed to my branch ONLY. This is my vision of some of what should be 
going on in an output format, though a lot of this should be in a theme really. 
Discussion versus Hannes' method is requested :).
  
  
http://cvs.php.net/viewvc.cgi/phd/build.php?r1=1.4&r2=1.4.2.1&diff_format=u
Index: phd/build.php
diff -u phd/build.php:1.4 phd/build.php:1.4.2.1
--- phd/build.php:1.4   Fri Jul 27 23:09:27 2007
+++ phd/build.php       Sun Jul 29 14:31:54 2007
@@ -1,15 +1,36 @@
 <?php
+error_reporting( E_ALL | E_STRICT );
+
 require_once 'config.php';
 require_once 'formats/xhtml.php';
 
-$phd = new PhDXHTMLReader( "${OPTIONS[ 'xml_root' ]}/.manual.xml" );
-$phd->seek( "function.dotnet-load" );
-echo date( DATE_RSS )." done seeking\n";
-
-ob_start();
-while( $phd->nextNode() ) {
-       print $phd->transform();
+file_put_contents( dirname( __FILE__ ) . "/temp.xml", <<<~XML
+<?xml version="1.0" encoding="utf-8"?>
+
+<book>
+ <part id="part1">
+  <chapter id="chap1">
+   Using the application <application>autoconf</application>, we can do some
+   fun stuff, since <command>php</command> does other fun things, and dolor
+   Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
+   tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
+   quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
+   consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
+   cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat
+   non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
+  </chapter>
+ </part>
+</book>
+XML
+    );
+
+$phd = new PhDReader_XHTML( dirname( __FILE__ ) . "/temp.xml", NULL, 2 );
+
+while ( $phd->transformChunk( $chunk ) ) {
+    print "{$chunk}\n";
 }
+print "{$chunk}\n";
+
 $phd->close();
 
 ?>
http://cvs.php.net/viewvc.cgi/phd/formats/xhtml.php?r1=1.7.2.1&r2=1.7.2.2&diff_format=u
Index: phd/formats/xhtml.php
diff -u phd/formats/xhtml.php:1.7.2.1 phd/formats/xhtml.php:1.7.2.2
--- phd/formats/xhtml.php:1.7.2.1       Sun Jul 29 09:46:39 2007
+++ phd/formats/xhtml.php       Sun Jul 29 14:31:54 2007
@@ -1,6 +1,6 @@
 <?php
 
-/*  $Id: xhtml.php,v 1.7.2.1 2007/07/29 09:46:39 gwynne Exp $
+/*  $Id: xhtml.php,v 1.7.2.2 2007/07/29 14:31:54 gwynne Exp $
     +-------------------------------------------------------------------------+
     | Copyright(c) 2007                                                       |
     | Authors:                                                                |
@@ -20,53 +20,7 @@
 /* Grab the PhDReader parent class. */
 require_once 'include/PhDReader.class.php';
 
-class PhDXHTMLReader extends PhDReader {
-
-       protected $map = array(
-               'application'           => 'span',
-               'classname'             => 'span',
-               'code'                  => 'code',
-               'collab'                => 'span',
-               'collabname'            => 'span',
-               'command'               => 'span',
-               'computeroutput'        => 'span',
-               'constant'              => 'span',
-               'emphasis'              => 'em',
-               'enumname'              => 'span',
-               'envar'                 => 'span',
-               'filename'              => 'span',
-               'glossterm'             => 'span',
-               'holder'                => 'span',
-               'informaltable'         => 'table',
-               'itemizedlist'          => 'ul',
-               'listitem'              => 'li',
-               'literal'               => 'span',
-               'mediaobject'           => 'div',
-               'methodparam'           => 'span',
-               'member'                => 'li',
-               'note'                  => 'div',
-               'option'                => 'span',    
-               'orderedlist'           => 'ol',
-               'para'                  => 'p',
-               'parameter'             => 'span',
-        'partintro'             => 'div',
-               'productname'           => 'span',
-               'propname'              => 'span',
-               'property'              => 'span',
-               'proptype'              => 'span',
-        'section'               => 'div',
-               'simplelist'            => 'ul',
-               'simpara'               => 'p',
-               'title'                 => array(
-                       /* DEFAULT */          'h1',
-                       'refsect1'          => 'h3',
-                       'example'           => 'h4',
-               ),
-               'year'                  => 'span',
-       );
-    protected $CURRENT_FUNCTION_ID = "";
-       protected $CURRENT_REFERENCE_ID = "";
-       protected $functionList = array();
+class PhDReader_XHTML extends PhDReader {
 
     public function __construct( $file, $encoding = 'utf-8', $options = NULL ) 
{
         parent::__construct( $file, $encoding, $options );
@@ -80,51 +34,153 @@
         return 'XHTML 1.0 Transitional';
     
     }
-    
-       public function format_refentry( $open ) {
-
-               if ( $open ) {
-                       $this->CURRENT_FUNCTION_ID = $id = $this->getID();
-
-                       return sprintf( '<div id="%s" class="refentry">', $id );
-               }
-               $this->CURRENT_FUNCTION_ID = "";
-               return "</div>";
-       }
-       public function format_reference( $open ) {
-               if ( $open ) {
-                       $this->CURRENT_REFERENCE_ID = $id = $this->getID();
-
-                       return sprintf( '<div id="%s" class="reference">', $id 
);
-
-               }
-               $content  = "</div>";
-               $content .= '<ul class="funclist">';
-               foreach( $this->functionList as $func => $desc ) {
-                       $content .= sprintf( '<li><a href="function.%1$s.html" 
class="refentry">%1$s</a></li>', $func );
-               }
-               $content .= "</ul>\n";
-               $this->CURRENT_REFERENCE_ID = "";
-               $this->functionList = array();
-               return $content;
-
-       }
-
-       public function format_function( $open ) {
 
-               return sprintf( '<a href="function.%1$s.html">%1$s</a>', 
$this->readContent() );
-
-       }
-
-       public function format_refsect1( $open ) {
-
-               if ( $open ) {
-                       return sprintf( '<div class="refsect %s">', 
$this->readAttribute( "role" ) );
-               }
-               return "</div>\n";
+    protected function transformNode( $name, $type, &$output ) {
+        
+        switch ( $type ) {
+            
+            case XMLReader::ELEMENT:
+            case XMLReader::END_ELEMENT:
+                return $this->processElement( $name, $type == 
XMLReader::ELEMENT, $output );
+                break;
+                
+            case XMLReader::TEXT:
+                $output = $this->value;
+                return FALSE;
+                
+            case XMLReader::CDATA:
+                $output = $this->processCDATA( $this->value );
+                return FALSE;
+                
+            case XMLReader::ENTITY_REF:
+                $output = '<div class="error">WARNING: UNRESOLVED ENTITY 
'.htmlspecialchars( $name ).'</div>';
+                return FALSE;
+        
+        }
+    
+    }
+    
+    protected function processElement( $name, $isOpen, &$output ) {
+        static $handlerMap = NULL;
+        
+        if ( is_null( $handlerMap ) ) {
+            $spanName = array( '<span class="%n%">', FALSE, '</span>', FALSE );
+            $divName = array( '<div class="%n%">', FALSE, '</div>', FALSE );
+            $divNameChunked = array( '<div class="%n%">', FALSE, '</div>', 
TRUE );
+            $oneToOne = array( '<%n%>', FALSE, '</%n%>', FALSE );
+            
+            $handlerMap = array(
+                'application' => $spanName,
+                'classname' => $spanName,
+                'code' => $oneToOne,
+                'collab' => $spanName,
+                'collabname' => $spanName,
+                'command' => $spanName,
+                'computerOutput' => $spanName,
+                'constant' => $spanName,
+                'emphasis' => $oneToOne,
+                'enumname' => $spanName,
+                'envar' => $spanName,
+                'filename' => $spanName,
+                'glossterm' => $spanName,
+                'holder' => $spanName,
+                'informatlable' => array( '<table>', FALSE, '</table>', FALSE 
),
+                'itemizedlist' => array( '<ul>', FALSE, '</ul>', FALSE ),
+                'listitem' => array( '<li>', FALSE, '</li>', FALSE ),
+                'literal' => $spanName,
+                'mediaobject' => $divName,
+                'methodparam' => $spanName,
+                'member' => array( '<li>', FALSE, '</li>', FALSE ),
+                'note' => $divName,
+                'option' => $spanName,
+                'orderedlist' => array( '<ol>', FALSE, '</ol>', FALSE ),
+                'para' => array( '<p>', FALSE, '</p>', FALSE ),
+                'parameter' => $spanName,
+                'partintro' => $divName,
+                'productname' => $spanName,
+                'propname' => $spanName,
+                'property' => $spanName,
+                'proptype' => $spanName,
+                'section' => $divNameChunked,
+                'simplelist' => array( '<ul>', FALSE, '</ul>', FALSE ),
+                'simpara' => array( '<p>', FALSE, '</p>', FALSE ),
+                'title' => array( 'checkparentname', array( '__default' => 
'h1', 'refsect1' => 'h3', 'example' => 'h4' ) ),
+                'year' => $spanName,
+                'refentry' => array( '<div id="%i%" class="refentry">', FALSE, 
'</div>', TRUE, TRUE ),
+                'reference' => array( $this, 'format_reference' ),
+                'function' => array( '<a href="function.%v%.html">', FALSE, 
'</a>', FALSE ),
+                'refsect1' => array( '<div class="refsect_%r%">', FALSE, 
'</div>', FALSE ),
+                '__default' => array( $this, 'unknownElement' ),
+            );
+        }
+
+        $mapping = isset( $handlerMap[ $name ] ) ? $handlerMap[ $name ] : 
$handlerMap[ '__default' ];
+        if ( is_array( $mapping ) ) {
+            if ( is_string( $mapping[ 0 ] ) ) {
+                switch ( $mapping[ 0 ] ) {
+                    case 'checkparentname':
+                        $output = '<div class="warning">NOT IMPLEMENTED 
YET.</div>';
+                        return FALSE;
+                    default:
+                        $id = $this->getID();
+                        $output = $this->formatMappingString( $name, $id, 
$isOpen ? $mapping[ 0 ] : $mapping[ 2 ] );
+                        if ( !empty( $mapping[ 4 ] ) ) {
+                            $this->pushStack( $id );
+                        }
+                        return ( $isOpen ? $mapping[ 1 ] : $mapping[ 3 ] );
+                }
+            } else if ( is_callable( $mapping ) ) {
+                return call_user_func( $mapping, $name, $isOpen, &$output );
+            }
+        } else if ( is_string( $mapping ) ) {
+            if ( $isOpen ) {
+                $output = $this->formatMappingString( $name, $this->getID(), 
$mapping );
+            } else {
+                $output = '';
+            }
+            return FALSE;
+        }
+        $output = '<div class="warning">Bad handler string for 
'.$name.'!</div>';
+        return FALSE;
 
-       }
+    }
+    
+    protected function processCDATA( $content ) {
+        
+        return '<div class="phpcode">' . highlight_string( $content ) . 
'</div>';
+        
+    }
+    
+    protected function formatMappingString( $name, $id, $string ) {
+        
+        // XXX Yes, this needs heavy optimization, it's example for now.
+        return str_replace( array( '%n%', '%i%', '%v%', '%r' ),
+                            array( $name, $id, $this->readInnerXML(), 
$this->getAttribute( 'role' ) ),
+                            $string );
+    
+    }
+    
+    protected  function format_reference( $name, $isOpen, $output ) {
+        if ( $isOpen ) {
+            $output = sprintf( '<div id="%s" class="reference">', 
$this->getID() );
+            return FALSE;
+        }
+        $output = '</div>' .
+                  '<ul class="funclist">';
+        foreach ( $this->popStack() as $func => $desc ) {
+            $output .= sptrinf( '<li><a href="function.%1$s.html" 
class="refentry">%1$s</a></li>', $func );
+        }
+        $output .= '</ul>';
+        return TRUE;
+    }
+    
+    protected function unknownElement( $name, $isOpen, $output ) {
 
+        $output = "Can't handle a {$name}.\n";
+        return FALSE;
+    
+    }
+/*
        public function format_link( $open ) {
 
                $this->moveToNextAttribute();
@@ -137,7 +193,7 @@
 
        public function format_methodsynopsis( $open ) {
 
-               /* We read this element to END_ELEMENT so $open is useless */
+               /* We read this element to END_ELEMENT so $open is useless *
                $content = '<div class="methodsynopsis">';
                $root = $this->name;
 
@@ -182,56 +238,7 @@
                return sprintf( '<div class="refnamediv"><span 
class="refname">%s</span><span class="refpurpose">%s</span></div>', $refname, 
$refpurpose );
        }
 
-       protected function transormFromMap($open, $tag, $name) {
-
-               $tag = $this->map[ $name ];
-               if($open) {
-                       return sprintf( '<%s class="%s">', $tag, $name );
-               }
-               return "</$tag>";
-
-       }
-
-       public function format_listing_hyperlink_function( $matches ) {
-
-               $link = str_replace( '_', '-', $matches[ 1 ] );
-               $link = "function${link}.html";
-               return '<a class="phpfunc" href="'.$link.'">'.$matches[ 1 
].'</a></span>'.$matches[ 2 ];
-
-       }
-
-       public function highlight_php_code( $str ) { /* copy&paste from 
livedocs */
-
-               if ( is_array( $str ) ) {
-                       $str = $str[ 0 ];
-               }
-       
-               $tmp = str_replace(
-                       array(
-                               '&nbsp;',
-                               '<font color="',        // for PHP 4
-                               '<span style="color: ', // for PHP 5.0.0RC1
-                               '</font>',
-                               "\n ",
-                               '  '
-                       ),
-                       array(
-                               ' ',
-                               '<span class="',
-                               '<span class="',
-                               '</span>',
-                               "\n&nbsp;",
-                               ' &nbsp;'
-                       ),
-                       highlight_string( $str, TRUE )
-               );
-       
-               $tmp = preg_replace_callback( 
'{([\w_]+)\s*</span>(\s*<span\s+class="keyword">\s*\()}m',
-                   array( $this, 'format_listing_hyperlink_function' ), $tmp );
-               return sprintf( '<div class="phpcode">%s</div>', $tmp );
-
-       }
-
+*/
 }
 
 /*
http://cvs.php.net/viewvc.cgi/phd/include/PhDReader.class.php?r1=1.6.2.1&r2=1.6.2.2&diff_format=u
Index: phd/include/PhDReader.class.php
diff -u phd/include/PhDReader.class.php:1.6.2.1 
phd/include/PhDReader.class.php:1.6.2.2
--- phd/include/PhDReader.class.php:1.6.2.1     Sun Jul 29 09:46:39 2007
+++ phd/include/PhDReader.class.php     Sun Jul 29 14:31:54 2007
@@ -1,6 +1,6 @@
 <?php
 
-/*  $Id: PhDReader.class.php,v 1.6.2.1 2007/07/29 09:46:39 gwynne Exp $
+/*  $Id: PhDReader.class.php,v 1.6.2.2 2007/07/29 14:31:54 gwynne Exp $
     +-------------------------------------------------------------------------+
     | Copyright(c) 2007                                                       |
     | Authors:                                                                |
@@ -22,27 +22,112 @@
        const XMLNS_XLINK = "http://www.w3.org/1999/xlinK";;
        const XMLNS_PHD   = "http://www.php.net/ns/phd";;
 
-       protected $map = array();
-    protected $STACK = array();
+    protected $stack = array();
 
        public function __construct( $file, $encoding = "utf-8", $options = 
NULL ) {
 
                if ( !parent::open( $file, $encoding, $options ) ) {
                        throw new Exception();
                }
+               $this->read();
 
        }
-    
+       
     public function __destruct() {
     }
     
-    /* Format subclasses must implement these to make them real formats. */
+    // ***
+    // Format subclasses must implement these to make them real formats.
+    //  THIS IS THE OFFICIAL OUTPUT FORMAT INTERFACE.
+
+    //  proto string getFormatName( void )
+    //      Return the name of the format.
     abstract public function getFormatName();
-    abstract protected function transformFromMap( $open, $name );
+
+    //  proto string transformNode( string name, int type, string &output )
+    //      Transform a given node, returning the binary string output. Binary
+    //      strings ARE handled safely. This function will be called for all
+    //      element, text, cdata, entity reference, and end element nodes. It
+    //      is always valid for this method to make the parser move around in
+    //      the file. Return TRUE to create a chunk boundary, FALSE otherwise.
+    abstract protected function transformNode( $name, $type, &$output );
     
-    /* These are new functions, extending XMLReader. */
+    // ***
+    // Protected methods (intended for internal and subclass use only)
+
+    // proto array getAllAttributes( void )
+    //  Return all the attributes in the current element node as name:ns =>
+    //  value pairs. Prefer the getAttribute*() methods defined by XMLReader
+    //  when possible; use this only when you really do need all the
+    //  attributes. An element without any attributes will result in an empty
+    //  array, while a non-element node will result in a return of FALSE.
+    protected function getAttributes() {
+        
+        $type = $this->nodeType;
+        if ( $type != XMLReader::ELEMENT && $type != XMLReader::END_ELEMENT ) {
+            return FALSE;
+        }
+        $attrCount = $this->attributeCount;
+        $attrs = array();
+        if ( $attrCount > 0 ) {
+            for ( $i = 0; $i < $attrCount; ++$i ) {
+                $this->moveToAttributeNo( $i );
+                $attrs[ $this->name ] = $this->value;
+            }
+            $this->moveToElement();
+        }
+        return $attrs;
+
+    }
     
-    /* Seek to an ID within the file. */
+    // proto string getID( void )
+    //  Get the ID of the current element. Works on element and end element
+    //  nodes only, returning an empty string in all other cases.
+    protected function getID() {
+
+               if ( $this->hasAttributes && $this->moveToAttributeNs( "id", 
self::XMLNS_XML ) ) {
+                       $id = $this->value;
+                       $this->moveToElement();
+                       return $id;
+               }
+               return "";
+
+       }
+       
+       // protected void pushStack( mixed value )
+       //  Push a value of any kind onto the parser stack. The stack is not 
used
+       //  by the parser; it is intended as a cheap data store for formats and
+       //  themes.
+       protected function pushStack( $value ) {
+           
+           array_push( $this->stack, $value );
+       
+       }
+       
+       // protected mixed stackTop( void )
+       //  Return the top value on the stack.
+       protected function stackTop() {
+           
+           return count( $this->stack ) ? $this->stack[ 0 ] : NULL;
+       
+       }
+       
+       // protected mixed popStack( void )
+       //  Pop the top value off the stack and return it.
+       protected function popStack() {
+           
+           return array_pop( $this->stack );
+       
+       }
+    
+    // ***
+    // Public methods
+    
+    // proto bool seek( string id )
+    //  Seek to an ID. This is used to start the parser somewhere that isn't at
+    //  the beginning (duh). Be careful; this does not cause the parser to halt
+    //  at the closing element of a successful seek. Don't forget to check the
+    //  return value.
        public function seek( $id ) {
 
                while( parent::read() ) {
@@ -54,6 +139,70 @@
                return FALSE;
 
        }
+       
+       // proto string transform( void )
+       //  Transform the whole tree as one giant chunk, IGNORING the output
+       //  format's chunker. Returns the tree, or FALSE on error.
+       public function transform() {
+           
+           $allData = '';
+           while ( ( $data = $this->transformChunk() ) !== FALSE ) {
+            $allData .= $data;
+           }
+           return $allData;
+       
+       }
+       
+       // proto bool transformChunk( string &outData )
+       //  Transform nodes until the output format says it's time to output a
+       //  chunking boundary or the parser runs out of data. Returns TRUE on
+       //  success, FALSE on EOF. $data contains the transformed data, if any.
+       public function transformChunk( &$outData ) {
+           global $OPTIONS;
+
+        $hasMore = TRUE;
+           $data = fopen( "php://temp/maxmemory:{$OPTIONS[ 
'chunking_memory_limit' ]}", "r+" );
+           $isChunk = FALSE;
+           do {
+               $nodeName = $this->name;
+               $nodeType = $this->nodeType;
+               switch ( $nodeType ) {
+                   case XMLReader::NONE:
+                       break;
+                       
+                case XMLReader::ELEMENT:
+                case XMLReader::END_ELEMENT:
+                case XMLReader::TEXT:
+                case XMLReader::CDATA:
+                case XMLReader::ENTITY_REF:
+                    $isChunk = $this->transformNode( $nodeName, $nodeType, 
$output );
+                    fwrite( $data, $output );
+                    break;
+
+                case XMLReader::ENTITY:
+                case XMLReader::PI:
+                case XMLReader::DOC_TYPE:
+                case XMLReader::DOC:
+                case XMLReader::DOC_FRAGMENT:
+                case XMLReader::NOTATION:
+                case XMLReader::WHITESPACE:
+                case XMLReader::SIGNIFICANT_WHITESPACE:
+                case XMLReader::END_ENTITY:
+                case XMLReader::XML_DECLARATION:
+                    // Eat it for lunch.
+                    break;
+            }
+            $hasMore = $this->read();
+        } while ( !$isChunk && $hasMore );
+        
+        rewind( $data );
+        $outData = stream_get_contents( $data );
+        fclose( $data );
+        return $hasMore;
+
+    }
+
+/*
        public function getID() {
                if ( $this->hasAttributes && $this->moveToAttributeNs("id", 
self::XMLNS_XML) ) {
                        $id = $this->value;
@@ -63,7 +212,6 @@
                return "";
        }
 
-    /* Go to the next useful node in the file. */
        public function nextNode() {
 
                while( $this->read() ) {
@@ -84,14 +232,12 @@
 
        }
     
-    /* Read a node with the right name? */
        public function readNode( $nodeName ) {
 
                return $this->read() && !( $this->nodeType == 
XMLReader::END_ELEMENT && $this->name == $nodeName );
 
        }
 
-    /* Get the content of a named node, or the current node. */
        public function readContent( $node = NULL ) {
 
                $retval = "";
@@ -106,25 +252,23 @@
 
        }
     
-    /* Get the attribute value by name, if exists. */
        public function readAttribute( $attr ) {
 
                return $this->moveToAttribute( $attr ) ? $this->value : "";
 
        }
 
-    /* Handle unmapped nodes. */
        public function __call( $func, $args ) {
 
                if ( $this->nodeType == XMLReader::END_ELEMENT ) {
-                   /* ignore */ return;
+                   /* ignore * return;
                }
                trigger_error( "No mapper for $func", E_USER_WARNING );
 
                /* NOTE:
                 *  The _content_ of the element will get processed even though 
we dont 
                 *  know how to handle the elment itself
-               */
+               *
                return "";
 
        }
@@ -141,7 +285,6 @@
                return $tag;
        }
  
-    /* Perform a transformation. */
        public function transform() {
 
                $type = $this->nodeType;
@@ -178,8 +321,8 @@
                case XMLReader::COMMENT:
                case XMLReader::WHITESPACE:
                case XMLReader::SIGNIFICANT_WHITESPACE:
-                       /* swallow it */
-                       /* XXX This could lead to a recursion overflow if a lot 
of comment nodes get strung together. */
+                       // swallow it
+                       // XXX This could lead to a recursion overflow if a lot 
of comment nodes get strung together.
                        $this->read();
                        return $this->transform();
 
@@ -189,7 +332,7 @@
                }
 
     }
-
+*/
 }
 
 /*

Reply via email to