FluentDOM
[ class tree: FluentDOM ] [ index: FluentDOM ] [ all elements ]

User Guide for FluentDOM

Bastian Feder Thomas Weinert

Table of Contents

FluentDOM

FluentDOM ist a jQuery like fluent XML interface for the DOMDocument in PHP.

The idea was born in a workshop of Tobias Schlitt, about the PHP XML extensions at the IPC Spring, in Berlin. He used this idea to show XPath samples in the session.

Many thanks to the jQuery people for their work, who did an exceptional job describing their interfaces and providing examples. This saved us a lot of work.

We implemented most of the jQuery methods into FluentDOM, but there are differences. Most important: we use XPath for expressions, not CSS selectors. Since XPath is supported by the ext/xml extension, no extra parsing need to be done. This should be faster processing the selectors and btw. it was easier for us to implement. And as a nice topping it supports namespaces, too.

We implemented several php interfaces: Countable, IteratorAggregate, SeekableIterator and RecursiveItrerator. Even ArrayAccess is supported.

Since FluentDOM works on XML documents, there is no method 'html()', but 'xml()'.

We support the string conversion using the magic __toString() method. It will output the xml or html of the associated DOMDocument.

FluentDOM needs a document. If you do not provide a valid source, an empty one will be created.

XPath do not only match element nodes (nodes with a tag name and maybe children), but text nodes, too. Which implicitly enhances FluentDOM to support them.

To be able to write phpUnit Tests and develop FluentDOM a lot of examples where written. Most of them are copied and adapted from or are deeply inspired by the jQuery documentation. They are located in the 'examples' folder and linked in the documentation. Once again many thanks to the jQuery team.

Basic Usage

This section shows some of the basic operation.

FluentDOM Function

The FluentDOM function is a little wrapper. It creates a new FluentDOM object and loads the source if it was provided. Possible sources are local XML or HTML files, XML or HTML strings, DOMDocument DOMNode objects or a FluentDOM object. The following two samples do the same.

Function Sample

  1. <?php
  2.  
  3. require('../../FluentDOM.php');
  4.  
  5. $xmlFile 'hello.xml';
  6.  
  7. // create and load
  8. echo FluentDOM($xmlFile)
  9.   // find root node
  10.   ->find('/message')
  11.   // replace text content
  12.   ->text('Hello World!');

Object Sample

  1. <?php
  2.  
  3. require('../../FluentDOM.php');
  4.  
  5. $xmlFile 'hello.xml';
  6.  
  7. // create object
  8. $fd new FluentDOM();
  9. // load file
  10. $fd->load($xmlFile);
  11.  
  12. echo $fd
  13.   ->find('/message')
  14.   ->text('Hello World!');


Loading Data

You can use different ways to load a source into a FluentDOM object. The simplest way is the FluentDOM function. But sometimes you need more. The default loaders do not support URLs for example. But here are other ways:

Prepare A DOMDocument

The first way is to create a DOMDocument with custom logic and load this into the FluentDOM object.

  1. <?php
  2.  
  3. require('../../FluentDOM.php');
  4.  
  5. $xmlFile 'hello.xml';
  6.  
  7. // prepare
  8. $dom new DOMDocument();
  9. $dom->load($xmlFile);
  10.  
  11. // load
  12. echo FluentDOM($dom)
  13.   ->find('/message')
  14.   ->text('Hello World!');

Use The "document" Attribute

The FluentDOM has an read only attribute document. You can not assign a value to this attribute directly. But you have access to all its methods and attributes. This example uses DOMDocument::load() to load the XML file.

  1. <?php
  2.  
  3. require('../../FluentDOM.php');
  4.  
  5. $xmlFile 'hello.xml';
  6.  
  7. // create object
  8. $fd new FluentDOM();
  9. // use document attribute
  10. $fd->document->load($xmlFile);
  11.  
  12. echo $fd
  13.   ->find('/message')
  14.   ->text('Hello World!');

Custom Loader

FluentDOM allows to use custom loaders. This are simple classes implementing the FluentDOMLoader interface. The interface has a single function load().

  1. <?php
  2.  
  3. require('../../FluentDOM.php');
  4.  
  5. $xmlFile 'hello.xml';
  6.  
  7. class ExampleLoader implements FluentDOMLoader {
  8.  
  9.   // this could implement checks, error handling, ...
  10.   public function load($source$type{
  11.     $dom new DOMDocument();
  12.     $dom->load($source);
  13.     return $dom;
  14.   }
  15. }
  16.  
  17. $fd new FluentDOM();
  18. // set loader(s)
  19. $fd->setLoaders(
  20.   array(
  21.     new ExampleLoader
  22.   )
  23. );
  24. // load data  using custom loader
  25. $fd->load($xmlFile);
  26.  
  27. echo $fd
  28.   ->find('/message')
  29.   ->text('Hello World!');


Find Elements

The selector language used in FluentDOM is XPath, not CSS.

The method find() is used to select some elements from the document. The selector parameter can be an XPath query or a callback function. XPath is a little different from CSS but more powerful. More important it is implemented in the PHP extension and faster any PHP based CSS selector implementation could be.

  1. <?php
  2. require('../../FluentDOM.php');
  3.  
  4. $fd FluentDOM('find.xml');
  5.  
  6. // find the document element <root>
  7. var_dump($fd->find('/root')->item(0)->nodeName);
  8.  
  9. //find the first <child> in <root>
  10. var_dump($fd->find('/root/child')->item(0)->textContent);
  11.  
  12. //find the all <child>s anywhere in the document
  13. foreach ($fd->find('//child'as $child{
  14.   var_dump($child->textContent);
  15. }
  16.  
  17. //find the <root> first then the second element in it
  18. var_dump($fd->find('/root')->find('*[2]')->item(0)->textContent);

If the FluentDOM object already contains a selection, the selector will be used with each selected element. If you this is the first action on the object, the document context is used. You can force the document context with the second parameter.


Tutorial: Create A HTML Menu

Step 1: The Root Element

After the FluentDOM class is included an instance of it is created. The default content type of a FluentDOM object is XML. For this tutorial it is changed to HTML.

  1. <?php
  2. require('../../FluentDOM.php');
  3.  
  4. // create a FluentDOM
  5. $fd new FluentDOM();
  6. // we generate html
  7. $fd->contentType 'html';
  8.  
  9. //add the base menu node
  10. $menu $fd->append('<ul/>');
  11.  
  12. // output the created document
  13. echo $fd;
  14. ?>

The method append() appends elements to the current selection and returns a FluentDOM with the appended elements. For later use this is assigned to a variable.

The example uses a string parameter to define the tag. This has to be some text or a valid xml tree with a single root node.

The parameter can be an DOMNode, too. It is up to you which way you prefer.

  1. <?php
  2. require('../../FluentDOM.php');
  3.  
  4. // create a FluentDOM
  5. $fd new FluentDOM();
  6. // we generate html
  7. $fd->contentType 'html';
  8.  
  9. //add the base menu node
  10. $menu $fd->append(
  11.   //create a dom element node
  12.   $fd->document->createElement('ul')
  13. );
  14.  
  15. // output the created document
  16. echo $fd;
  17. ?>

Step 2: Add Menu Items

A menu without items is useless. Using the chaining a listitem is appended and a hyperlink into it. The link target is set using attr() and with text() a link caption is provided. These two methods do not change the selected elements.

  1. <?php
  2. require('../../FluentDOM.php');
  3.  
  4. // create a FluentDOM
  5. $fd new FluentDOM();
  6. // we generate html
  7. $fd->contentType 'html';
  8.  
  9. //add the base menu node
  10. $menu $fd->append('<ul/>');
  11.  
  12. // add the first menu item
  13. $menu
  14.   // add the <li>
  15.   ->append('<li/>')
  16.   // add an <a> into the <li>
  17.   ->append('<a/>')
  18.   // set the href attribute of the <a>
  19.   ->attr('href''/sample.php')
  20.   // set the text content of the <a>
  21.   ->text('Sample');
  22.  
  23. // add the second menu item
  24. $menu
  25.   ->append('<li/>')
  26.   ->append('<a/>')
  27.   ->attr('href''http://fluentdom.org')
  28.   ->text('FluentDOM');
  29.  
  30. // output the created document
  31. echo $fd;
  32. ?>

Step 3: Improve Menu Items

Of course menu items can get classes. The method addClass() will add a class to all selected elements.

Javascript links do not need to have a href attribute, attr() can set other parameters like "id" or "onclick", too.

  1. <?php
  2. require('../../FluentDOM.php');
  3.  
  4. $fd new FluentDOM();
  5. $fd->contentType 'html';
  6.  
  7. $menu $fd->append('<ul/>');
  8.  
  9. // first menu item
  10. $menu
  11.   ->append('<li/>')
  12.   ->append('<a/>')
  13.   ->attr('href''/sample.php')
  14.   ->text('Sample');
  15.  
  16. // second menu item
  17. $menu
  18.   ->append('<li/>')
  19.   ->append('<a/>')
  20.   ->attr('href''http://fluentdom.org')
  21.   // add a class to the menu item <a>
  22.   ->addClass('externalLink')
  23.   ->text('FluentDOM');
  24.  
  25. // third menu item
  26. $menu
  27.   ->append('<li/>')
  28.   ->append('<a/>')
  29.   // set the id attribute
  30.   ->attr('id''alertSample')
  31.   // set the js ionclick handler
  32.   ->attr('onclick'"alert('Hi');")
  33.   ->text('Alert Sample');
  34.  
  35. echo $fd;
  36. ?>

Step 4: Mark Menu Items

Often the first and/or the last element in a list need special threatment. To add classes to them find() is used to select them and addClass() to mark them.

FluentDOM uses XPath for selectors. In XPath "//" selects elements at an level (from root) and "[1]" means that it has to be the first element in it's parent node.

  1. <?php
  2. require('../../FluentDOM.php');
  3.  
  4. $fd new FluentDOM();
  5. $fd->contentType 'html';
  6.  
  7. $menu $fd->append('<ul/>');
  8.  
  9. $menu
  10.   ->append('<li/>')
  11.   ->append('<a/>')
  12.   ->attr('href''/sample.php')
  13.   ->text('Sample');
  14.  
  15. $menu->append('<li/>')
  16.   ->append('<a/>')
  17.   ->attr('href''http://fluentdom.org')
  18.   ->addClass('externalLink')
  19.   ->text('FluentDOM');
  20.  
  21. $menu
  22.   ->append('<li/>')
  23.   ->append('<a/>')
  24.   ->attr('id''alertSample')
  25.   ->attr('onclick'"alert('Hi');")
  26.   ->text('Alert Sample');
  27.  
  28. // mark first siblings
  29. $fd
  30.   // find all first <li>
  31.   ->find('//li[1]')
  32.   // set a class
  33.   ->addClass('first');
  34.  
  35. // mark last siblings
  36. $fd
  37.   // find all last <li>
  38.   ->find('//li[position() = last()]')
  39.   // set a class
  40.   ->addClass('last');
  41.  
  42. echo $fd;
  43. ?>

Step 5: Add A Submenu

In the last step a submenu is added. The submenu is appended to the <li> tag. The method end() is used to jump to the previous selection.

  1. <?php
  2. require('../../FluentDOM.php');
  3.  
  4. $fd new FluentDOM();
  5. $fd->contentType 'html';
  6.  
  7. $menu $fd->append('<ul/>');
  8.  
  9. $menu
  10.   ->append('<li/>')
  11.   ->append('<a/>')
  12.   ->attr('href''/sample.php')
  13.   ->text('Sample');
  14.  
  15. // remember the <li> so we cann add a submenu
  16. $item $menu
  17.   ->append('<li/>')
  18.   ->append('<a/>')
  19.   ->attr('href''http://fluentdom.org')
  20.   ->addClass('externalLink')
  21.   ->text('FluentDOM')
  22.   // <a> is selected, jump to parent selection
  23.   ->end();
  24.  
  25. // add the submenu
  26. $subMenu $item->append('<ul/>');
  27.  
  28. // add the submenu item
  29. $subMenu
  30.   ->append('<li/>')
  31.   ->append('<a/>')
  32.   ->attr('href''http://nightly.fluentdom.org/documentation')
  33.   ->addClass('externalLink')
  34.   ->text('Documentation');
  35.  
  36. $menu
  37.   ->append('<li/>')
  38.   ->append('<a/>')
  39.   ->attr('id''alertSample')
  40.   ->attr('onclick'"alert('Hi');")
  41.   ->text('Alert Sample');
  42.  
  43. $fd
  44.   ->find('//li[1]')
  45.   ->addClass('first');
  46. $fd
  47.   ->find('//li[position() = last()]')
  48.   ->addClass('last');
  49.  
  50. echo $fd;
  51. ?>

XPath 101

This is a little introduction into XPath. For further information see the links at the end of this section.

Syntax elements

  • / - Level separator
  • // - Multi-level separator
  • * - Element wildcard
  • @ - Attribute prefix
  • @* - Attribute wildcard
  • [ ] - Conditions
  • . - Current element
  • .. - Parent element

Simple XPath Selector Samples

-match the document element with the name "element-name".

/element-name

Match all direct childs of the document element with the name "child".

/*/child

Match all elements with name "a" and attribute "href" anywhere in the document.

//a[@href]

Match all elements with name "strong" that are child (direct or not) of the current element.

.//strong

Match the first direct child of the current element.

*[1]

Match all elements with the name "div" in the current element with the attribute "id" set to "sampleOne".

div[@id = "sampleOne"]


Functions

  • name() - Element name
  • local-name() - Element name wihtout namespace prefix
  • position() - Position in parent element (starts with 1)
  • last() - Position of last element
  • count(...) - Element count
  • normalize-space() - Normalize withespaces
  • concat() - Concatinate strings
  • contains() - Check if a string contains anther string

This is only a selection of functions uses in the following samples. XPath knows some more.



Documentation generated on Sun, 26 Sep 2010 01:00:30 +0200 by phpDocumentor 1.4.3