Skip to content

Commit

Permalink
Source, Specs and Getting Started improvements.
Browse files Browse the repository at this point in the history
* query() supports a variable number of XPaths
* namespace() supports a variable number of FluidNamespace instances
* namespace() supports a namespace id, uri and mode as arguments
* namespaces() returns all registered namespaces
* FluidNamespace instances are read-only
* FluidNamespace::id/uri/mode() can't mutate the instance
  • Loading branch information
daniele-orlando committed Nov 27, 2015
1 parent 161956a commit 9800b2e
Show file tree
Hide file tree
Showing 6 changed files with 306 additions and 108 deletions.
14 changes: 11 additions & 3 deletions documents/Changelog.txt
Original file line number Diff line number Diff line change
@@ -1,8 +1,16 @@
1.2:
* query() supports a variable number of XPaths
* namespace() supports a variable number of FluidNamespace instances
* namespace() supports a namespace id, uri and mode as arguments
* namespaces() returns all registered namespaces
* FluidNamespace instances are read-only
* FluidNamespace::id/uri/mode() can't mutate the instance

1.1.1:
* Fixes a NOTICE error.
* Fixes a NOTICE error

1.1:
* XML namespaces support added
* XML namespaces support added

1.0:
* Initial release.
* Initial release
32 changes: 20 additions & 12 deletions documents/Examples.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,6 @@
'encoding' => 'UTF-8', // The encoding for the XML header.
'stylesheet' => null ]; // An url pointing to an XSL file.



/************************************************************************
* Customizing the root node with an attribute and some children nodes. *
*************************************************************************/

$book->setAttribute('type', 'science') // It sets an attribute of the root node ('book').
->appendChild([ 'title' => 'The Theory Of Everything',
'author' => 'S. Hawking' ]); // It creates two nodes, each one with some text inside.
Expand Down Expand Up @@ -104,20 +98,34 @@



/*********************
* Chaining queries. *
**********************/
/******************
* XPath queries. *
*******************/

/*
* Chaining queries gives you great flexibility to traverse the document
* without loosing the manipulation flow.
* 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')
->setAttribute('lang', 'en')
->query('..')
->setAttribute('lang', 'en')
->query('/book/title')
->query('../title')
->setAttribute('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')
->setAttribute('lang', 'en');


Expand Down
81 changes: 79 additions & 2 deletions documents/Getting-Started.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ In every described situation FluidXML performs better in every way.

## Creating your first XML document

First of all, depending the way you have chosen to install FluidXML, you have two<br/>
First of all, depending the method you have chosen to install FluidXML, you have two<br/>
options to include the library.
* If you have cloned the repository, copy the `source/FluidXml.php` in your PHP<br/>
project and include it:
Expand All @@ -32,7 +32,7 @@ We can proceed to create our first XML document in the simplest way.
> $book = fluidxml();
> ```
It creates a new XML document with one root node that by default is called `<doc/>`.
It creates a new XML document with one root node by default called `<doc/>`.
```php
echo $book->xml();
Expand Down Expand Up @@ -114,13 +114,15 @@ boolean value returns the new node instead of the current one.
> Extended syntax
> ```php
> // true asks to return the 'chapters' node instead of the 'book' node.
>
> $book->appendChild('chapters', true)
> ->appendChild('chapter', 'Ideas About The Universe')
> ->appendChild('chapter', 'The Expanding Universe');
> ```
> Concise syntax
> ```php
> // true asks to return the 'chapters' node instead of the 'book' node.
>
> $book->add('chapters', true)
> ->add('chapter', 'Ideas About The Universe')
> ->add('chapter', 'The Expanding Universe');
Expand Down Expand Up @@ -200,6 +202,81 @@ To demonstrate this concept, we create a new document that will be filled with f
</food>
```
Another important argument is `$attributes`, which allows to set the attributes<br/>
of a node contextually to its creation.

> Extended syntax
> ```php
> $food->appendChild('fruit', 'apple', [ 'price' => 'expensive',
> 'color' => 'red' ]);
>
> // which is identical to
>
> $food->appendChild('fruit', 'apple', true) // Remember, passing 'true' returns the created node.
> ->setAttribute([ 'price' => 'expensive',
> 'color' => 'red' ]);
>
> // The advantage comes when multiple nodes have the same attributes.
>
> // A bunch of egg's all with the same price.
> $food->appendChild([ ['egg'],
> ['egg'],
> ['egg'] ], ['price' => '0.25']);
> ```
> Concise syntax
> ```php
> $food->add('fruit', 'apple', [ 'price' => 'expensive',
> 'color' => 'red' ]);
>
> // which is identical to
>
> $food->add('fruit', 'apple', true) // Remember, passing 'true' returns the created node.
> ->attr([ 'price' => 'expensive',
> 'color' => 'red' ]);
>
> // The advantage comes when multiple nodes have the same attributes.
>
> // A bunch of egg's all with the same price.
> $food->add([ ['egg'],
> ['egg'],
> ['egg'] ], ['price' => '0.25']);
> ```
## Executing XPath queries
The possibilty to execute XPath queries very easily is another feature of FluidXML.
```php
$eggs = $food->query('//egg');
$fruits = $food->query('//fruit[@price="expensive"]');
echo "We have {$eggs->length()} eggs and {$fruits->length()} expensive fruit.\n";
```
Chaining queries together with the usage of XPath relative queries gives an immense<br/>
flexibility.

```php
$book->query('//chapter')
->setAttribute('lang', 'en')
->query('..')
->setAttribute('lang', 'en')
->query('../title')
->setAttribute('lang', 'en');
```

> **Pro Tip**:
> `query()` supports quering multiple XPath queries.<br/>
> The previous example can be refactored using this advanced feature.
> ```php
> $book->query('//chapter',
> '//chapters',
> '/book/title')
> ->setAttribute('lang', 'en');
> ```
* * *
#### This document is a draft. It will be continued.
* * *
Expand Down
2 changes: 1 addition & 1 deletion documents/ReadMe.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,8 @@ $book->setAttribute('type', 'book')
Or, if you prefer, there is a **concise syntax**.

```php

$book = fluidxml();

$book->attr('type', 'book')
->add('title', 'The Theory Of Everything')
->add('author', 'S. Hawking')
Expand Down
85 changes: 45 additions & 40 deletions source/FluidXml.php
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ interface FluidInterface
*
* @return FluidContext The context associated to the DOMNodeList.
*/
public function query($xpath);
public function query(...$xpath);

/**
* Append a new node as child of the current context.
Expand Down Expand Up @@ -179,9 +179,9 @@ public function dom()
return $this->dom;
}

public function query($xpath)
public function query(...$xpath)
{
return $this->newContext($this->dom)->query($xpath);
return $this->newContext($this->dom)->query(...$xpath);
}

public function appendChild($child, ...$optionals)
Expand Down Expand Up @@ -343,7 +343,7 @@ class FluidContext implements FluidInterface, \ArrayAccess, \Iterator
private $nodes = [];
private $seek = 0;

public function __construct(\DOMDocument $dom, $context, array $namespaces = null)
public function __construct(\DOMDocument $dom, $context, array $namespaces = [])
{
$this->dom = $dom;

Expand All @@ -353,8 +353,8 @@ public function __construct(\DOMDocument $dom, $context, array $namespaces = nul

foreach ($context as $n) {
if ($n instanceof \DOMNodeList) {
for ($i = 0, $l = $n->length; $i < $l; ++$i) {
$this->nodes[] = $n->item($i);
foreach ($n as $i) {
$this->nodes[] = $i;
}
} else if ($n instanceof \DOMNode) {
$this->nodes[] = $n;
Expand All @@ -365,8 +365,8 @@ public function __construct(\DOMDocument $dom, $context, array $namespaces = nul
}
}

foreach ($namespaces as $n) {
$this->namespace($n);
if (! empty($namespaces)) {
$this->namespace(...\array_values($namespaces));
}
}

Expand Down Expand Up @@ -444,10 +444,12 @@ public function length()
return \count($this->nodes);
}

public function query($xpath)
public function query(...$xpath)
{
if (! \is_array($xpath)) {
$xpath = [ $xpath ];
$xpaths = $xpath;

if (\is_array($xpath[0])) {
$xpaths = $xpath[0];
}

$domxp = new \DOMXPath($this->dom);
Expand All @@ -459,7 +461,7 @@ public function query($xpath)
$results = [];

foreach ($this->nodes as $n) {
foreach ($xpath as $x) {
foreach ($xpaths as $x) {
// Returns a DOMNodeList.
$res = $domxp->query($x, $n);

Expand Down Expand Up @@ -805,8 +807,29 @@ trait FluidNamespaceTrait
{
private $namespaces = [];

public function namespace(FluidNamespace ...$namespaces)
public function namespaces()
{
return $this->namespaces;
}

public function namespace(...$arguments)
{
$namespaces = [];

if (\is_string($arguments[0])) {
$args = [ $arguments[0], $arguments[1] ];

if (isset($arguments[2])) {
$args[] = $arguments[2];
}

$namespaces[] = new FluidNamespace(...$args);
} else if (\is_array($arguments[0])) {
$namespaces = $arguments[0];
} else {
$namespaces = $arguments;
}

foreach ($namespaces as $n) {
$this->namespaces[$n->id()] = $n;
}
Expand Down Expand Up @@ -840,42 +863,24 @@ public function __construct($id, $uri, $mode = 1)
}
}

$this->id($id);
$this->uri($uri);
$this->mode($mode);
$this->config[self::ID] = $id;
$this->config[self::URI] = $uri;
$this->config[self::MODE] = $mode;
}

public function id($value = null)
public function id()
{
if ($value === null) {
return $this->config[self::ID];
}

$this->config[self::ID] = $value;

return $this;
return $this->config[self::ID];
}

public function uri($value = null)
public function uri()
{
if ($value === null) {
return $this->config[self::URI];
}

$this->config[self::URI] = $value;

return $this;
return $this->config[self::URI];
}

public function mode($value = null)
public function mode()
{
if ($value === null) {
return $this->config[self::MODE];
}

$this->config[self::MODE] = $value;

return $this;
return $this->config[self::MODE];
}

public function querify($xpath)
Expand Down
Loading

0 comments on commit 9800b2e

Please sign in to comment.