Skip to content

SimpleXML Migration

Thomas Weinert edited this page Jul 12, 2018 · 8 revisions

SimpleXML Migration

If you worked with SimpleXML before the following examples should help you to understand FluentDOM. Like SimpleXML, FluentDOM uses PHP language features and interfaces to provide an easier and more compact syntax. Unlike SimpleXML, FluentDOM tries not to hide DOM, but to extend it. PHP itself implements DOM Level 2, FluentDOM adds DOM Level 3 methods.

The complete source of the following examples can be found in the repository: /examples/SimpleXML Migration.

Load

FluentDOM::load() returns an extended DOM document.

SimpleXML load xml from string

$element = simplexml_load_string($string);
echo $element->saveXML();

SimpleXML load xml from file

$element = simplexml_load_file($file);
echo $element->saveXML();

FluentDOM load xml from string

$document = FluentDOM::load($string);
echo $document->saveXML();

FluentDOM load xml from file

$document = FluentDOM::load($file, 'xml', [FluentDOM\Loader\Options::IS_FILE => TRUE]);
echo $document->saveXML();

FluentDOM load html from string

$document = FluentDOM::load('<div/>', 'html');
echo $document->saveHTML();

FluentDOM load json from string

$document = FluentDOM::load('{"foo": "bar"}', 'json');
echo $document->saveXML();

Elements

In SimpleXML you can use object property syntax to access the tag structure. The property can be cast to string to fetch the direct text children content.

$element = simplexml_load_string($xml);
echo $element->channel->title, "\n";

FluentDOM uses Xpath to accomplish that. Nodes can be used like functions to execute an Xpath expression in the context of the node. Xpath has a string cast built in.

$document = FluentDOM::load($xml);
echo $document('string(/rss/channel/title)'), "\n";

Property of a non-object

A problem with the object syntax is that it can result in error messages if an expected node structure does not exists.

$element = simplexml_load_string('<foo/>');
var_dump($element->some->other->element);
// PHP Notice:  Trying to get property of non-object in

Using Xpath avoids the problem. If the location path returns and empty list, the result of the string cast will be an empty string.

$document = FluentDOM::load('<foo/>');
var_dump($document('string(/root/some/other/element)'));
// string(0) ""

You can use Xpath to validate if a node exists of course.

$document = FluentDOM::load('<foo/>');
var_dump($document('count(/root/some/other/element) > 0'));
// bool(false)

Traversing

SimpleXML implements Traversable and __toString(). This allows to iterate nodes with foreach() and allow them to be cast into strings.

$element = simplexml_load_string($xml);
foreach ($element->channel->item as $item) {
  echo $item->title, "\n";
}

FluentDOM depends heavily on XPath. If your Xpath expression is a location path it will return a node list, but using xpath functions, you can return strings, number or booleans.

$document = FluentDOM::load($xml);
foreach ($document('/rss/channel/item') as $item) {
  echo $item('string(title)'), "\n";
}

The nodes it self implement __toString(), so they can be cast into a string.

$document = FluentDOM::load($xml);
foreach ($document('/rss/channel/item/title') as $title) {
  echo $title, "\n";
}

Attributes

SimpleXML allows to use Array Syntax to access the attribute of an element node.

$element = simplexml_load_string($xml);
echo $element['attribute'], "\n";

If you use a qualified name FluentDOM does also, ...

$element = FluentDOM::load($xml)->documentElement;
echo $element['attribute'], "\n";

... but if it is an integer it will access the child nodes.

$element = FluentDOM::load($xml)->documentElement[1];
echo $element->localName, "\n";

Children

In SimpleXML the ->children() method allows access to an array containing the child elements

$element = simplexml_load_string($xml);
var_dump((string)$element->channel->children()[1]->title);

FluentDOM again uses Xpath. The expression results in a DOMNodelist object. It has methods to access its items and you can use iterator_to_array() to convert it into an array.

$document = FluentDOM::load($xml);
var_dump((string)$document('/rss/channel/item/title')->item(0));

Since PHP 5.6.3, DOMNodelist allows to use array syntax.

$document = FluentDOM::load($xml);
var_dump((string)$document('/rss/channel/item/title')[0]);

Namespaces

SimpleXMLs children() method is namespace aware. The first argument can a namespace uri or prefix (I suggest you always provide the namespace uri).

$element = simplexml_load_string($xml);
foreach ($element->children('http://www.w3.org/2005/Atom')->entry as $entry) {
  echo $entry->children('http://www.w3.org/2005/Atom')->title, "\n";
}

Or use SimpleXML to fetch the nodes, the problem here is that you will have to register them again and again on each node.

$element = simplexml_load_string($xml);
$element->registerXPathNamespace('a', 'http://www.w3.org/2005/Atom');
foreach ($element->xpath('a:entry') as $entry) {
  $entry->registerXPathNamespace('a', 'http://www.w3.org/2005/Atom');
  echo $entry->xpath('a:title')[0], "\n";
}

In FluentDOM the namespaces can be registered on the document object. All node objects will have access to the registered namespaces.

$document = FluentDOM::load($xml);
$document->registerNamespace('a', 'http://www.w3.org/2005/Atom');
foreach ($document('/a:feed/a:entry') as $entry) {
  echo $entry('string(a:title)'), "\n";
}

Create

SimpleXML has some limited functionality for this, basically you can add child elements.

$element = simplexml_load_string('<ul/>');
$li = $element->addChild('li', 'FluentDOM');
$li['href'] = 'http://fluentdom.org';
echo $element->saveXml();

FluentDOM extends DOM for that, so you still can use all the DOM methods to create, insert and replace nodes. DOMDocument::createElement() is extended. It can resolve namespace prefixes and add attributes.

$document = new FluentDOM\DOM\Document();
$ul = $document->appendChild($document->createElement('ul'));
$li = $ul->appendChild(
  $document->createElement('li', 'FluentDOM', ['href' => 'http://fluentdom.org'])
);
echo $document->saveHtml();

But here is a shortcut to add an element child.

$document = new FluentDOM\DOM\Document();
$ul = $document->appendElement('ul');
$li = $ul->appendElement('li', 'FluentDOM', ['href' => 'http://fluentdom.org']);
echo $document->saveHtml();

Additionally it has a dedicated API to create documents. The Creator is a function object. The first argument is the element name, the following arguments are attributes (array) or child nodes (scalars, nodes, ...). The calls can be nested, resulting in a really compact syntax.

Methods of the Creator allow to add special nodes like comments.

$_ = FluentDOM::create();
$document = $_(
  'ul',
  $_('li', ['href' => 'http://fluentdom.org'], 'FluentDOM')
)->document;
echo $document->saveHtml();
Clone this wiki locally