<?php
$DS = DIRECTORY_SEPARATOR;
$back = '..' . $DS;
$source = __DIR__ . $DS . $back . $back . 'source';
\set_include_path($source . PATH_SEPARATOR . \get_include_path());
////////////////////////////////////////////////////////////////////////////////
require_once 'FluidXml.php';
use \FluidXml\FluidXml;
use \FluidXml\FluidNamespace;
use function \FluidXml\fluidxml;
use function \FluidXml\fluidns;
use function \FluidXml\fluidify;
/*****************************
* Creating An XML Document. *
******************************/
$book = new FluidXml('book');
// or
$book = new FluidXml(null, ['root' => 'book']);
// $book is an XML document with 'book' as root node.
// The default options are:
// [ 'root' => 'doc', // The root node of the document.
// 'version' => '1.0', // The version for the XML header.
// 'encoding' => 'UTF-8', // The encoding for the XML header.
// 'stylesheet' => null ]; // An url pointing to an XSL file.
$booksheet = new FluidXml('book', ['stylesheet' => 'http://domain.com/style.xsl']);
// With PHP 7 this is valid too:
// $booksheet = FluidXml::new('book', ['stylesheet' => 'http://domain.com/style.xsl']);
$book->setAttribute('type', 'science') // It sets an attribute of the root node ('book').
->addChild([ 'title' => 'The Theory Of Everything',
'author' => 'S. Hawking' ]); // It creates two nodes, each one with some text inside.
echo $book->xml(); // Exports the xml document as a string.
echo "????????????????????????????????????????????????????????????????????????????????\n";
/**********************
* Context Switching. *
***********************/
/*
* Passing a 'true' boolean value to any method that performs an insertion of a node,
* returns the newly created node instead of the parent.
* This operation is called Context Switch.
* Methods that support this context switch are:
* - addChild($child, ...$optionals);
* - prependSibling($sibling, ...$optionals);
* - appendSibling($sibling, ...$optionals);
* and their alias methods (of course).
*/
$book->addChild('chapters', true) // true forces the return of the 'chapters' node.
->addChild('chapter', 'Ideas About The Universe', ['id' => 123, 'first' => ''])
->addChild('chapter', 'The Expanding Universe', ['id' => 321])
->addChild('chapter', 'Black Holes', ['id' => 432])
->addChild('chapter', 'Black Holes Ain\'t So Black', ['id' =>234]);
/********************
* Appending Nodes. *
*********************/
/*
* Inserting a node can be performed in different ways,
* each one with its pros and cons.
*/
/*
* In this examples, it is used the concise syntax, but the same concepts
* are applicable to the standard syntax.
*/
$food = fluidxml('food');
$food->add('fruit') // A 'fruit' node with an empty content.
->add('fruit', 'orange'); // A 'fruit' node with 'orange' as content.
// A node can have even a bunch of attributes.
$food->add('fruit', 'apple', [ 'price' => 'expensive',
'color' => 'red' ]);
// Batch insertion of nodes.
$food->add([ 'cake' => 'Tiramisu',
'pizza' => 'Margherita' ]);
// PHP arrays can't contain identical keys.
// But it's still possible to create, in a batch operation, nodes with the same tag.
$food->add([ [ 'pasta' => 'Carbonara' ],
[ 'pasta' => 'Matriciana' ] ]);
// A bunch of egg's all with the same price.
$food->add([ ['egg'], ['egg'], ['egg'] ], ['price' => '0.25']);
// Complex array structures are supported too.
$food->add([ 'menu' => [
'pasta' => [
'spaghetti' => [
'@id' => '123',
'@country' => 'Italy',
'@' => 'Spaghetti are an Italian dish...',
'variants' => [
'tomato' => [ '@type' => 'vegan' ],
'egg' => [ '@type' => 'vegetarian' ] ]]]]]);
echo $food->xml();
echo "????????????????????????????????????????????????????????????????????????????????\n";
/*************************
* Importing XML strings.*
**************************/
/*
* Raw XML/XHTML strings che be injected at any point of the document too.
*/
$book->add('cover', true)
->add(<<<XML
<h1>The Theory Of Everything</h1>
<img src="http://goo.gl/kO3Iov"/>
XML
);
/*
* The document can be filled with a raw XML string.
*/
$html = fluidxml(null);
$html->add(<<<XML
<html>
<head>
<meta/>
</head>
<body>
<p/>
</body>
</html>
XML
);
/*
* Sometimes XML/XHTML comes from legacy templating systems or external sources.
*/
$string = $html->xml();
// XML string import.
$fluid = fluidxml($string);
echo $fluid->xml();
echo "????????????????????????????????????????????????????????????????????????????????\n";
$dom = new DOMDocument();
$dom->loadXML($fluid->xml());
$dom->formatOutput = true;
$dom->preserveWhiteSpace = false;
// DOMDocument import.
$fluid = fluidxml($dom);
echo $fluid->xml();
echo "????????????????????????????????????????????????????????????????????????????????\n";
$simplexml = new SimpleXMLElement($fluid->xml());
// SimpleXMLElement import.
$fluid = fluidxml($simplexml);
echo $fluid->xml();
echo "????????????????????????????????????????????????????????????????????????????????\n";
// XML file import.
// $fluid = fluidify('path/to/file.xml');
$other = fluidxml($fluid->xml());
$fluid = fluidxml();
$fluid->add($other) // Imports a FluidXml instance.
->add([ 'query' => $fluid->query('//meta'), // Imports a FluidXml query.
'dom' => $dom, // Imports a DOMDocument.
'domnodes' => $dom->childNodes, // Imports a DOMNodeList.
'simplexml' => $simplexml ]); // Imports a SimpleXMLElement.
/******************
* XPath Queries. *
*******************/
/*
* XPath queries can be absolute or relative to the context over they are executed.
*/
$eggs = $food->query('//egg');
$fruits = $food->query('//fruit[@price="expensive"]');
echo "We have {$eggs->length()} eggs and {$fruits->length()} expensive fruit.\n";
echo "????????????????????????????????????????????????????????????????????????????????\n";
$book->query('//chapter')
->attr('lang', 'en')
->query('..')
->attr('lang', 'en')
->query('../title')
->attr('lang', 'en');
/*
* The previous code presents a repetition: all 'setAttribute' calls are identical.
* It can be refactored taking advantage of an advanced feature of 'query'.
*/
$book->query('//chapter', '//chapters', '/book/title')
->attr('lang', 'en');
/*******************************
* Accessing The Node Content. *
********************************/
/*
* The result of a query can be accessed even as array.
* Accessing the result of a query as array performs the unwrapping of the node
* and returns a raw instance of DOMNode.
* You loose the FluidXML interface but gain direct access to the DOMNode apis.
*/
$chapters = $book->query('//chapter');
$l = $chapters->length();
// DOMNode access.
$chapters[0]->setAttribute('first', '');
$chapters[$l - 1]->setAttribute('last', '');
/*
* The previous ->setAttribute is the DOMNode::setAttribute.
* not the FluidXml::setAttribute().
* Many other methods/properties are available like:
* - hasAttribute()
* - getAttribute()
* - nodeValue
* See http://php.net/manual/en/class.domnode.php for the reference documentation.
*/
echo $book->xml();
echo "????????????????????????????????????????????????????????????????????????????????\n";
/*
* Because the result of a query behaves like an array, it can be iterated too.
*/
foreach ($chapters as $i => $chapter) {
// $chapter is an instance of DOMNode.
$title = $chapter->nodeValue;
$id = $chapter->getAttribute('id');
$has_first_attr = $chapter->hasAttribute('first');
if ($has_first_attr) {
echo "The first chapter has title '{$title}' with id '{$id}'.\n";
} else {
$ii = $i + 1;
echo "Chapter {$ii} has title '{$title}' with id '{$id}'.\n";
}
}
/*
* To retrieve all DOMNode in one operation there is the ->asArray() method.
*/
$chapters_nodes = $chapters->array(); // Returns an array of DOMNode.
echo "????????????????????????????????????????????????????????????????????????????????\n";
/***************
* Namespaces. *
***************/
/*
* To use a namespace you have to register its identifier together with its uri.
*/
$xhtml = fluidns('xhtml', 'http://www.w3.org/1999/xhtml');
$book->namespace($xhtml)
->namespace('svg', 'http://www.w3.org/2000/svg')
->namespace('xsl', 'http://www.w3.org/TR/xsl', FluidNamespace::MODE_IMPLICIT)
->add('xhtml:h1')
->add([ 'xsl:template' => [ 'xsl:variable' ] ])
->query('//xhtml:h1')
->add('svg:shape');
echo $book->xml();
echo "????????????????????????????????????????????????????????????????????????????????\n";
/*******************
* Removing Nodes. *
*******************/
$food->remove('//egg'); // Removes all the eggs.
// Which is the same of
// $food->query('//egg')->remove(); // Removes all the eggs using a query.
// $food->query('/doc')->remove('egg'); // Removes all the eggs using a relative XPath.
/* ->remove(...$xpath)
* accepts the same arguments of
* ->query(...$xpath)
* Remember that, like `->query()`, even `->remove()` accepts multiple XPath strings.
*/
$food->remove('//fruit', '//cake', '//pasta', '//pizza');
echo $food->xml();
echo "????????????????????????????????????????????????????????????????????????????????\n";
|