eZ Publish  [trunk]
ezsimplifiedxmleditoutput.php
Go to the documentation of this file.
00001 <?php
00002 /**
00003  * File containing the eZSimplifiedXMLEditOutput class.
00004  *
00005  * @copyright Copyright (C) 1999-2012 eZ Systems AS. All rights reserved.
00006  * @license http://www.gnu.org/licenses/gpl-2.0.txt GNU General Public License v2
00007  * @version //autogentag//
00008  * @package kernel
00009  */
00010 
00011 // if ( !class_exists( 'eZXMLSchema' ) )
00012 class eZSimplifiedXMLEditOutput
00013 {
00014     public $OutputTags = array(
00015 
00016         'section'      => array( 'handler' => 'outputSection' ),
00017 
00018         'embed'        => array( 'handler' => 'outputEmbed',
00019                                  'attributes' => array( 'xhtml:id' => 'id',
00020                                                        'object_id' => false,
00021                                                        'node_id' => false,
00022                                                        'show_path' => false ),
00023                                  'isSingle' => true ),
00024 
00025         'embed-inline' => array( 'handler' => 'outputEmbed',
00026                                  'attributes' => array( 'xhtml:id' => 'id',
00027                                                        'object_id' => false,
00028                                                        'node_id' => false,
00029                                                        'show_path' => false ),
00030                                  'isSingle' => true ),
00031 
00032         'object'       => array( 'handler' => 'outputObject',
00033                                  'attributes' => array( 'xhtml:id' => 'id',
00034                                                        'image:ezurl_target' => 'target',
00035                                                        'image:ezurl_href' => 'href',
00036                                                        'image:ezurl_id' => false ),
00037                                  'isSingle' => true ),
00038 
00039         'td'           => array( 'handler' => 'outputTd',
00040                                  'attributes' => array( 'xhtml:width' => 'width',
00041                                                        'xhtml:colspan' => 'colspan',
00042                                                        'xhtml:rowspan' => 'rowspan' ) ),
00043 
00044         'th'           => array( 'handler' => 'outputTd',
00045                                  'attributes' => array( 'xhtml:width' => 'width',
00046                                                        'xhtml:colspan' => 'colspan',
00047                                                        'xhtml:rowspan' => 'rowspan' ) ),
00048 
00049         'header'       => array( 'handler' => 'outputHeader' ),
00050 
00051         'paragraph'    => array( 'handler' => 'outputParagraph' ),
00052 
00053         'line'         => array( 'handler' => 'outputLine' ),
00054 
00055         'link'         => array( 'handler' => 'outputLink',
00056                                  'attributes' => array( 'xhtml:id' => 'id',
00057                                                         'xhtml:title' => 'title',
00058                                                         'url_id' => false,
00059                                                         'object_id' => false,
00060                                                         'node_id' => false,
00061                                                         'show_path' => false,
00062                                                         'ezurl_id' => false,
00063                                                         'anchor_name' => false ) ),
00064         'anchor'       => array( 'isSingle' => true ),
00065 
00066         '#text'        => array( 'handler' => 'outputText' )
00067         );
00068 
00069     // Call this function to obtain edit output string
00070 
00071     function performOutput( $dom )
00072     {
00073         $this->XMLSchema = eZXMLSchema::instance();
00074         $this->NestingLevel = 0;
00075         $this->Output = '';
00076         $sectionLevel = -1;
00077 
00078         $this->createLinksArray( $dom );
00079 
00080         $this->outputTag( $dom->documentElement, $sectionLevel );
00081 
00082         return $this->Output;
00083     }
00084 
00085     function outputTag( $element, $sectionLevel )
00086     {
00087         $tagName = $element->nodeName;
00088         if ( isset( $this->OutputTags[$tagName] ) )
00089         {
00090             $currentTag = $this->OutputTags[$tagName];
00091 
00092             if ( isset( $currentTag['attributes'] ) )
00093                 $attributeRules = $currentTag['attributes'];
00094         }
00095         else
00096         {
00097             $currentTag = null;
00098         }
00099 
00100         //eZDebugSetting::writeDebug( 'kernel-datatype-ezxmltext', 'outputting tag ' . $element->nodeName );
00101 
00102         // Prepare attributes array
00103 
00104         $attributes = array();
00105 
00106         if ( $element->hasAttributes() )
00107         {
00108             $attributeNodes = $element->attributes;
00109 
00110             foreach ( $attributeNodes as $attrNode )
00111             {
00112                 if ( $attrNode->prefix && $attrNode->prefix != 'custom' )
00113                 {
00114                     $attrName = $attrNode->prefix . ':' . $attrNode->localName;
00115                 }
00116                 else
00117                 {
00118                     $attrName = $attrNode->nodeName;
00119                 }
00120 
00121                 $attributes[$attrName] = $attrNode->value;
00122             }
00123         }
00124 
00125         // Call tag handler
00126         $result = null;
00127         if ( $currentTag && isset( $currentTag['handler'] ) )
00128         {
00129             $result = $this->callOutputHandler( 'handler', $element, $attributes, $sectionLevel );
00130         }
00131 
00132         $hasChildren = $element->hasChildNodes();
00133         $isInline = $this->XMLSchema->isInline( $element );
00134         //eZDebugSetting::writeDebug( 'kernel-datatype-ezxmltext', $isInline ? 'yes' : 'no', 'is inline element?' );
00135         $isSingle = isset( $currentTag['isSingle'] ) && $currentTag['isSingle'];
00136         //eZDebugSetting::writeDebug( 'kernel-datatype-ezxmltext', $isSingle ? 'yes' : 'no', 'is single element?' );
00137 
00138         // If output was not set by handler, do a normal tag output
00139         if ( !is_string( $result ) )
00140         {
00141             // Convert (if needed) and output attributes
00142             $attrString = '';
00143             foreach ( array_keys( $attributes ) as $name )
00144             {
00145                 $value = $attributes[$name];
00146                 if ( isset( $attributeRules ) && isset( $attributeRules[$name] ) )
00147                 {
00148                     if ( !$attributeRules[$name] )
00149                         continue;
00150 
00151                     $name = $attributeRules[$name];
00152                 }
00153                 $attrString .= ' ' . $name . '="' . $value . '"';
00154             }
00155 
00156             $this->formatBeforeOpeningTag( $element, $isInline, $hasChildren );
00157 
00158             //Output opening tag
00159             $closing = $isSingle ? ' />' : '>';
00160 
00161             $this->Output .= '<' . $tagName . $attrString . $closing;
00162 
00163             if ( !$isSingle )
00164             {
00165                 $this->formatAfterOpeningTag( $element, $isInline, $hasChildren );
00166             }
00167 
00168             $this->NestingLevel++;
00169 
00170             //eZDebugSetting::writeDebug( 'kernel-datatype-ezxmltext', $this->Output, 'output so far' );
00171         }
00172 
00173         if ( $element->hasChildNodes() )
00174         {
00175             // Process children
00176             foreach ( $element->childNodes as $child )
00177             {
00178                 $this->outputTag( $child, $sectionLevel );
00179             }
00180         }
00181 
00182         if ( is_string( $result ) )
00183         {
00184             $this->Output .= $result;
00185             return;
00186         }
00187         else
00188         {
00189             $this->NestingLevel--;
00190             if ( !$isSingle )
00191             {
00192                 $this->formatBeforeClosingTag( $element, $isInline, $hasChildren );
00193 
00194                 $this->Output .= '</' . $tagName . '>';
00195             }
00196 
00197             $this->formatAfterClosingTag( $element, $isInline, $hasChildren );
00198         }
00199 
00200         return;
00201     }
00202 
00203     function formatBeforeOpeningTag( $element, $isInline, $hasChildren )
00204     {
00205         // Add indenting for block tags
00206         if ( !$isInline )
00207         {
00208             if ( $this->NestingLevel > 0 )
00209             {
00210                 $this->Output .= str_repeat( '  ', $this->NestingLevel );
00211             }
00212         }
00213     }
00214 
00215     function formatAfterOpeningTag( $element, $isInline, $hasChildren )
00216     {
00217         // Add linebreak in case we have block tag as a first child
00218         if ( !$isInline && $hasChildren )
00219         {
00220             $firstChild = $element->firstChild;
00221             if ( $firstChild && $firstChild->nodeName == 'paragraph' && !$firstChild->hasAttributes() )
00222             {
00223                 $firstChild = $firstChild->firstChild;
00224             }
00225             if ( $firstChild && $firstChild->nodeName == 'line' )
00226             {
00227                 $firstChild = $firstChild->firstChild;
00228             }
00229             if ( $firstChild && !$this->XMLSchema->isInline( $firstChild ) )
00230             {
00231                 $this->Output .= "\n";
00232             }
00233         }
00234     }
00235 
00236     function formatBeforeClosingTag( $element, $isInline, $hasChildren )
00237     {
00238         if ( !$isInline && $hasChildren )
00239         {
00240             $lastChild = $element->lastChild;
00241             if ( $lastChild && $lastChild->nodeName == 'paragraph' && !$lastChild->hasAttributes() )
00242             {
00243                 $lastChild = $lastChild->lastChild;
00244             }
00245             if ( $lastChild && $lastChild->nodeName == 'line' )
00246             {
00247                 $lastChild = $lastChild->lastChild;
00248             }
00249             if ( $lastChild && !$this->XMLSchema->isInline( $lastChild ) )
00250             {
00251                 // Add line breaks and indenting for block tags
00252                 $this->Output .= "\n";
00253                 if ( $this->NestingLevel > 0 )
00254                 {
00255                     $this->Output .= str_repeat( '  ', $this->NestingLevel );
00256                 }
00257             }
00258         }
00259     }
00260 
00261     function formatAfterClosingTag( $element, $isInline, $hasChildren )
00262     {
00263         if ( !$isInline )
00264         {
00265             $next = $element->nextSibling;
00266             if ( $next )
00267             {
00268                 $this->Output .= "\n";
00269             }
00270             else
00271             {
00272                 $parent = $element->parentNode;
00273                 while( $parent && $parent->nodeName == 'section' )
00274                 {
00275                     $next = $parent->nextSibling;
00276                     if ( $next )
00277                     {
00278                         $this->Output .= "\n";
00279                         break;
00280                     }
00281                     $parent = $parent->parentNode;
00282                 }
00283             }
00284         }
00285     }
00286 
00287     function callOutputHandler( $handlerName, $element, &$params, &$sectionLevel )
00288     {
00289         $result = null;
00290         $thisOutputTag = $this->OutputTags[$element->nodeName];
00291         if ( isset( $thisOutputTag[$handlerName] ) )
00292         {
00293             if ( is_callable( array( $this, $thisOutputTag[$handlerName] ) ) )
00294             {
00295                 $result = call_user_func_array( array( $this, $thisOutputTag[$handlerName] ),
00296                                                 array( $element, &$params, &$sectionLevel ) );
00297             }
00298             else
00299             {
00300                 eZDebug::writeWarning( "'$handlerName' output handler for tag <$element->nodeName> doesn't exist: '" . $thisOutputTag[$handlerName] . "'.", 'eZXML converter' );
00301             }
00302         }
00303         return $result;
00304     }
00305 
00306     /*
00307         Tag handlers
00308     */
00309     function outputSection( $element, &$attributes, &$sectionLevel )
00310     {
00311         $sectionLevel++;
00312 
00313         $ret = '';
00314         return $ret;
00315     }
00316 
00317     function outputText( $element, &$attributes, &$sectionLevel )
00318     {
00319         $text = $element->textContent;
00320 
00321         if ( $element->parentNode->nodeName != 'literal' )
00322         {
00323             $text = htmlspecialchars( $text );
00324             $text = str_replace ( '&amp;nbsp;', '&nbsp;', $text);
00325             $text = str_replace( "\n", '', $text );
00326         }
00327         return $text;
00328     }
00329 
00330     function outputTd( $element, &$attributes, &$sectionLevel )
00331     {
00332         $ret = null;
00333 
00334         // We have to reset section level in the table cell
00335         $sectionLevel = 0;
00336         return $ret;
00337     }
00338 
00339     function outputHeader( $element, &$attributes, &$sectionLevel )
00340     {
00341         $ret = null;
00342         $attributes['level'] = $sectionLevel;
00343         return $ret;
00344     }
00345 
00346     function outputParagraph( $element, &$attributes, &$sectionLevel )
00347     {
00348         $ret = null;
00349         if ( count( $attributes ) == 0 )
00350         {
00351             $next = $element->nextSibling;
00352             if ( $next )
00353             {
00354                 $ret = "\n\n";
00355             }
00356             else
00357             {
00358                 $ret = "";
00359                 $parent = $element->parentNode;
00360                 while( $parent && $parent->nodeName == 'section' )
00361                 {
00362                     $next = $parent->nextSibling;
00363                     if ( $next )
00364                     {
00365                         $ret = "\n\n";
00366                         break;
00367                     }
00368                     $parent = $parent->parentNode;
00369                 }
00370             }
00371         }
00372         return $ret;
00373     }
00374 
00375     function outputLine( $element, &$attributes, &$sectionLevel )
00376     {
00377         $ret = '';
00378         $next = $element->nextSibling;
00379         if ( is_object( $next ) )
00380         {
00381             $ret = "\n";
00382         }
00383         return $ret;
00384     }
00385 
00386     function outputEmbed( $element, &$attributes, &$sectionLevel )
00387     {
00388         $ret = null;
00389         $href = '';
00390         $objectID = isset( $attributes['object_id'] ) ? $attributes['object_id'] : null;
00391         $nodeID = isset( $attributes['node_id'] ) ? $attributes['node_id'] : null;
00392         $showPath = isset( $attributes['show_path'] ) ? $attributes['show_path'] : null;
00393         if ( $objectID )
00394         {
00395             $href = 'ezobject://' .$objectID;
00396         }
00397         elseif ( $nodeID )
00398         {
00399             $href = eZSimplifiedXMLEditOutput::eznodeHref( $nodeID, $showPath );
00400         }
00401         $attributes['href'] = $href;
00402         return $ret;
00403     }
00404 
00405     function outputObject( $element, &$attributes, &$sectionLevel )
00406     {
00407         $ret = null;
00408         if ( isset( $attributes['image:ezurl_id'] ) )
00409         {
00410             $linkID = $attributes['image:ezurl_id'];
00411             if ( $linkID != null )
00412             {
00413                 $href = eZURL::url( $linkID );
00414                 $attributes['href'] = $href;
00415             }
00416         }
00417         return $ret;
00418     }
00419 
00420     function outputLink( $element, &$attributes, &$sectionLevel )
00421     {
00422         $ret = null;
00423         $href = '';
00424         $linkID = isset( $attributes['url_id'] ) ? $attributes['url_id'] : null;
00425         $objectID = isset( $attributes['object_id'] ) ? $attributes['object_id'] : null;
00426         $nodeID = isset( $attributes['node_id'] ) ? $attributes['node_id'] : null;
00427         $anchorName = isset( $attributes['anchor_name'] ) ? $attributes['anchor_name'] : null;
00428         $showPath = isset( $attributes['show_path'] ) ? $attributes['show_path'] : null;
00429 
00430         if ( $objectID )
00431         {
00432             $href = 'ezobject://' .$objectID;
00433         }
00434         elseif ( $nodeID )
00435         {
00436             $href = eZSimplifiedXMLEditOutput::eznodeHref( $nodeID, $showPath );
00437         }
00438         elseif ( $linkID )
00439         {
00440             // Fetch URL from cached array
00441             $href = $this->LinkArray[$linkID];
00442         }
00443         else
00444         {
00445             $href = isset( $attributes['href'] ) ? $attributes['href'] : '';
00446         }
00447 
00448         if ( $anchorName != null )
00449         {
00450             $href .= '#' . $anchorName;
00451         }
00452 
00453         $attributes['href'] = $href;
00454         return $ret;
00455     }
00456 
00457     /*!
00458       Helper function to generate the href attribute value for the eznode:// protocol
00459      */
00460     static function eznodeHref( $nodeID, $showPath )
00461     {
00462         if ( $showPath == 'true' )
00463         {
00464             $node = eZContentObjectTreeNode::fetch( $nodeID, false, false );
00465             $href = $node ? 'eznode://' . $node['path_identification_string'] : 'eznode://' . $nodeID;
00466         }
00467         else
00468         {
00469             $href = 'eznode://' . $nodeID;
00470         }
00471 
00472         return $href;
00473     }
00474 
00475     /*!
00476       Helper function to prepare links array
00477     */
00478     function createLinksArray( $dom )
00479     {
00480         $links = array();
00481         $node = array();
00482 
00483         if ( $dom )
00484         {
00485             // Fetch all links and cache the url's
00486             $links = $dom->getElementsByTagName( "link" );
00487         }
00488 
00489         $linkIDArray = array();
00490         // Find all Link id's
00491         foreach ( $links as $link )
00492         {
00493             $linkIDValue = $link->getAttribute( 'url_id' );
00494             if ( !$linkIDValue )
00495             {
00496                 continue;
00497             }
00498             if ( !in_array( $linkIDValue, $linkIDArray ) )
00499             {
00500                  $linkIDArray[] = $linkIDValue;
00501              }
00502         }
00503 
00504         if ( count( $linkIDArray ) > 0 )
00505         {
00506             $inIDSQL = implode( ', ', $linkIDArray );
00507             $db = eZDB::instance();
00508             $linkArray = $db->arrayQuery( "SELECT * FROM ezurl WHERE id IN ( $inIDSQL ) " );
00509             foreach ( $linkArray as $linkRow )
00510             {
00511                 $this->LinkArray[$linkRow['id']] = $linkRow['url'];
00512             }
00513         }
00514     }
00515 
00516     public $XMLSchema;
00517     public $Output = '';
00518     public $NestingLevel = 0;
00519 
00520     // Contains all links hashed by ID
00521     public $LinkArray = array();
00522 }
00523 ?>