eZ Publish  [4.0]
ezdomnode.php
Go to the documentation of this file.
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 &amp; that &quot;wrapped&quot; in &lt;div&gt; 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( "&", "&amp;", $tagContent );
00931                     $tagContent = str_replace( ">", "&gt;", $tagContent );
00932                     $tagContent = str_replace( "<", "&lt;", $tagContent );
00933                     $tagContent = str_replace( "'", "&apos;", $tagContent );
00934                     $tagContent = str_replace( '"', "&quot;", $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( "&", "&amp;", $attrContent );
00986                         $attrContent = str_replace( ">", "&gt;", $attrContent );
00987                         $attrContent = str_replace( "<", "&lt;", $attrContent );
00988                         $attrContent = str_replace( "'", "&apos;", $attrContent );
00989                         $attrContent = str_replace( '"', "&quot;", $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 ?>