The Tree component enables you to create, manipulate and query tree structures.
The component provides many operations on
trees, as well as on the nodes in the trees. Because there are different
algorithms for storing tree structures in a relational databaseâeach with
different propertiesâthe component supports multiple back-ends. The Tree
component itself comes with a memory (ezcTreeMemory) and XML (ezcTreeXml)
back-end. The TreeDatabaseTiein component provides three back-ends that store
the tree structure in a database table.
Aside from storing the hierarchical data itself, the component also enables you to
associate data with the tree nodes. The data is stored through a data store.
Depending on the back-ends, different data stores are available, as shown in the
following table:
To use a tree, you will need both a tree back-end (a class inherited from
ezcTree), and a data store (implementation of the ezcTreeDataStore interface).
The following example shows how to instantiate a new tree object using
the ezcTreeXml back-end and the ezcTreeXmlInternalDataStore data store:
- <?php
- require_once 'tutorial_autoload.php';
-
- $store = new ezcTreeXmlInternalDataStore();
- $tree = new ezcTreeXml( 'files/example1.xml', $store );
-
- $f = $tree->fetchNodeById( 'F' );
- echo $f->data, "<br/>\n"; // echos Fluorine
- ?>
Lines 4 and 5 define the data store and the tree. The parameters to ezcTree's
constructor specify which file and data store to use. After opening the
tree, lines 7 and 8 demonstrate how to fetch a node from the tree by using the
node ID, and then access the data that belongs to the node. IDs can be either
integer numbers or strings. There are a few restrictions when using strings as
IDs; they must:
- be a valid PHP array key
- consist of XML NameChar characters only
Memory trees can never be instantiated, because there is no permanent storage
available. They will always have to be created from scratch or created from
another tree by using the ezcTree::copy() method.
It is possible to run many operations on trees and nodes, other than fetching
the nodes. The following example demonstrates two different types of
operations on the tree or on nodes.
- <?php
- require_once 'tutorial_autoload.php';
-
- $store = new ezcTreeXmlInternalDataStore();
- $tree = new ezcTreeXml( 'files/example1.xml', $store );
-
- if ( $tree->fetchNodeById( 'F' )
- ->isDescendantOf( $tree->fetchNodeById( 'NonMetals' ) ) )
- {
- echo "Flourine is a non-metal.<br/>\n";
- }
-
- if ( $tree->isDescendantOf( 'O', 'NonMetals' ) )
- {
- echo "Oxygen is a non-metal.<br/>\n";
- }
-
- $nonMetals = $tree->fetchSubtree( 'NonMetals' );
- echo "We found {$nonMetals->size} non-metals: \n";
- foreach ( $nonMetals->nodes as $node )
- {
- echo "- {$node->id}: {$node->data} \n";
- }
- ?>
Lines 7 to 11 show how to tell whether a node is a descendant of another
node. Most of the operations can also be done directly on the tree by using
the node IDs. This is shown in lines 13 to 16. All operations are
implemented on the tree level, so using the syntax in lines 13 to 16 will
result in slightly higher performance. Lines 18 to 23 demonstrate another tree
operation: fetching a sub-tree. All operations that can return more than one
node do so as an ezcTreeNodeList.
Refer to the ezcTreeNode documentation for a full list of supported
operations.
When you iterate over a node list manually, such as in the previous examples,
the associated data is fetched on demand - at the moment the ->data property of
a node is requested. If you have a large node list to be returned, this can
create many database queries if you are using a database-based back-end and data store.
In such cases, you might want to fetch all data in one go - with one query. The
ezcTreeNodeListIterator class enables you to do this:
- <?php
- require_once 'tutorial_autoload.php';
-
- $store = new ezcTreeXmlInternalDataStore();
- $tree = new ezcTreeXml( 'files/example1.xml', $store );
-
- $noble = $tree->fetchChildren( 'NobleGasses' );
- echo "We found {$noble->size} noble gasses: \n";
-
- foreach ( new ezcTreeNodeListIterator( $tree, $noble, true ) as $nodeId => $nodeData )
- {
- echo "- {$nodeId}: {$nodeData} \n";
- }
- ?>
In line 7 we use the ezcTree->fetchChildren() method to find all the direct
children of the node with the ID "NobleGasses". Then in lines 10 to 13 we create a
ezcTreeNodeListIterator over the returned ezcTreeNodeList $noble. The first
parameter is the tree, the second one is the node list, and the third parameter
specifies whether the data should be prefetched.
If you want to create a new tree, instead of instantiating a tree you use
the overloaded ezcTree::create() factory method. Once a tree and associated
store are created you can proceed to fill the tree with nodes. The example
below demonstrates this (and creates the XML file that is used in the other
examples in this tutorial):
- <?php
- require_once 'tutorial_autoload.php';
-
- $store = new ezcTreeXmlInternalDataStore();
- $tree = ezcTreeXml::create( 'files/example1.xml', $store );
-
- $rootNode = $tree->createNode( 'Elements', 'Elements' );
- $tree->setRootNode( $rootNode );
-
- $nonMetal = $tree->createNode( 'NonMetals', 'Non-Metals' );
- $rootNode->addChild( $nonMetal );
- $nobleGasses = $tree->createNode( 'NobleGasses', 'Noble Gasses' );
- $rootNode->addChild( $nobleGasses );
-
- $nonMetal->addChild( $tree->createNode( 'H', 'Hydrogen' ) );
- $nonMetal->addChild( $tree->createNode( 'C', 'Carbon' ) );
- $nonMetal->addChild( $tree->createNode( 'N', 'Nitrogen' ) );
- $nonMetal->addChild( $tree->createNode( 'O', 'Oxygen' ) );
- $nonMetal->addChild( $tree->createNode( 'P', 'Phosphorus' ) );
- $nonMetal->addChild( $tree->createNode( 'S', 'Sulfur' ) );
- $nonMetal->addChild( $tree->createNode( 'Se', 'Selenium' ) );
-
- $nobleGasses->addChild( $tree->createNode( 'F', 'Fluorine' ) );
- $nobleGasses->addChild( $tree->createNode( 'Cl', 'Chlorine' ) );
- $nobleGasses->addChild( $tree->createNode( 'Br', 'Bromine' ) );
- $nobleGasses->addChild( $tree->createNode( 'I', 'Iodine' ) );
- ?>
In line 5 we create a new tree by using the ezcTreeXml::create() factory
method. The name of the file is the first argument and the data store is the
second argument. This will create a completely empty tree without nodes or
even a root node. In lines 7 and 8 we then create a new node with the
ezcTree->createNode() method, which accepts the node ID and node data value as
arguments. The ezcTreeDbExternalTableDataStore data store also supports
compound data values, as is listed in the documentation for
ezcTreeDbExternalTableDataStore->__construct(). Lines 10 to 13 proceed to add
two new nodes to the $rootNode and lines 15-26 add further nodes to the
$nonMetal and $nobleGasses nodes.
The Tree component also supports auto-generated IDs for tree nodes. In order to
let the component generate IDs for you, you need to set the Tree property
"autoId" to "true". In the example below we create another tree structure, but
let the Tree component generate the IDs automatically:
- <?php
- require_once 'tutorial_autoload.php';
-
- $store = new ezcTreeXmlInternalDataStore();
- $tree = ezcTreeXml::create( 'files/royals.xml', $store );
- $tree->autoId = true;
-
- $rootNode = $tree->createNode( null, 'Beatrix' );
- $tree->setRootNode( $rootNode );
-
- $willem = $tree->createNode( null, 'Willem-Alexander' );
- $rootNode->addChild( $willem );
- $friso = $tree->createNode( null, 'Friso' );
- $rootNode->addChild( $friso );
-
- echo $friso->id, "\n";
-
- $willem->addChild( $tree->createNode( null, 'Catharina' ) );
- $willem->addChild( $tree->createNode( null, 'Alexia' ) );
- $willem->addChild( $tree->createNode( null, 'Ariane' ) );
-
- $friso->addChild( $tree->createNode( null, 'Luana' ) );
- $friso->addChild( $tree->createNode( null, 'Zaria' ) );
- ?>
The main change compared to the previous example is the setting of autoId to
true in line 6. When autoId is set, the ID argument to ezcTree::createNode()
can be null. In that case an ID is automatically generated.
This property must be set immediately after instantiating the tree, unless an
already existing tree is opened through the ezcTreeXml class. For database
backends, there are a few extra requirements for the schema. The "id" field
should be defined as an auto-increment integer field, or an integer field
linked with a sequence.
The Tree component comes with two generic back-ends - one that stores the tree
structure in an XML file, and another one that only keeps a tree structure in
memory. The XML back-end uses PHP's DOM functionality to parse the tree and thus
the entire tree structure is loaded into memory when an ezcTreeXml object
is instantiated.
The ezcTreeMemory back-end has to be created from scratch when it used.
However, it is also possible to copy an ezcTreeXml-based tree to a memory-based
one. The example below demonstrates this:
- <?php
- require_once 'tutorial_autoload.php';
-
- $store = new ezcTreeXmlInternalDataStore();
- $tree = new ezcTreeXml( 'files/example1.xml', $store );
-
- $memTree = ezcTreeMemory::create( new ezcTreeMemoryDataStore() );
- ezcTree::copy( $tree, $memTree );
-
- echo $memTree->getChildCountRecursive( 'Elements' ), "\n";
- ?>
Operations on trees based on ezcTreeMemory are of course faster than operations
on trees based on ezcTreeDb or ezcTreeXml.
By installing the TreeDatabaseTiein and TreePersistentObjectTiein components,
a few more back-ends and data stores are available. There are three additional
back-ends:
- ezcTreeDbParentChild - Uses the ID of the parent to keep track of the
structure only.
- ezcTreeDbNestedSet - Uses left/right values in addition to the parent ID
that the ezcTreeDbParentChild back-end uses to keep track of the tree structure.
- ezcTreeDbMaterializedPath - Uses /1/2/4/6/19/24 style paths to store the
tree structure.
Each of those three back-ends have different performance-related properties
depending on which operation is run. The following table summarizes
some of the properties of each algorithm:
| Operation |
Back-ends |
|---|
| Parent Child |
Nested set |
Materialized Path |
|---|
| addChild() |
Simple operation. |
Possibly long, as on
average the left and
right values of half of
the nodes in the tree
have to be updated. |
Simple operation. |
| delete() |
Recursive operation
to find a whole
tree. |
Simple operation. |
Simple operation.
but query has to
use LIKE. |
| fetchChildren() |
Simple operation. |
Simple operation. |
Simple operation. |
| fetchNodeById() |
Simple operation. |
Simple operation. |
Simple operation. |
| fetchParent() |
Simple operation. |
Simple operation. |
Simple operation. |
| fetchPath() |
Recursive operation
to iterate over the
parents all the way
to the root node. |
Simple operation. |
Simple operation. |
| fetchSubtreeBreadthFirst() |
Recursive operation
to find the whole
subtree - order of
nodes for each level
is not guaranteed. |
Recursive operation to
find the whole subtree
- order of nodes for
each level is not
guaranteed. |
Recursive operation
to find the whole
subtree - order of
nodes for each level
is not guaranteed. |
| fetchSubtreeDepthFirst() |
Recursive operation
to find the whole
subtree - order of
nodes is not
guaranteed. |
Simple operation -
order of nodes is the
same order as when they
were added. |
Simple operation.
but query has to use
LIKE - order of
nodes is not
guaranteed. |
| getChildCount() |
Simple operation. |
Simple operation. |
Simple operation. |
| getChildCountRecursive() |
Recursive operation
to find the nodes in
the whole subtree. |
Simple operation. |
Simple operation.
but query has to use
LIKE. |
| getPathLength() |
Recursive operation
to iterate over the
parents all the way
to the root node. |
Simple operation. |
Simple operation. |
| hasChildNodes() |
Simple operation. |
Simple operation. |
Simple operation. |
| isChildOf() |
Simple operation. |
Simple operation. |
Simple operation. |
| isDescendantOf() |
Recursive operation
to iterate over the
parents until either
the root node or
when the node is
found. |
Simple operation. |
Simple operation. |
| isSiblingOf() |
Simple operation. |
Simple operation. |
Simple operation. |
| move() |
Simple operation. |
Possibly long, as on
average the left and
the right values of
half of the nodes need
to be updated - twice. |
All the nodes in the
subtree that is
moved need to be
updated - this is
done with string
operations. |
| nodeExists() |
Simple operation. |
Simple operation. |
Simple operation. |
| setRootNode() |
Simple operation. |
Simple operation. |
Simple operation. |
The database back-ends that the TreeDatabaseTiein component provides also
support two different data stores. One of them,
ezcTreeDbExternalTableDataStore, comes with the TreeDatabaseTiein component.
Another one, ezcTreePersistentObjectDataStore, is provided through the
TreePersistentObjectTiein component.
ezcTreeDbExternalTableDataStore can be used in two different modes. In the
first you specify a database field that is matched against the node's ID, and
another field that is used for the "data" property belonging to a node. The next
example illustrates this:
- <?php
- require_once 'tutorial_autoload.php';
-
- $dbh = ezcDbFactory::create( 'sqlite://:memory:' );
- $dbh->exec( <<<ENDSQL
- CREATE TABLE nested_set (
- 'id' varchar(255) NOT NULL,
- 'parent_id' varchar(255),
- 'lft' integer NOT NULL,
- 'rgt' integer NOT NULL
- );
- CREATE UNIQUE INDEX 'nested_set_pri' on 'nested_set' ( 'id' );
- CREATE INDEX 'nested_set_left' on 'nested_set' ( 'lft' );
- CREATE INDEX 'nested_set_right' on 'nested_set' ( 'rgt' );
-
- CREATE TABLE data (
- 'node_id' varchar(255) NOT NULL,
- 'data_field' varchar(255) NOT NULL
- );
- CREATE UNIQUE INDEX 'data_pri' on 'data' ( 'node_id' );
- ENDSQL
- );
-
- $store = new ezcTreeDbExternalTableDataStore( $dbh, 'data', 'node_id', 'data_field' );
- $tree = new ezcTreeDbNestedSet( $dbh, 'nested_set', $store );
-
- $tree->setRootNode( $rootNode = $tree->createNode( 'Elements', 'Elements' ) );
- $rootNode->addChild( $nonMetal = $tree->createNode( 'NonMetals', 'Non-Metals' ) );
- $rootNode->addChild( $nobleGasses = $tree->createNode( 'NobleGasses', 'Noble Gasses' ) );
- $nonMetal->addChild( $tree->createNode( 'H', 'Hydrogen' ) );
-
- echo $tree->fetchNodeById( 'H' )->data, "\n";
- ?>
In this example, lines 4 to 22 set up the database and database tables. Refer
to the specific database back-end's documentation for full information on
what the different tables should look like. In this case,
for the data store we only create two fields: node_id and
data_field. We can see this back in line 24, where we instantiate the store
object. We specify the database object, the name of the data table ('data'),
the field that is matched against the node ID ('node_id') and which field to
use for data ('data_field'). In lines 27 to 30 we then insert some sample nodes
and line 32 demonstrates the retrieval of data.
In the second mode, we do not specify a field to fetch data from:
- <?php
- require_once 'tutorial_autoload.php';
-
- // Setup the database tables
- $dbh = ezcDbFactory::create( 'sqlite://:memory:' );
- $dbh->exec( <<<ENDSQL
- CREATE TABLE nested_set (
- 'id' varchar(255) NOT NULL,
- 'parent_id' varchar(255),
- 'lft' integer NOT NULL,
- 'rgt' integer NOT NULL
- );
- CREATE UNIQUE INDEX 'nested_set_pri' on 'nested_set' ( 'id' );
- CREATE INDEX 'nested_set_left' on 'nested_set' ( 'lft' );
- CREATE INDEX 'nested_set_right' on 'nested_set' ( 'rgt' );
-
- CREATE TABLE data (
- 'node_id' varchar(255) NOT NULL,
- 'melting_temp_k' float,
- 'boiling_temp_k' float
- );
- CREATE UNIQUE INDEX 'data_pri' on 'data' ( 'node_id' );
- ENDSQL
- );
-
- // Setup the store and tree
- $store = new ezcTreeDbExternalTableDataStore( $dbh, 'data', 'node_id' );
- $tree = new ezcTreeDbNestedSet( $dbh, 'nested_set', $store );
-
- // Insert data
- $tree->setRootNode( $root = $tree->createNode( 'Metals', array() ) );
- $root->addChild( $tree->createNode( 'Fe', array( 'melting_temp_K' => 1811, 'boiling_temp_K' => 3134 ) ) );
-
- // Fetch data
- var_dump( $tree->fetchNodeById( 'Fe' )->data );
- ?>
Differences when compared with the previous example include the data table definition in lines
17 to 21. Instead of defining a specific data field to use, there are now
multiple fields ('melting_temp_k' and 'boiling_temp_k'). The instantiation of
the data store in line 27 now misses the fourth argument as well. The data that
is specified when creating a node now consists of an array describing all the
fields in the database table, except for the 'node_id' as that one is implicit.
When fetching the data the whole table record is returned, minus the 'node_id'
field.
The ezcTreePersistentObjectDataStore brings multiple data fields even further
and extends the Tree to use persistent objects as data for the tree nodes.
- <?php
- require_once 'tutorial_autoload.php';
-
- // Setup the database tables
- $dbh = ezcDbFactory::create( 'sqlite://:memory:' );
- $dbh->exec( <<<ENDSQL
- CREATE TABLE nested_set (
- 'id' varchar(255) NOT NULL,
- 'parent_id' varchar(255),
- 'lft' integer NOT NULL,
- 'rgt' integer NOT NULL
- );
- CREATE UNIQUE INDEX 'nested_set_pri' on 'nested_set' ( 'id' );
- CREATE INDEX 'nested_set_left' on 'nested_set' ( 'lft' );
- CREATE INDEX 'nested_set_right' on 'nested_set' ( 'rgt' );
-
- CREATE TABLE data (
- 'node_id' varchar(255) NOT NULL,
- 'melting_temp_k' float,
- 'boiling_temp_k' float
- );
- CREATE UNIQUE INDEX 'data_pri' on 'data' ( 'node_id' );
- ENDSQL
- );
-
- // Create the example Persistent Object definition files and stub classes
- $dbSchema = ezcDbSchema::createFromDb( $dbh );
- $writer1 = new ezcDbSchemaPersistentWriter( true );
- $writer2 = new ezcDbSchemaPersistentClassWriter( true );
- $writer1->saveToFile( 'files/po_defs', $dbSchema );
- $writer2->saveToFile( 'files/classes', $dbSchema );
- require 'files/classes/data.php';
-
- // Setup the store and tree
- $session = new ezcPersistentSession( $dbh, new ezcPersistentCodeManager( "files/po_defs" ) );
- $store = new ezcTreePersistentObjectDataStore( $session, 'data', 'node_id' );
- $tree = new ezcTreeDbNestedSet( $dbh, 'nested_set', $store );
-
- // Insert data
- $metal = new data();
- $tree->setRootNode( $root = $tree->createNode( 'Metals', $metal ) );
- $iron = new data();
- $iron->setState( array( 'melting_temp_k' => 1811, 'boiling_temp_k' => 3134 ) );
- $root->addChild( $tree->createNode( 'Fe', $iron ) );
-
- // Fetch data
- $fe = $tree->fetchNodeById( 'Fe' )->data;
- var_dump( $fe );
- ?>
The database tables are set up just like the previous example in lines 5 to 24.
Lines 26 to 32 then continue to use the DatabaseSchema component to write
persistent definition files and class stubs. The store is set up in lines 35 and
36. ezcTreePersistentObjectDataStore uses ezcPersistentSession as the
first argument and then the object's class and object's ID property as second
and third arguments. Unlike the previous example, you should specify the class
and property names of the persistent objects that you are storing - not
the table name and ID field. Lines 39 to 48 then show how data is inserted into
the tree, and how it is retrieved. You will most likely have to tune the
classes that are generated for you in a real life situation, as the generated
classes (line 29 and 31) only have private properties and the getState() and
setState() methods that persistent objects are required to have. Refer
to the PersistentObject documentation for more information.
Sometimes it is useful to visualize a tree structure. The Tree component has
some functionality for this in the form of different visualizers. There are
currently three possibilities.
The ezcTreeVisitorPlainText class implements a visitor pattern to render a tree
for the console. Both latin1 and utf-8 are supported as character sets, and
the utf-8 version looks much better. The following example shows how to
generated a text-based representation of the tree from the first example in
this tutorial:
- <?php
- require_once 'tutorial_autoload.php';
-
- $store = new ezcTreeXmlInternalDataStore();
- $tree = new ezcTreeXml( 'files/example1.xml', $store );
-
- $visitor = new ezcTreeVisitorPlainText( ezcTreeVisitorPlainText::SYMBOL_UTF8 );
- $tree->accept( $visitor );
- echo (string) $visitor; // print the plot
- ?>
The output is:
Elements
ââNonMetals
â ââH
â ââC
â ââN
â ââO
â ââP
â ââS
â ââSe
ââNobleGasses
ââF
ââCl
ââBr
ââI
The ezcTreeVisitorXHTML class implements another visitor that renders the trees
as nested XHTML lists. In the following example we render the same tree again
with the default options for this visitor:
- <?php
- require_once 'tutorial_autoload.php';
-
- $store = new ezcTreeXmlInternalDataStore();
- $tree = new ezcTreeXml( 'files/example1.xml', $store );
-
- $visitor = new ezcTreeVisitorXHTML();
- $tree->accept( $visitor );
- echo (string) $visitor;
- ?>
This outputs the following XHTML:
<ul>
<li><a href="/idNonMetals">Non-Metals</a>
<ul>
<li><a href="/idNonMetals/idH">Hydrogen</a></li>
<li><a href="/idNonMetals/idC">Carbon</a></li>
<li><a href="/idNonMetals/idN">Nitrogen</a></li>
<li><a href="/idNonMetals/idO">Oxygen</a></li>
<li><a href="/idNonMetals/idP">Phosphorus</a></li>
<li><a href="/idNonMetals/idS">Sulfur</a></li>
<li><a href="/idNonMetals/idSe">Selenium</a></li>
</ul>
</li>
<li><a href="/idNobleGasses">Noble Gasses</a>
<ul>
<li><a href="/idNobleGasses/idF">Fluorine</a></li>
<li><a href="/idNobleGasses/idCl">Chlorine</a></li>
<li><a href="/idNobleGasses/idBr">Bromine</a></li>
<li><a href="/idNobleGasses/idI">Iodine</a></li>
</ul>
</li>
</ul>
The ezcTreeVisitorXHTML visitor allows some options that can be set through the
constructor. Options include whether links should be added (addLinks), whether
the root node should be shown (displayRootNode) and others. The options are
documented with the ezcTreeVisitorXHTMLOptions class.
In case you are not on the console, it is also possible to render the tree as a
GraphViz .dot file that can then be used to generate an image, such as a
PNG image. The next example shows the use of the ezcTreeVisitorGraphViz class:
- <?php
- require_once 'tutorial_autoload.php';
-
- $store = new ezcTreeXmlInternalDataStore();
- $tree = new ezcTreeXml( 'files/example1.xml', $store );
-
- $visitor = new ezcTreeVisitorGraphViz;
- $tree->accept( $visitor );
- file_put_contents( 'files/graphviz.dot', (string) $visitor );
- ?>
The generated .dot file can be converted to an image by running the following command:
dot -Tpng -o img/graphviz.png files/graphviz.dot
The result of this is as follows (scaled):
Aside from console and graphical output, there is also a visualizer that
renders the tree in a YUI compatible XHTML output. This can be used to
automatically populate a YUI style menu. The code is pretty much the same,
except for the addition of the xmlId argument to the constructor of
ezcTreeVisitorYUI.
- <?php
- require_once 'tutorial_autoload.php';
-
- $store = new ezcTreeXmlInternalDataStore();
- $tree = new ezcTreeXml( 'files/example1.xml', $store );
-
- $visitor = new ezcTreeVisitorYUI( 'menu' );
- $tree->accept( $visitor );
- echo (string) $visitor;
- ?>
However, in order to actually render the menu, you need to have some specific
JavaScript in the head element of your HTML code. First of all, you need to include
the YUI code:
<script type="text/javascript" src="http://yui.yahooapis.com/2.3.1/build/yahoo-dom-event/yahoo-dom-event.js"></script>
<script type="text/javascript" src="http://yui.yahooapis.com/2.3.1/build/container/container_core-min.js"></script>
<script type="text/javascript" src="http://yui.yahooapis.com/2.3.1/build/menu/menu-min.js"></script>
Then, you need the following code to turn the generated menu into a YUI menu
(the {literal} opening and closing tag is required if you use the Template
component):
<script type="text/javascript">
{literal}
YAHOO.util.Event.onContentReady('overview', function () {
var oMenu = new YAHOO.widget.MenuBar("menu", { autosubmenudisplay: true, showdelay: 200 });
oMenu.render();
});
{/literal}
</script>
The full (but minimal) code looks then like:
- <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
- <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
- <head>
- <link rel="stylesheet" type="text/css" href="http://yui.yahooapis.com/2.3.1/build/menu/assets/skins/sam/menu.css"/>
-
- <script type="text/javascript" src="http://yui.yahooapis.com/2.3.1/build/yahoo-dom-event/yahoo-dom-event.js"></script>
- <script type="text/javascript" src="http://yui.yahooapis.com/2.3.1/build/container/container_core-min.js"></script>
- <script type="text/javascript" src="http://yui.yahooapis.com/2.3.1/build/menu/menu-min.js"></script>
- <script type="text/javascript">
- YAHOO.util.Event.onContentReady('menu', function () {
- var oMenu = new YAHOO.widget.MenuBar("menu", { autosubmenudisplay: true, showdelay: 200 });
-
- oMenu.render();
- });
- </script>
- </head>
- <body class="yui-skin-sam">
- <?php
- require_once 'tutorial_autoload.php';
-
- $store = new ezcTreeXmlInternalDataStore();
- $tree = new ezcTreeXml( 'files/example1.xml', $store );
-
- $visitor = new ezcTreeVisitorYUI( 'menu' );
- $tree->accept( $visitor );
- echo (string) $visitor;
- ?>
- </body>
- </html>
The result of this is as follows (scaled):
The ezcTreeVisitorYUI visitor allows some options that can be set through the
constructor. The options are documented with the ezcTreeVisitorYUIOptions
class.