|
eZ Publish
[4.0]
|
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 ?>