|
eZ Publish
[4.0]
|
00001 <?php 00002 // 00003 // Definition of eZDOMNode class 00004 // 00005 // Created on: <16-Nov-2001 12:11:43 bf> 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 /*! \file ezdomnode.php 00032 DOM node handling 00033 */ 00034 00035 /*! 00036 \class eZDOMNode ezdomnode.php 00037 \ingroup eZXML 00038 \brief eZDOMNode encapsulates XML DOM nodes 00039 00040 The following node types are supported: 00041 - Element node, has value \c 1 00042 - Attribute node, has value \c 2 00043 - Text node, has value \c 3 00044 - CDATA node, has value \c 4 00045 00046 \sa eZXML eZDOMDocument 00047 */ 00048 00049 class eZDOMNode 00050 { 00051 /*! 00052 Element node, defines a node which contains attributes and children 00053 */ 00054 const TYPE_ELEMENT = 1; 00055 /*! 00056 Attribute node, defines a node which contains an attribute name and it's value 00057 */ 00058 const TYPE_ATTRIBUTE = 2; 00059 /*! 00060 Text node, defines a node which contains a text string encoded by escaping some characters. 00061 */ 00062 const TYPE_TEXT = 3; 00063 /*! 00064 CDATA node, defines a node which contains a text string encoding in a CDATA structure. 00065 */ 00066 const TYPE_CDATASECTION = 4; 00067 00068 /*! 00069 Initializes the DOM node. 00070 */ 00071 function eZDOMNode() 00072 { 00073 $this->content =& $this->value; 00074 $this->Content =& $this->content; 00075 $this->Name =& $this->tagname; 00076 $this->Type =& $this->type; 00077 $this->nodeName =& $this->Name; 00078 } 00079 00080 function __clone() 00081 { 00082 $children = $this->Children; 00083 $this->children = array(); 00084 foreach( $children as $child ) 00085 { 00086 $this->children[] = clone $child; 00087 } 00088 $attributes = $this->attributes; 00089 $this->attributes = array(); 00090 foreach ( $attributes as $attribute ) 00091 { 00092 $this->attributes[] = clone $attribute; 00093 } 00094 } 00095 00096 /*! 00097 Subtree destructor. Needed to clean memory properly. 00098 */ 00099 static function cleanup( $node ) 00100 { 00101 if ( $node->hasChildren() ) 00102 { 00103 foreach( array_keys( $node->Children ) as $key ) 00104 { 00105 $child =& $node->Children[$key]; 00106 if ( $child->hasChildren() ) 00107 { 00108 $child->cleanup( $child ); 00109 } 00110 00111 } 00112 $node->removeChildren(); 00113 } 00114 } 00115 00116 /*! 00117 \return The name of the node. 00118 00119 For element and attributes nodes this will the name supplied when creating the node, 00120 for text nodes it returns \c #text and CDATA returns \c #cdata-section 00121 */ 00122 function name() 00123 { 00124 return $this->Name; 00125 } 00126 00127 /*! 00128 Sets the current name to \a $name. 00129 */ 00130 function setName( $name ) 00131 { 00132 $this->Name = $name; 00133 $this->LocalName = $name; 00134 } 00135 00136 /*! 00137 \return The namespace URI for the node or \c false if no URI 00138 */ 00139 function namespaceURI() 00140 { 00141 return $this->NamespaceURI; 00142 } 00143 00144 /*! 00145 Sets the namespace URI of the node to \a $uri. 00146 */ 00147 function setNamespaceURI( $uri ) 00148 { 00149 $this->NamespaceURI = $uri; 00150 } 00151 00152 /*! 00153 Returns the local name of the node if the node uses namespaces. If not false is returned. 00154 */ 00155 function localName() 00156 { 00157 return $this->LocalName; 00158 } 00159 00160 /*! 00161 \return The prefix of the nodes name, this will be the namespace for the node. 00162 */ 00163 function prefix() 00164 { 00165 return $this->Prefix; 00166 } 00167 00168 /*! 00169 Sets the namespace prefix for this node to \a $value. 00170 */ 00171 function setPrefix( $value ) 00172 { 00173 $this->Prefix = $value; 00174 } 00175 00176 /*! 00177 \return An integer value which describes the type of node. 00178 00179 The type is one of: 00180 - 1 - Element node, that is a node which contains attributes and children. 00181 - 2 - Attribute node, this is a node which contains a name and a value. 00182 - 3 - Text node, this is a node which contains a text string 00183 - 4 - CDATA node, this is a node which contains a text string 00184 */ 00185 function type() 00186 { 00187 return $this->Type; 00188 } 00189 00190 /*! 00191 Sets the node type to \a $type. 00192 00193 Use one of the following defines for the type: 00194 - eZDOMNode::TYPE_ELEMENT - Element nodes 00195 - eZDOMNode::TYPE_ATTRIBUTE - Attribute nodes 00196 - eZDOMNode::TYPE_TEXT - Text nodes 00197 - eZDOMNode::TYPE_CDATASECTION - CDATA nodes 00198 */ 00199 function setType( $type ) 00200 { 00201 $this->Type = $type; 00202 } 00203 00204 /*! 00205 \return The content of the node or \c false if it does not contain any content. 00206 00207 \note This will only make sense for text and CDATA nodes. 00208 */ 00209 function &content() 00210 { 00211 return $this->Content; 00212 } 00213 00214 /*! 00215 Sets the content of the node to the \a $content. 00216 00217 \note This will only make sense for text and CDATA nodes. 00218 */ 00219 function setContent( $content ) 00220 { 00221 $this->Content = $content; 00222 } 00223 00224 /*! 00225 \return An array with attribute nodes. 00226 00227 \note This will only make sense for element nodes. 00228 */ 00229 function &attributes() 00230 { 00231 return $this->Attributes; 00232 } 00233 00234 /*! 00235 \return An array with attribute nodes matching the namespace URI \a $namespaceURI. 00236 00237 \note This will only make sense for element nodes. 00238 */ 00239 function &attributesNS( $namespaceURI ) 00240 { 00241 $ret = array(); 00242 if ( count( $this->Attributes ) > 0 ) 00243 { 00244 foreach ( $this->Attributes as $attribute ) 00245 { 00246 if ( $attribute->namespaceURI() == $namespaceURI ) 00247 { 00248 00249 $ret[] = $attribute; 00250 } 00251 } 00252 } 00253 return $ret; 00254 } 00255 00256 /*! 00257 \return \c true if the node has any attributes. 00258 00259 \note This will only make sense for element nodes. 00260 */ 00261 function hasAttributes() 00262 { 00263 return count( $this->Attributes ) > 0; 00264 } 00265 00266 /*! 00267 \return The number of attributes for the node. 00268 00269 \note This will only make sense for element nodes. 00270 */ 00271 function attributeCount() 00272 { 00273 return count( $this->Attributes ); 00274 } 00275 00276 /*! 00277 \return An array with child nodes. 00278 00279 \note This will only make sense for element nodes. 00280 */ 00281 function &children() 00282 { 00283 return $this->Children; 00284 } 00285 00286 /*! 00287 \return \c true if the node has children. 00288 00289 \note This will only make sense for element nodes. 00290 */ 00291 function hasChildren() 00292 { 00293 return count( $this->Children ) > 0; 00294 } 00295 00296 /*! 00297 \return The number of children for the node. 00298 00299 \note This will only make sense for element nodes. 00300 */ 00301 function childrenCount() 00302 { 00303 return count( $this->Children ); 00304 } 00305 00306 /*! 00307 \return first child of current dom node. 00308 00309 \note added for compatibility with DOM XML library 00310 */ 00311 function first_child() 00312 { 00313 return isset( $this->Children[0] ) ? $this->Children[0] : null; 00314 } 00315 00316 /*! 00317 \return node value of current dom node. 00318 00319 \note added for compatibility with DOM XML library 00320 */ 00321 function node_value() 00322 { 00323 return $this->Content; 00324 } 00325 00326 /*! 00327 Finds the first element named \a $name and returns the children of that node. 00328 If no element node is found it returns \c false. 00329 00330 \note This will only make sense for element nodes. 00331 \note If multiple elements with that name is found \c false is returned. 00332 \sa elementByName, children 00333 */ 00334 function &elementChildrenByName( $name ) 00335 { 00336 $element =& $this->elementByName( $name ); 00337 if ( !$element ) 00338 { 00339 $children = false; 00340 return $children; 00341 } 00342 return $element->children(); 00343 } 00344 00345 /*! 00346 Finds the first element named \a $name and returns the first child of that node. 00347 If no element node is found or there are not children it returns \c false. 00348 00349 \note This will only make sense for element nodes. 00350 \note If multiple elements with that name is found \c false is returned. 00351 \sa elementByName, firstChild 00352 */ 00353 function &elementFirstChildByName( $name ) 00354 { 00355 $element =& $this->elementByName( $name ); 00356 if ( !$element ) 00357 { 00358 $child = false; 00359 return $child; 00360 } 00361 return $element->firstChild(); 00362 } 00363 00364 /*! 00365 \deprecated Use firstElementByName() instead. 00366 \returns The first element that is named \a $name. 00367 If multiple elements with that name is found \c false is returned. 00368 00369 \note This will only make sense for element nodes. 00370 \sa elementsByName 00371 */ 00372 function &elementByName( $name ) 00373 { 00374 $element = false; 00375 foreach ( array_keys( $this->Children ) as $key ) 00376 { 00377 $child =& $this->Children[$key]; 00378 if ( $child->name() == $name ) 00379 { 00380 if ( $element ) 00381 { 00382 $retValue = false; 00383 return $retValue; 00384 } 00385 $element =& $child; 00386 } 00387 } 00388 return $element; 00389 } 00390 00391 /* 00392 \returns The first element that is named \a $name. 00393 If multiple elements with that name is found \c false is returned. 00394 00395 \note This will only make sense for element nodes. 00396 */ 00397 function &firstElementByName( $name ) 00398 { 00399 $element = false; 00400 foreach ( array_keys( $this->Children ) as $key ) 00401 { 00402 $child =& $this->Children[$key]; 00403 if ( $child->name() == $name && !$child->prefix() ) 00404 { 00405 $element =& $child; 00406 break; 00407 } 00408 } 00409 return $element; 00410 } 00411 00412 /*! 00413 Alias for libxml compatibility 00414 */ 00415 function get_elements_by_tagname( $name ) 00416 { 00417 $elements = array(); 00418 foreach ( array_keys( $this->Children ) as $key ) 00419 { 00420 $child =& $this->Children[$key]; 00421 if ( $child->name() == $name ) 00422 $elements[] =& $child; 00423 } 00424 00425 return $elements; 00426 } 00427 00428 /*! 00429 Finds the first element named \a $name and returns the text content of that node. 00430 If no element node is found or no text content exists it returns \c false. 00431 00432 \note This will only make sense for element nodes. 00433 \note If multiple elements with that name is found \c false is returned. 00434 \sa elementByName, textContent 00435 */ 00436 function elementTextContentByName( $name ) 00437 { 00438 $element = $this->elementByName( $name ); 00439 if ( !$element ) 00440 { 00441 return false; 00442 } 00443 00444 return $element->textContent(); 00445 } 00446 00447 /*! 00448 \param attribute name 00449 \param attribute value 00450 00451 \return element by attribute value 00452 */ 00453 function &elementByAttributeValue( $attr, $value ) 00454 { 00455 foreach ( array_keys( $this->Children ) as $key ) 00456 { 00457 $child =& $this->Children[$key]; 00458 if ( $child->attributeValue( $attr ) == $value ) 00459 { 00460 return $child; 00461 } 00462 } 00463 00464 unset( $child ); 00465 $child = false; 00466 return $child; 00467 } 00468 00469 /*! 00470 \deprecated Use getElementsByTagName/getElementsByTagNameNS instead. 00471 \return An array with elements that matches the name \a $name. 00472 00473 \note This will only make sense for element nodes. 00474 \sa elementByName 00475 */ 00476 function &elementsByName( $name ) 00477 { 00478 $elements = array(); 00479 foreach ( array_keys( $this->Children ) as $key ) 00480 { 00481 $child =& $this->Children[$key]; 00482 if ( $child->name() == $name ) 00483 { 00484 $elements[] =& $child; 00485 } 00486 } 00487 return $elements; 00488 } 00489 00490 /*! 00491 \return An array with text contents taken from all child nodes which matches the name \a $name. 00492 00493 \note This will only make sense for element nodes. 00494 \sa elementsByName, textContent 00495 */ 00496 function &elementsTextContentByName( $name ) 00497 { 00498 $elements = array(); 00499 foreach ( array_keys( $this->Children ) as $key ) 00500 { 00501 $child =& $this->Children[$key]; 00502 if ( $child->name() == $name ) 00503 { 00504 $elements[] = $child->textContent(); 00505 } 00506 } 00507 return $elements; 00508 } 00509 00510 /*! 00511 \deprecated This function is deprecated. 00512 Use getAttribute instead. 00513 00514 \return The value of the attribute named \a $attributeName. 00515 If no value is found \c false is returned. 00516 00517 \note This will only make sense for element nodes. 00518 */ 00519 function attributeValue( $attributeName ) 00520 { 00521 $returnValue = false; 00522 foreach ( $this->Attributes as $attribute ) 00523 { 00524 if ( $attribute->name() == $attributeName ) 00525 $returnValue = $attribute->content(); 00526 } 00527 00528 return $returnValue; 00529 } 00530 00531 /*! 00532 Alias for libxml compatibility 00533 */ 00534 function get_attribute( $attributeName ) 00535 { 00536 return $this->attributeValue( $attributeName ); 00537 } 00538 00539 /*! 00540 Finds the first element named \a $name and returns the value of the attribute named \a $attributeName. 00541 If no element node is found or no attribute with the given name exists it returns \c false. 00542 00543 \note This will only make sense for element nodes. 00544 \note If multiple elements with that name is found \c false is returned. 00545 \sa elementByName, attributeValue 00546 */ 00547 function elementAttributeValueByName( $name, $attributeName ) 00548 { 00549 $element = $this->elementByName( $name ); 00550 if ( !$element ) 00551 return false; 00552 else 00553 return $element->attributeValue( $attributeName ); 00554 } 00555 00556 /*! 00557 Goes trough all attributes of the node and matches the attribute names 00558 with the parameter \a $attributeDefinitions. 00559 00560 \param $attributeDefinitions An associative array which maps from matching attribute name to lookup name. 00561 \param $defaultValue If other value than \c null it will be set as value for all lookup names that didn't match 00562 00563 The matching attribute name in the will be matched against the attributes of the node. 00564 When a match is found the attribute value will be fetched and placed in the returned 00565 associative array using lookup name as key. 00566 00567 A code example will explain this, the variable \a $songNode contains the following xml 00568 \code 00569 <song name="Shine On You Crazy Diamond" track="1" /> 00570 \endcode 00571 00572 The PHP code is. 00573 \code 00574 $def = array( 'name' => 'song_name', 00575 'track' => 'track_number' ); 00576 $values = $songNode->attributeValues( $def ); 00577 \endcode 00578 00579 \a $values will now contain. 00580 \code 00581 array( 'song_name' => 'Shine On You Crazy Diamond', 00582 'track_number => '1' ) 00583 \endcode 00584 00585 This method and appendAttributes() work together, the values inserted with appendAttributes() 00586 can be extracted with this method. 00587 00588 \note This will only make sense for element nodes. 00589 \sa elementAttributeValueByName, appendAttributes 00590 */ 00591 function attributeValues( $attributeDefinitions = false, $defaultValue = null ) 00592 { 00593 $hash = array(); 00594 foreach ( $this->Attributes as $attribute ) 00595 { 00596 if ( $attributeDefinitions === false ) 00597 { 00598 $hash[$attribute->name()] = $attribute->content(); 00599 continue; 00600 } 00601 00602 foreach ( $attributeDefinitions as $attributeName => $keyName ) 00603 { 00604 if ( $attribute->name() == $attributeName ) 00605 { 00606 $hash[$keyName] = $attribute->content(); 00607 break; 00608 } 00609 } 00610 } 00611 if ( $defaultValue !== null ) 00612 { 00613 foreach ( $attributeDefinitions as $attributeName => $keyName ) 00614 { 00615 if ( !isset( $hash[$keyName] ) ) 00616 $hash[$keyName] = $defaultValue; 00617 } 00618 } 00619 00620 return $hash; 00621 } 00622 00623 /*! 00624 \deprecated This function is deprecated. 00625 Use getAttributeNS instead. 00626 00627 \return The value of the attribute named \a $attributeName and having namespace \a $namespaceURI. 00628 If no value is found \c false is returned. 00629 00630 \note This will only make sense for element nodes. 00631 */ 00632 function attributeValueNS( $attributeName, $namespaceURI ) 00633 { 00634 $returnValue = false; 00635 if ( count( $this->Attributes ) > 0 ) 00636 { 00637 foreach ( $this->Attributes as $attribute ) 00638 { 00639 if ( $attribute->name() == $attributeName && 00640 $attribute->namespaceURI() == $namespaceURI ) 00641 { 00642 00643 $returnValue = $attribute->content(); 00644 } 00645 } 00646 } 00647 00648 return $returnValue; 00649 } 00650 00651 /*! 00652 Appends the node \a $node as a child of the current node. 00653 00654 \return The node that was just inserted. 00655 00656 \note This will only make sense for element nodes. 00657 */ 00658 function appendChild( eZDOMNode $node ) 00659 { 00660 if ( $this->parentNode !== false ) 00661 $node->parentNode =& $this; 00662 00663 $this->Children[] =& $node; 00664 return $node; 00665 } 00666 00667 /*! 00668 Alias for libXML compatibility 00669 */ 00670 function append_child( &$node ) 00671 { 00672 return $this->appendChild( $node ); 00673 } 00674 00675 /*! 00676 Appends the attribute node \a $node as an attribute of the current node. 00677 00678 \return The attribute node that was just inserted. 00679 00680 \note This will only make sense for element nodes. 00681 */ 00682 function appendAttribute( eZDOMNode $node ) 00683 { 00684 $this->Attributes[] =& $node; 00685 return $node; 00686 } 00687 00688 function set_attribute( $name, $value ) 00689 { 00690 $this->removeNamedAttribute( $name ); 00691 return $this->appendAttribute( eZDOMDocument::createAttributeNode( $name, $value ) ); 00692 } 00693 00694 /*! 00695 Appends multiple attributes and attribute values. 00696 00697 \param $attributeValues An associative array containing the attribute values to insert, 00698 it maps from lookup name to attribute value. 00699 \param $attributeDefinitions An associative array defining how lookup names maps to attribute names, 00700 the array key is the attribute name and the array value the lookup name. 00701 \param $includeEmptyValues If \c true it will set attribute values even though they don't exist in \a $attributeValues 00702 00703 \code 00704 $definition = array( 'name' => 'song_name', 00705 'track' => 'track_name' ); 00706 $values = array( 'song_name' => 'Shine On You Crazy Diamond', 00707 'track_number' => '1' ); 00708 $node->appendAttributes( $values, $definition ); 00709 \endcode 00710 00711 The node will then look like. 00712 \code 00713 <song name="Shine On You Crazy Diamond" track="1" /> 00714 \endcode 00715 00716 This method and attributeValues() work together, the returned result of attributeValues() 00717 can be inserted with this method. 00718 00719 \note This will only make sense for element nodes. 00720 \sa attributeValues 00721 */ 00722 function appendAttributes( $attributeValues, 00723 $attributeDefinitions, 00724 $includeEmptyValues = false ) 00725 { 00726 foreach ( $attributeDefinitions as $attributeXMLName => $attributeKey ) 00727 { 00728 if ( $includeEmptyValues or 00729 ( isset( $attributeValues[$attributeKey] ) and 00730 $attributeValues[$attributeKey] !== false ) ) 00731 { 00732 $value = false; 00733 if ( isset( $attributeValues[$attributeKey] ) and 00734 $attributeValues[$attributeKey] !== false ) 00735 $value = $attributeValues[$attributeKey]; 00736 $this->Attributes[] = eZDOMDocument::createAttributeNode( $attributeXMLName, $value ); 00737 } 00738 } 00739 } 00740 00741 /*! 00742 Removes the attribute node named \a $name. 00743 \return The removed attribute node or \c false if no such node exists. 00744 00745 \note This will only make sense for element nodes. 00746 */ 00747 function removeNamedAttribute( $name ) 00748 { 00749 $removed = false; 00750 foreach( array_keys( $this->Attributes ) as $key ) 00751 { 00752 if ( $this->Attributes[$key]->name() == $name ) 00753 { 00754 unset( $this->Attributes[$key] ); 00755 $removed = true; 00756 } 00757 } 00758 return $removed; 00759 } 00760 00761 /*! 00762 Alias for libxml compatibility 00763 */ 00764 function remove_attribute( $name ) 00765 { 00766 return $this->removeNamedAttribute( $name ); 00767 } 00768 00769 /*! 00770 Removes all attribute from the node. 00771 00772 \note This will only make sense for element nodes. 00773 */ 00774 function removeAttributes() 00775 { 00776 $this->Attributes = array(); 00777 } 00778 00779 /*! 00780 Removes all child nodes that matches the name \a $name. 00781 \return \c true if it removed any nodes, otherwise \c false. 00782 00783 \note This will only make sense for element nodes. 00784 */ 00785 function removeNamedChildren( $name ) 00786 { 00787 $removed = false; 00788 foreach( array_keys( $this->Children ) as $key ) 00789 { 00790 if ( $this->Children[$key]->name() == $name ) 00791 { 00792 if ( $this->parentNode !== false ) 00793 { 00794 unset( $this->Children[$key]->parentNode ); 00795 $this->Children[$key]->parentNode = null; 00796 } 00797 unset( $this->Children[$key] ); 00798 $removed = true; 00799 } 00800 } 00801 return $removed; 00802 } 00803 00804 /*! 00805 Removes all child nodes from the current node. 00806 00807 \note This will only make sense for element nodes. 00808 */ 00809 function removeChildren() 00810 { 00811 if ( $this->parentNode !== false ) 00812 { 00813 foreach( array_keys( $this->Children ) as $key ) 00814 { 00815 unset( $this->Children[$key]->parentNode ); 00816 $this->Children[$key]->parentNode = null; 00817 } 00818 } 00819 00820 $this->Children = array(); 00821 } 00822 00823 /*! 00824 Removes the last child node of the current node. 00825 00826 \note This will only make sense for element nodes. 00827 */ 00828 function removeLastChild() 00829 { 00830 end( $this->Children ); 00831 $key = key( $this->Children ); 00832 if ( $this->parentNode !== false ) 00833 { 00834 unset( $this->Children[$key]->parentNode ); 00835 $this->Children[$key]->parentNode = null; 00836 } 00837 00838 unset( $this->Children[$key] ); 00839 } 00840 00841 /*! 00842 Removes child by the given child object. 00843 00844 \note W3C DOM function 00845 */ 00846 function removeChild( &$childToRemove ) 00847 { 00848 if ( $childToRemove->parentNode !== false ) 00849 { 00850 unset( $childToRemove->parentNode ); 00851 $childToRemove->parentNode = null; 00852 } 00853 $childToRemove->flag = true; 00854 00855 foreach ( array_keys( $this->Children ) as $key ) 00856 { 00857 if ( $this->Children[$key]->flag === true ) 00858 { 00859 unset( $this->Children[$key] ); 00860 break; 00861 } 00862 } 00863 $childToRemove->flag = false; 00864 } 00865 00866 /*! 00867 \return The content() of the first child node or \c false if there are no children. 00868 00869 \note This will only make sense for element nodes. 00870 \sa elementTextContentByName 00871 */ 00872 function textContent() 00873 { 00874 return $this->collectTextContent( $this ); 00875 } 00876 00877 function collectTextContent( $element ) 00878 { 00879 $ret = ''; 00880 if ( $element->Type == eZDOMNode::TYPE_TEXT or 00881 $element->Type == eZDOMNode::TYPE_CDATASECTION ) 00882 { 00883 $ret = $element->content(); 00884 } 00885 else 00886 { 00887 if ( count( $element->Children ) > 0 ) 00888 { 00889 foreach( array_keys( $element->Children ) as $key ) 00890 { 00891 $child =& $element->Children[$key]; 00892 $ret .= $this->collectTextContent( $child ); 00893 } 00894 } 00895 } 00896 return $ret; 00897 } 00898 00899 /*! 00900 \return A string that represents the current node. 00901 The string will be created according to the node type which are: 00902 - Element node, places the name in <>, expands all attributes and calls toString() on all children. 00903 - Text node, returns the content() by escaping the characters & < > ' and ". 00904 - CDATA node, returns the text wrapped in <![CDATA[ and ]] 00905 00906 \param $level The current tab level, starts at 0 and is increased by 1 for each recursion 00907 \param $charset Which charset the text will be encoded in, currently not used 00908 00909 Example strings. 00910 \code 00911 '<song name="Shine On You Crazy Diamond" track="1" />' 00912 'This & that "wrapped" in <div> tags' 00913 '<![CDATA[This & that "wrapped" in <div> tags' 00914 \endcode 00915 00916 \note This will only make sense for element nodes. 00917 */ 00918 function toString( $level, $charset = false, $convertSpecialChars = true ) 00919 { 00920 $spacer = str_repeat( " ", $level*2 ); 00921 $ret = ""; 00922 switch ( $this->Name ) 00923 { 00924 case "#text" : 00925 { 00926 $tagContent = $this->Content; 00927 // convert special chars 00928 if ( $convertSpecialChars ) 00929 { 00930 $tagContent = str_replace( "&", "&", $tagContent ); 00931 $tagContent = str_replace( ">", ">", $tagContent ); 00932 $tagContent = str_replace( "<", "<", $tagContent ); 00933 $tagContent = str_replace( "'", "'", $tagContent ); 00934 $tagContent = str_replace( '"', """, $tagContent ); 00935 } 00936 00937 $ret = $tagContent; 00938 }break; 00939 00940 case "#cdata-section" : 00941 { 00942 $ret = "<![CDATA["; 00943 $ret .= $this->Content; 00944 $ret .= "]]>"; 00945 }break; 00946 00947 default : 00948 { 00949 $isOneLiner = false; 00950 // check if it's a oneliner 00951 if ( count( $this->Children ) == 0 and ( $this->Content == "" ) ) 00952 $isOneLiner = true; 00953 00954 $attrStr = ""; 00955 00956 // check for namespace definition 00957 if ( $this->namespaceURI() != "" ) 00958 { 00959 $attrPrefix = ""; 00960 if ( $this->Prefix != "" ) 00961 $attrPrefix = ":" . $this->prefix(); 00962 $attrStr = " xmlns" . $attrPrefix . "=\"" . $this->namespaceURI() . "\""; 00963 } 00964 00965 $prefix = ""; 00966 if ( $this->Prefix != false ) 00967 $prefix = $this->Prefix. ":"; 00968 00969 // generate attributes string 00970 if ( count( $this->Attributes ) > 0 ) 00971 { 00972 $i = 0; 00973 foreach ( $this->Attributes as $attr ) 00974 { 00975 $attrPrefix = ""; 00976 if ( $attr->prefix() != false ) 00977 $attrPrefix = $attr->prefix(). ":"; 00978 00979 if ( $i > 0 ) 00980 $attrStr .= "\n" . $spacer . str_repeat( " ", strlen( $prefix . $this->Name ) + 1 + 1 ); 00981 else 00982 $attrStr .= ' '; 00983 00984 $attrContent = $attr->content(); 00985 $attrContent = str_replace( "&", "&", $attrContent ); 00986 $attrContent = str_replace( ">", ">", $attrContent ); 00987 $attrContent = str_replace( "<", "<", $attrContent ); 00988 $attrContent = str_replace( "'", "'", $attrContent ); 00989 $attrContent = str_replace( '"', """, $attrContent ); 00990 00991 $attrStr .= $attrPrefix . $attr->name() . "=\"" . $attrContent . "\""; 00992 ++$i; 00993 } 00994 } 00995 00996 if ( $isOneLiner ) 00997 $oneLinerEnd = " /"; 00998 else 00999 $oneLinerEnd = ""; 01000 01001 $ret = ''; 01002 01003 if ( $this->Name =='link' ) //don't insert enything before <link> tag 01004 { 01005 $ret .= "<" . $prefix . $this->Name . $attrStr . $oneLinerEnd . ">"; 01006 } 01007 else //make alignment 01008 { 01009 if ( $level > 0 ) 01010 $ret .= "\n"; 01011 $ret .= "$spacer<" . $prefix . $this->Name . $attrStr . $oneLinerEnd . ">"; 01012 } 01013 01014 $lastChildType = false; 01015 if ( count( $this->Children ) > 0 ) 01016 { 01017 foreach ( $this->Children as $child ) 01018 { 01019 $ret .= $child->toString( $level + 1, $charset, $convertSpecialChars ); 01020 $lastChildType = $child->type(); 01021 } 01022 } 01023 01024 if ( !$isOneLiner ) 01025 { 01026 if ( $lastChildType == 1 ) 01027 $ret .= "\n$spacer"; 01028 $ret .= "</" . $prefix . $this->Name . ">"; 01029 } 01030 // $ret .= "$spacer</" . $prefix . $this->Name . ">\n"; 01031 01032 }break; 01033 } 01034 return $ret; 01035 } 01036 01037 /*! 01038 Alias for libxml compatibility 01039 */ 01040 function dump_mem( $format, $charset = false ) 01041 { 01042 return $this->toString( 0, $charset); 01043 } 01044 01045 01046 /* 01047 W3C DOM compatibility functions 01048 */ 01049 // \note W3C DOM function 01050 01051 function setAttribute( $name, $value ) 01052 { 01053 foreach ( $this->Attributes as $attribute ) 01054 { 01055 if ( $attribute->name() == $name ) 01056 { 01057 $attribute->setContent( $value ); 01058 return $attribute; 01059 } 01060 } 01061 01062 $attr = eZDOMDocument::createAttribute( $name ); 01063 $attr->setContent( $value ); 01064 return $this->appendAttribute( $attr ); 01065 } 01066 01067 // \note W3C DOM function 01068 01069 function setAttributeNS( $namespaceURI, $qualifiedName, $value ) 01070 { 01071 foreach ( $this->Attributes as $attribute ) 01072 { 01073 if ( !$attribute->Prefix ) 01074 continue; 01075 01076 $fullName = $attribute->Prefix . ':' . $attribute->LocalName; 01077 if ( $fullName == $qualifiedName ) 01078 { 01079 $attribute->setContent( $value ); 01080 return $attribute; 01081 } 01082 } 01083 $attr = eZDOMDocument::createAttributeNS( $namespaceURI, $qualifiedName ); 01084 $attr->setContent( $value ); 01085 return $this->appendAttribute( $attr ); 01086 } 01087 01088 // \note W3C DOM function 01089 function getAttribute( $attributeName ) 01090 { 01091 $returnValue = ''; 01092 foreach ( $this->Attributes as $attribute ) 01093 { 01094 if ( $attribute->name() == $attributeName && !$attribute->Prefix ) 01095 $returnValue = $attribute->Content; 01096 } 01097 01098 return $returnValue; 01099 } 01100 01101 // \note W3C DOM function 01102 function getAttributeNS( $namespaceURI, $localName ) 01103 { 01104 $returnValue = ''; 01105 foreach ( $this->Attributes as $attribute ) 01106 { 01107 if ( $attribute->LocalName == $localName && 01108 $attribute->NamespaceURI == $namespaceURI ) 01109 $returnValue = $attribute->Content; 01110 } 01111 01112 return $returnValue; 01113 } 01114 01115 // \note W3C DOM function 01116 function removeAttribute( $name ) 01117 { 01118 $removed = false; 01119 foreach( array_keys( $this->Attributes ) as $key ) 01120 { 01121 if ( $this->Attributes[$key]->name() == $name && !$this->Attributes[$key]->Prefix ) 01122 { 01123 unset( $this->Attributes[$key] ); 01124 $removed = true; 01125 } 01126 } 01127 return $removed; 01128 } 01129 01130 // \note W3C DOM function 01131 function removeAttributeNS( $namespaceURI, $localName ) 01132 { 01133 $removed = false; 01134 foreach( array_keys( $this->Attributes ) as $key ) 01135 { 01136 if ( $this->Attributes[$key]->LocalName == $localName && 01137 $this->Attributes[$key]->NamespaceURI == $namespaceURI ) 01138 { 01139 unset( $this->Attributes[$key] ); 01140 $removed = true; 01141 } 01142 } 01143 return $removed; 01144 } 01145 01146 /* 01147 \note W3C DOM function 01148 */ 01149 function hasChildNodes() 01150 { 01151 return count( $this->Children ) > 0; 01152 } 01153 01154 /*! 01155 \return The first child of the node or \c false if there are no children. 01156 01157 \note This will only make sense for element nodes. 01158 \note W3C DOM function 01159 */ 01160 01161 function &firstChild() 01162 { 01163 if ( count( $this->Children ) == 0 ) 01164 { 01165 $child = false; 01166 return $child; 01167 } 01168 reset( $this->Children ); 01169 $key = key( $this->Children ); 01170 $child =& $this->Children[$key]; 01171 01172 return $child; 01173 } 01174 01175 /*! 01176 \return The last child node or \c false if there are no children. 01177 01178 \note This will only make sense for element nodes. 01179 */ 01180 01181 function &lastChild() 01182 { 01183 if ( count( $this->Children ) == 0 ) 01184 { 01185 $child = false; 01186 return $child; 01187 } 01188 end( $this->Children ); 01189 $key = key( $this->Children ); 01190 $child =& $this->Children[$key]; 01191 01192 return $child; 01193 } 01194 01195 /*! 01196 Replaces child by the new one given. 01197 01198 \note W3C DOM function 01199 */ 01200 function replaceChild( &$newChild, &$oldChild ) 01201 { 01202 if ( $this->parentNode !== false ) 01203 { 01204 unset( $oldChild->parentNode ); 01205 $oldChild->parentNode = null; 01206 } 01207 $oldChild->flag = true; 01208 01209 $newChildren = array(); 01210 01211 foreach( array_keys( $this->Children ) as $key ) 01212 { 01213 if ( $this->Children[$key]->flag === true ) 01214 { 01215 if ( $this->parentNode !== false ) 01216 $newChild->parentNode =& $this; 01217 01218 $newChildren[$key] =& $newChild; 01219 } 01220 else 01221 { 01222 $newChildren[$key] =& $this->Children[$key]; 01223 } 01224 } 01225 $this->Children =& $newChildren; 01226 $oldChild->flag = false; 01227 01228 return $oldChild; 01229 } 01230 01231 /*! 01232 Replaces child by the new one given. 01233 01234 \note W3C DOM function 01235 */ 01236 function insertBefore( &$newNode, &$refNode ) 01237 { 01238 $refNode->flag = true; 01239 01240 $newChildren = array(); 01241 01242 foreach ( array_keys( $this->Children ) as $key ) 01243 { 01244 if ( $this->Children[$key]->flag === true ) 01245 { 01246 $newChildren[] =& $newNode; 01247 if ( $this->parentNode !== false ) 01248 { 01249 $newNode->parentNode =& $this; 01250 } 01251 } 01252 $newChildren[] =& $this->Children[$key]; 01253 } 01254 $this->Children =& $newChildren; 01255 $refNode->flag = false; 01256 return $newNode; 01257 } 01258 01259 /*! 01260 \note emulation of W3C DOM property 01261 */ 01262 01263 function &nextSibling() 01264 { 01265 $ret = null; 01266 if ( !$this->parentNode ) 01267 return $ret; 01268 01269 $parent =& $this->parentNode; 01270 $this->flag = true; 01271 01272 $next = false; 01273 $children =& $parent->Children; 01274 01275 foreach( array_keys( $children ) as $child_key ) 01276 { 01277 if ( $next ) 01278 { 01279 $ret =& $children[$child_key]; 01280 break; 01281 } 01282 elseif ( $children[$child_key]->flag === true ) 01283 { 01284 $next = true; 01285 } 01286 } 01287 $this->flag = false; 01288 01289 return $ret; 01290 } 01291 01292 /*! 01293 \note emulation of W3C DOM property 01294 */ 01295 01296 function &previousSibling() 01297 { 01298 $ret = null; 01299 if ( !$this->parentNode ) 01300 return $ret; 01301 01302 $parent =& $this->parentNode; 01303 $this->flag = true; 01304 01305 $prev = false; 01306 $children =& $parent->Children; 01307 foreach( array_keys( $children ) as $child_key ) 01308 { 01309 if ( $prev !== false && $children[$child_key]->flag === true ) 01310 { 01311 $ret =& $children[$prev]; 01312 break; 01313 } 01314 $prev = $child_key; 01315 } 01316 $this->flag = false; 01317 return $ret; 01318 } 01319 01320 /*! 01321 \note W3C DOM function 01322 */ 01323 01324 function getElementsByTagName( $name ) 01325 { 01326 $elements = array(); 01327 foreach ( array_keys( $this->Children ) as $key ) 01328 { 01329 $child =& $this->Children[$key]; 01330 if ( $child->name() == $name && !$child->prefix() ) 01331 $elements[] =& $child; 01332 } 01333 01334 return $elements; 01335 } 01336 01337 /*! 01338 \note W3C DOM function 01339 */ 01340 function getElementsByTagNameNS( $namespaceURI, $localName ) 01341 { 01342 $elements = array(); 01343 foreach ( array_keys( $this->Children ) as $key ) 01344 { 01345 $child =& $this->Children[$key]; 01346 if ( $child->name() == $localName && $child->namespaceURI() == $namespaceURI ) 01347 $elements[] =& $child; 01348 } 01349 01350 return $elements; 01351 } 01352 01353 /*! 01354 Outputs DOM subtree to the debug output in the easy readable form. 01355 01356 \param node subtree root node 01357 */ 01358 01359 function writeDebug( &$node, $text, $showAttributes = false, $showParent = false ) 01360 { 01361 if ( !$node ) 01362 $node =& $this; 01363 01364 if ( $node ) 01365 { 01366 if ( $node instanceof eZDOMNode ) 01367 { 01368 $d = eZDOMNode::debugNode( $node, $showAttributes, $showParent ); 01369 eZDebug::writeDebug( $d, $text ); 01370 } 01371 else 01372 { 01373 eZDebug::writeDebug( $node, $text ); 01374 } 01375 } 01376 else 01377 { 01378 eZDebug::writeDebug( array( $node ), $text ); 01379 } 01380 } 01381 01382 function debugNode( &$node, $showAttributes, $showParent ) 01383 { 01384 $d = array(); 01385 $d['name'] = $node->nodeName; 01386 if ( $node->nodeName == '#text' ) 01387 $d['text'] = $node->content; 01388 else if ( $node->Type == 2 ) 01389 $d['value'] = $node->value; 01390 01391 if ( $showParent ) 01392 $d['parent'] = $node->parentNode->nodeName; 01393 01394 if ( count( $node->Children ) ) 01395 { 01396 $d['children'] = array(); 01397 foreach( array_keys($node->Children) as $child_key ) 01398 { 01399 $d['children'][] = eZDOMNode::debugNode( $node->Children[$child_key], $showAttributes, $showParent ); 01400 } 01401 } 01402 01403 if ( $showAttributes && count( $node->Attributes ) ) 01404 { 01405 $d['attributes'] = array(); 01406 foreach( array_keys($node->Attributes) as $attr_key ) 01407 { 01408 $d['attributes'][] = eZDOMNode::debugNode( $node->Attributes[$attr_key], $showAttributes, $showParent ); 01409 } 01410 } 01411 return $d; 01412 } 01413 01414 /*! 01415 Outputs XML from DOM as a string. 01416 01417 \param node subtree root node 01418 */ 01419 static function writeDebugStr( $node, $text ) 01420 { 01421 if ( is_object( $node ) ) 01422 eZDebug::writeDebug( $node->toString( 0 ), $text ); 01423 else 01424 eZDebug::writeDebug( $node, $text ); 01425 } 01426 01427 /// \privatesection 01428 01429 /// Name of the node 01430 public $Name = false; 01431 01432 /// tagname, added for DOM XML compatibility. 01433 public $tagname = null; 01434 01435 /// DOM W3C compatibility 01436 public $nodeName = null; 01437 01438 /// Type of the DOM node. ElementNode=1, AttributeNode=2, TextNode=3, CDATASectionNode=4 01439 public $type; 01440 public $Type = eZDOMNode::TYPE_ELEMENT; 01441 01442 /// Content of the node 01443 public $content = ""; 01444 public $Content = ""; 01445 public $value = ''; 01446 01447 /// Subnodes 01448 public $Children = array(); 01449 01450 /// Attributes 01451 public $Attributes = array(); 01452 01453 /// Contains the namespace URI. E.g. xmlns="http://ez.no/article/", http://ez.no/article/ would be the namespace URI 01454 public $NamespaceURI = false; 01455 01456 /// The local part of a name. E.g: book:title, title is the local part 01457 public $LocalName = false; 01458 01459 /// contains the namespace prefix. E.g: book:title, book is the prefix 01460 public $Prefix = false; 01461 01462 /// Reference to the parent node. 01463 /// Available only if Document has been created with parameter $setParentNode = true 01464 /// or parsed with eZXML::domTree function with $params["SetParentNode"] = true 01465 public $parentNode = false; 01466 01467 // temporary flag to mark node 01468 public $flag = false; 01469 } 01470 01471 ?>