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