eZ Publish  [4.0]
ezxhtmlxmloutput.php
Go to the documentation of this file.
00001 <?php
00002 //
00003 // Definition of eZXHTMLXMLOutput class
00004 //
00005 // Created on: <18-Aug-2006 15:05:00 ks>
00006 //
00007 // ## BEGIN COPYRIGHT, LICENSE AND WARRANTY NOTICE ##
00008 // SOFTWARE NAME: eZ Publish
00009 // SOFTWARE RELEASE: 4.0.x
00010 // COPYRIGHT NOTICE: Copyright (C) 1999-2008 eZ Systems AS
00011 // SOFTWARE LICENSE: GNU General Public License v2.0
00012 // NOTICE: >
00013 //   This program is free software; you can redistribute it and/or
00014 //   modify it under the terms of version 2.0  of the GNU General
00015 //   Public License as published by the Free Software Foundation.
00016 //
00017 //   This program is distributed in the hope that it will be useful,
00018 //   but WITHOUT ANY WARRANTY; without even the implied warranty of
00019 //   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00020 //   GNU General Public License for more details.
00021 //
00022 //   You should have received a copy of version 2.0 of the GNU General
00023 //   Public License along with this program; if not, write to the Free
00024 //   Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
00025 //   MA 02110-1301, USA.
00026 //
00027 //
00028 // ## END COPYRIGHT, LICENSE AND WARRANTY NOTICE ##
00029 //
00030 
00031 /*!
00032 */
00033 
00034 //include_once( 'kernel/classes/datatypes/ezxmltext/ezxmloutputhandler.php' );
00035 ////include_once( 'lib/eztemplate/classes/eztemplateincludefunction.php' );
00036 
00037 class eZXHTMLXMLOutput extends eZXMLOutputHandler
00038 {
00039 
00040     public $OutputTags = array(
00041 
00042     'section'      => array( 'quickRender' => true,
00043                              'initHandler' => 'initHandlerSection',
00044                              'renderHandler' => 'renderChildrenOnly' ),
00045 
00046     'embed'        => array( 'initHandler' => 'initHandlerEmbed',
00047                              'renderHandler' => 'renderAll',
00048                              'attrNamesTemplate' => array( 'class' => 'classification',
00049                                                            'xhtml:id' => 'id',
00050                                                            'object_id' => false,
00051                                                            'node_id' => false,
00052                                                            'show_path' => false ),
00053                              'attrDesignKeys' => array( 'class' => 'classification' ) ),
00054 
00055     'embed-inline' => array( 'initHandler' => 'initHandlerEmbed',
00056                              'renderHandler' => 'renderInline',
00057                              'attrNamesTemplate' => array( 'class' => 'classification',
00058                                                            'xhtml:id' => 'id',
00059                                                            'object_id' => false,
00060                                                            'node_id' => false,
00061                                                            'show_path' => false ),
00062                              'attrDesignKeys' => array( 'class' => 'classification' ) ),
00063 
00064     'table'        => array( 'initHandler' => 'initHandlerTable',
00065                              'renderHandler' => 'renderAll',
00066                              'contentVarName' => 'rows',
00067                              'attrNamesTemplate' => array( 'class' => 'classification',
00068                                                            'width' => 'width' ),
00069                              'attrDesignKeys' => array( 'class' => 'classification' ) ),
00070 
00071     'tr'           => array( //'quickRender' => array( 'tr', "\n" ),
00072                              'initHandler' => 'initHandlerTr',
00073                              'renderHandler' => 'renderAll',
00074                              'attrNamesTemplate' => array( 'class' => 'classification' ),
00075                              'attrDesignKeys' => array( 'class' => 'classification' ) ),
00076 
00077     'td'           => array( 'initHandler' => 'initHandlerTd',
00078                              'renderHandler' => 'renderAll',
00079                              'attrNamesTemplate' => array( 'xhtml:width' => 'width',
00080                                                            'xhtml:colspan' => 'colspan',
00081                                                            'xhtml:rowspan' => 'rowspan',
00082                                                            'class' => 'classification' ),
00083                              'attrDesignKeys' => array( 'class' => 'classification' ) ),
00084 
00085     'th'           => array( 'initHandler' => 'initHandlerTd',
00086                              'renderHandler' => 'renderAll',
00087                              'attrNamesTemplate' => array( 'xhtml:width' => 'width',
00088                                                            'xhtml:colspan' => 'colspan',
00089                                                            'xhtml:rowspan' => 'rowspan',
00090                                                            'class' => 'classification' ),
00091                              'attrDesignKeys' => array( 'class' => 'classification' ) ),
00092 
00093     'ol'           => array( 'renderHandler' => 'renderAll',
00094                              'attrNamesTemplate' => array( 'class' => 'classification' ),
00095                              'attrDesignKeys' => array( 'class' => 'classification' ) ),
00096 
00097     'ul'           => array( 'renderHandler' => 'renderAll',
00098                              'attrNamesTemplate' => array( 'class' => 'classification' ),
00099                              'attrDesignKeys' => array( 'class' => 'classification' ) ),
00100 
00101     'li'           => array( 'renderHandler' => 'renderAll',
00102                              'attrNamesTemplate' => array( 'class' => 'classification' ),
00103                              'attrDesignKeys' => array( 'class' => 'classification' ) ),
00104 
00105     'header'       => array( 'initHandler' => 'initHandlerHeader',
00106                              'renderHandler' => 'renderAll',
00107                              'attrNamesTemplate' => array( 'class' => 'classification' ),
00108                              'attrDesignKeys' => array( 'class' => 'classification' ) ),
00109 
00110     'paragraph'    => array( //'quickRender' => array( 'p', "\n" ),
00111                              'renderHandler' => 'renderParagraph',
00112                              'attrNamesTemplate' => array( 'class' => 'classification' ),
00113                              'attrDesignKeys' => array( 'class' => 'classification' ) ),
00114 
00115     'line'         => array( //'quickRender' => array( '', "<br/>" ),
00116                              'renderHandler' => 'renderLine' ),
00117 
00118     'literal'      => array( 'renderHandler' => 'renderAll',
00119                              'attrNamesTemplate' => array( 'class' => 'classification' ),
00120                              'attrDesignKeys' => array( 'class' => 'classification' ) ),
00121 
00122     'strong'       => array( 'renderHandler' => 'renderInline',
00123                              'attrNamesTemplate' => array( 'class' => 'classification' ),
00124                              'attrDesignKeys' => array( 'class' => 'classification' ) ),
00125 
00126     'emphasize'    => array( 'renderHandler' => 'renderInline',
00127                              'attrNamesTemplate' => array( 'class' => 'classification' ),
00128                              'attrDesignKeys' => array( 'class' => 'classification' ) ),
00129 
00130     'link'         => array( 'initHandler' => 'initHandlerLink',
00131                              'renderHandler' => 'renderInline',
00132                              'attrNamesTemplate' => array( 'xhtml:id' => 'id',
00133                                                            'xhtml:title' => 'title',
00134                                                            'url_id' => false,
00135                                                            'object_id' => false,
00136                                                            'node_id' => false,
00137                                                            'show_path' => false,
00138                                                            'ezurl_id' => false,
00139                                                            'anchor_name' => false,
00140                                                            'class' => 'classification' ),
00141                              'attrDesignKeys' => array( 'class' => 'classification' ) ),
00142 
00143     'anchor'       => array( 'renderHandler' => 'renderInline' ),
00144 
00145     'custom'       => array( 'initHandler' => 'initHandlerCustom',
00146                              'renderHandler' => 'renderCustom',
00147                              'attrNamesTemplate' => array( 'name' => false ) ),
00148 
00149     '#text'        => array( 'quickRender' => true,
00150                              'renderHandler' => 'renderText' )
00151     );
00152 
00153     function eZXHTMLXMLOutput( &$xmlData, $aliasedType, $contentObjectAttribute = null )
00154     {
00155         $this->eZXMLOutputHandler( $xmlData, $aliasedType, $contentObjectAttribute );
00156 
00157         $ini = eZINI::instance('ezxml.ini');
00158         if ( $ini->variable( 'ezxhtml', 'RenderParagraphInTableCells' ) == 'disabled' )
00159             $this->RenderParagraphInTableCells = false;
00160     }
00161 
00162     function initHandlerSection( $element, &$attributes, &$siblingParams, &$parentParams )
00163     {
00164         $ret = array();
00165         if( !isset( $parentParams['section_level'] ) )
00166             $parentParams['section_level'] = 0;
00167         else
00168             $parentParams['section_level']++;
00169 
00170         // init header counter for current level and for the next level if needed
00171         $level = $parentParams['section_level'];
00172         if ( $level != 0 )
00173         {
00174             if ( !isset( $this->HeaderCount[$level] ) )
00175                 $this->HeaderCount[$level] = 0;
00176 
00177             if ( !isset( $this->HeaderCount[$level + 1] ) )
00178                 $this->HeaderCount[$level + 1] = 0;
00179         }
00180 
00181         return $ret;
00182     }
00183 
00184     function initHandlerHeader( $element, &$attributes, &$siblingParams, &$parentParams )
00185     {
00186         $level = $parentParams['section_level'];
00187         $this->HeaderCount[$level]++;
00188 
00189         // headers auto-numbering
00190         $i = 1;
00191         $headerAutoName = '';
00192         while ( $i <= $level )
00193         {
00194             if ( $i > 1 )
00195                 $headerAutoName .= "_";
00196 
00197             $headerAutoName .= $this->HeaderCount[$i];
00198             $i++;
00199         }
00200         $levelNumber = str_replace( "_", ".", $headerAutoName );
00201 
00202         if ( $this->ObjectAttributeID )
00203             $headerAutoName = $this->ObjectAttributeID . '_' . $headerAutoName;
00204 
00205         $ret = array( 'tpl_vars' => array( 'level' => $level,
00206                                            'header_number' => $levelNumber,
00207                                            'toc_anchor_name' => $headerAutoName ) );
00208 
00209         return $ret;
00210     }
00211 
00212     function initHandlerLink( $element, &$attributes, &$siblingParams, &$parentParams )
00213     {
00214         $ret = array();
00215 
00216         // Set link parameters for rendering children of link tag
00217         $href='';
00218         if ( $element->getAttribute( 'url_id' ) != null )
00219         {
00220             $linkID = $element->getAttribute( 'url_id' );
00221             if ( isset( $this->LinkArray[$linkID] ) )
00222                 $href = $this->LinkArray[$linkID];
00223         }
00224         elseif ( $element->getAttribute( 'node_id' ) != null )
00225         {
00226             $nodeID = $element->getAttribute( 'node_id' );
00227             $node = isset( $this->NodeArray[$nodeID] ) ? $this->NodeArray[$nodeID] : null;
00228 
00229             if ( $node != null )
00230             {
00231                 $view = $element->getAttribute( 'view' );
00232                 if ( $view )
00233                     $href = 'content/view/' . $view . '/' . $nodeID;
00234                 else
00235                     $href = $node->attribute( 'url_alias' );
00236             }
00237             else
00238             {
00239                 eZDebug::writeWarning( "Node #$nodeID doesn't exist", "XML output handler: link" );
00240             }
00241         }
00242         elseif ( $element->getAttribute( 'object_id' ) != null )
00243         {
00244             $objectID = $element->getAttribute( 'object_id' );
00245             if ( isset( $this->ObjectArray["$objectID"] ) )
00246             {
00247                 $object = $this->ObjectArray["$objectID"];
00248                 $node = $object->attribute( 'main_node' );
00249                 if ( $node )
00250                 {
00251                     $nodeID = $node->attribute( 'node_id' );
00252 
00253                     $view = $element->getAttribute( 'view' );
00254                     if ( $view )
00255                         $href = 'content/view/' . $view . '/' . $nodeID;
00256                     else
00257                         $href = $node->attribute( 'url_alias' );
00258                 }
00259                 else
00260                 {
00261                     eZDebug::writeWarning( "Object #$objectID doesn't have assigned nodes", "XML output handler: link" );
00262                 }
00263             }
00264             else
00265             {
00266                 eZDebug::writeWarning( "Object #$objectID doesn't exist", "XML output handler: link" );
00267             }
00268         }
00269         elseif ( $element->getAttribute( 'href' ) != null )
00270         {
00271             $href = $element->getAttribute( 'href' );
00272         }
00273 
00274         if ( $element->getAttribute( 'anchor_name' ) != null )
00275         {
00276             $href .= '#' . $element->getAttribute( 'anchor_name' );
00277         }
00278 
00279         if ( $href !== false )
00280         {
00281             $attributes['href'] = $href;
00282             $parentParams['link_parameters'] = $attributes;
00283         }
00284 
00285         return $ret;
00286     }
00287 
00288     function initHandlerEmbed( $element, &$attributes, &$siblingParams, &$parentParams )
00289     {
00290         // default return value in case of errors
00291         $ret = array( 'no_render' => true );
00292 
00293         $tplSuffix = '';
00294         $objectID = $element->getAttribute( 'object_id' );
00295         if ( $objectID &&
00296              !empty( $this->ObjectArray["$objectID"] ) )
00297         {
00298             $object = $this->ObjectArray["$objectID"];
00299         }
00300         else
00301         {
00302             $nodeID = $element->getAttribute( 'node_id' );
00303             if ( $nodeID )
00304             {
00305                 if ( isset( $this->NodeArray[$nodeID] ) )
00306                 {
00307                     $node = $this->NodeArray[$nodeID];
00308                     $objectID = $node->attribute( 'contentobject_id' );
00309                     $object = $node->object();
00310                     $tplSuffix = '_node';
00311                 }
00312                 else
00313                 {
00314                     eZDebug::writeWarning( "Node #$nodeID doesn't exist", "XML output handler: embed" );
00315                     return $ret;
00316                 }
00317             }
00318         }
00319 
00320         if ( !isset( $object ) || !$object || !( $object instanceof eZContentObject ) )
00321         {
00322             eZDebug::writeWarning( "Can't fetch object #$objectID", "XML output handler: embed" );
00323             return $ret;
00324         }
00325         if ( $object->attribute( 'status' ) != eZContentObject::STATUS_PUBLISHED )
00326         {
00327             eZDebug::writeWarning( "Object #$objectID is not published", "XML output handler: embed" );
00328             return $ret;
00329         }
00330 
00331         if ( $object->attribute( 'can_read' ) ||
00332              $object->attribute( 'can_view_embed' ) )
00333         {
00334             $templateName = $element->nodeName . $tplSuffix;
00335         }
00336         else
00337         {
00338             $templateName = $element->nodeName . '_denied';
00339         }
00340 
00341         $objectParameters = array();
00342         $excludeAttrs = array( 'view', 'class', 'node_id', 'object_id' );
00343 
00344         foreach ( array_keys( $attributes ) as $attrName )
00345         {
00346            $value = $attributes[$attrName];
00347            if ( !in_array( $attrName, $excludeAttrs ) )
00348            {
00349                if ( strpos( $attrName, ':' ) !== false )
00350                    $attrName = substr( $attrName, strpos( $attrName, ':' ) + 1 );
00351 
00352                $objectParameters[$attrName] = $value;
00353                unset( $attributes[$attrName] );
00354            }
00355         }
00356 
00357         if ( isset( $parentParams['link_parameters'] ) )
00358             $linkParameters = $parentParams['link_parameters'];
00359         else
00360             $linkParameters = array();
00361 
00362         $ret = array( 'template_name' => $templateName,
00363                       'tpl_vars' => array( 'object' => $object,
00364                                            'link_parameters' => $linkParameters,
00365                                            'object_parameters' => $objectParameters ),
00366                       'design_keys' => array( 'class_identifier', $object->attribute( 'class_identifier' ) ) );
00367 
00368         if ( $tplSuffix == '_node')
00369             $ret['tpl_vars']['node'] = $node;
00370 
00371         return $ret;
00372     }
00373 
00374     function initHandlerTable( $element, &$attributes, &$siblingParams, &$parentParams )
00375     {
00376         // Numbers of rows and cols are lower by 1 for back-compatibility.
00377         $rows = $element->childNodes;
00378         $rowCount = $rows->length;
00379         $rowCount--;
00380         $lastRow = $element->lastChild;
00381         $cols = $lastRow->childNodes;
00382         $colCount = $cols->length;
00383         if ( $colCount )
00384             $colCount--;
00385 
00386         $ret = array( 'tpl_vars' => array( 'col_count' => $colCount,
00387                                            'row_count' => $rowCount ) );
00388         return $ret;
00389     }
00390 
00391     function initHandlerTr( $element, &$attributes, &$siblingParams, &$parentParams )
00392     {
00393         $ret = array();
00394         if( !isset( $siblingParams['table_row_count'] ) )
00395             $siblingParams['table_row_count'] = 0;
00396         else
00397             $siblingParams['table_row_count']++;
00398 
00399         $parentParams['table_row_count'] = $siblingParams['table_row_count'];
00400 
00401         // Number of cols is lower by 1 for back-compatibility.
00402         $cols = $element->childNodes;
00403         $colCount = $cols->length;
00404         if ( $colCount )
00405             $colCount--;
00406 
00407         $ret = array( 'tpl_vars' => array( 'row_count' => $parentParams['table_row_count'],
00408                                            'col_count' => $colCount ) );
00409         return $ret;
00410     }
00411 
00412     function initHandlerTd( $element, &$attributes, &$siblingParams, &$parentParams )
00413     {
00414         if( !isset( $siblingParams['table_col_count'] ) )
00415             $siblingParams['table_col_count'] = 0;
00416         else
00417             $siblingParams['table_col_count']++;
00418 
00419         $ret = array( 'tpl_vars' => array( 'col_count' => &$siblingParams['table_col_count'],
00420                                            'row_count' => &$parentParams['table_row_count'] ) );
00421         return $ret;
00422     }
00423 
00424     function initHandlerCustom( $element, &$attributes, &$siblingParams, &$parentParams )
00425 {
00426         $ret = array( 'template_name' => $attributes['name'] );
00427         return $ret;
00428     }
00429 
00430     // Render handlers
00431 
00432     function renderParagraph( $element, $childrenOutput, $vars )
00433     {
00434         // don't render if inside 'li' or inside 'td' (by option)
00435         $parent = $element->parentNode;
00436 
00437         if ( ( $parent->nodeName == 'li' && $parent->childNodes->length == 1 ) ||
00438              ( $parent->nodeName == 'td' && $parent->childNodes->length == 1 && !$this->RenderParagraphInTableCells ) )
00439         {
00440             return $childrenOutput;
00441         }
00442 
00443         // break paragraph by block tags
00444         $tagText = '';
00445         $lastTagInline = null;
00446         $inlineContent = '';
00447         foreach( $childrenOutput as $key=>$childOutput )
00448         {
00449             if ( $childOutput[0] === true )
00450                 $inlineContent .= $childOutput[1];
00451 
00452             if ( ( $childOutput[0] === false && $lastTagInline === true ) ||
00453                  ( $childOutput[0] === true && !array_key_exists( $key + 1, $childrenOutput ) ) )
00454             {
00455                 $tagText .= $this->renderTag( $element, $inlineContent, $vars );
00456                 $inlineContent = '';
00457             }
00458 
00459             if ( $childOutput[0] === false )
00460                 $tagText .= $childOutput[1];
00461 
00462             $lastTagInline = $childOutput[0];
00463         }
00464         return array( false, $tagText );
00465     }
00466 
00467     function renderInline( $element, $childrenOutput, $vars )
00468     {
00469         $renderedArray = array();
00470         $lastTagInline = null;
00471         $inlineContent = '';
00472 
00473         foreach( $childrenOutput as $key=>$childOutput )
00474         {
00475             if ( $childOutput[0] === true )
00476                 $inlineContent .= $childOutput[1];
00477 
00478             // Render only inline parts, block parts just passed to parent
00479             if ( ( $childOutput[0] === false && $lastTagInline === true ) ||
00480                  ( $childOutput[0] === true && !array_key_exists( $key + 1, $childrenOutput ) ) )
00481             {
00482                 $tagText = $this->renderTag( $element, $inlineContent, $vars );
00483                 $renderedArray[] = array( true, $tagText );
00484                 $inlineContent = '';
00485             }
00486 
00487             if ( $childOutput[0] === false )
00488                 $renderedArray[] = array( false, $childOutput[1] );
00489 
00490             $lastTagInline = $childOutput[0];
00491 
00492         }
00493         return $renderedArray;
00494     }
00495 
00496     function renderLine( $element, $childrenOutput, $vars )
00497     {
00498         $renderedArray = array();
00499         $lastTagInline = null;
00500         $inlineContent = '';
00501 
00502         foreach( $childrenOutput as $key=>$childOutput )
00503         {
00504             if ( $childOutput[0] === true )
00505                 $inlineContent .= $childOutput[1];
00506 
00507             // Render line tag only if the last part of childrenOutput is inline and the next tag
00508             // within the same paragraph is 'line' too.
00509 
00510             if ( $childOutput[0] === false && $lastTagInline === true )
00511             {
00512                 $renderedArray[] = array( true, $inlineContent );
00513                 $inlineContent = '';
00514             }
00515             elseif ( $childOutput[0] === true && !array_key_exists( $key + 1, $childrenOutput ) )
00516             {
00517                 $next = $element->nextSibling;
00518                 if ( $next && $next->nodeName == 'line' )
00519                 {
00520                     $tagText = $this->renderTag( $element, $inlineContent, $vars );
00521                     $renderedArray[] = array( true, $tagText );
00522                 }
00523                 else
00524                     $renderedArray[] = array( true, $inlineContent );
00525             }
00526 
00527             if ( $childOutput[0] === false )
00528                 $renderedArray[] = array( false, $childOutput[1] );
00529 
00530             $lastTagInline = $childOutput[0];
00531         }
00532         return $renderedArray;
00533     }
00534 
00535     function renderCustom( $element, $childrenOutput, $vars )
00536     {
00537         if ( $this->XMLSchema->isInline( $element ) )
00538         {
00539             $ret = $this->renderInline( $element, $childrenOutput, $vars );
00540         }
00541         else
00542         {
00543             $ret = $this->renderAll( $element, $childrenOutput, $vars );
00544         }
00545         return $ret;
00546     }
00547 
00548     function renderChildrenOnly( $element, $childrenOutput, $vars )
00549     {
00550         $tagText = '';
00551         foreach( $childrenOutput as $childOutput )
00552         {
00553             $tagText .= $childOutput[1];
00554         }
00555 
00556         return array( false, $tagText );
00557     }
00558 
00559     function renderText( $element, $childrenOutput, $vars )
00560     {
00561         if ( $element->parentNode->nodeName != 'literal' )
00562         {
00563             $text = htmlspecialchars( $element->textContent );
00564             // Get rid of linebreak and spaces stored in xml file
00565             $text = preg_replace( "#[\n]+#", "", $text );
00566 
00567             if ( $this->AllowMultipleSpaces )
00568                 $text = preg_replace( "#  #", " &nbsp;", $text );
00569             else
00570                 $text = preg_replace( "# +#", " ", $text );
00571 
00572             if ( $this->AllowNumericEntities )
00573                 $text = preg_replace( '/&amp;#([0-9]+);/', '&#\1;', $text );
00574         }
00575         else
00576         {
00577             $text = $element->textContent;
00578         }
00579 
00580         return array( true, $text );
00581     }
00582 
00583 
00584     /// Array of parameters for rendering tags that are children of 'link' tag
00585     public $LinkParameters = array();
00586 
00587     public $HeaderCount = array();
00588 
00589     public $RenderParagraphInTableCells = true;
00590 }
00591 
00592 ?>