diff --git a/documents/APIs.md b/documents/APIs.md
index 065f323..cab7e0d 100644
--- a/documents/APIs.md
+++ b/documents/APIs.md
@@ -26,33 +26,27 @@ __construct($root?, array $options?);
->query(...$xpath);
-->appendChild($child, ...$optionals);
-// alias:
->add($child, ...$optionals);
+->appendChild($child, ...$optionals);
-->prependSibling($sibling, ...$optionals);
-// aliases:
->prepend($sibling, ...$optionals);
+->prependSibling($sibling, ...$optionals);
->insertSiblingBefore($sibling, ...$optionals);
-->appendSibling($sibling, ...$optionals);
-// aliases:
->append($sibling, ...$optionals);
+->appendSibling($sibling, ...$optionals);
->insertSiblingAfter($sibling, ...$optionals);
-->setAttribute(...$arguments);
-// alias:
->attr(...$arguments);
+->setAttribute(...$arguments);
-->setText($text);
-// alias:
->text($text);
+->setText($text);
->appendText($text);
-->setCdata($text);
-// alias:
->cdata($text);
+->setCdata($text);
->appendCdata($text);
@@ -65,6 +59,8 @@ __construct($root?, array $options?);
->dom();
->xml($strip = false);
+
+->save($file, $strip = false);
```
diff --git a/documents/Changelog.txt b/documents/Changelog.txt
index 1c7dca2..817433b 100644
--- a/documents/Changelog.txt
+++ b/documents/Changelog.txt
@@ -1,20 +1,26 @@
[+]: new [~]: changed [-]: removed [#]: fixed [@]: internal
-1.12.4: (2016-01-23)
-Internal cleanup.
+1.13: (2016-01-24)
+introduces the '->save()' method.
+
+ * [+] ->save() is part of the family.
+
+
+1.12.4:
+internal cleanup.
* [@] cleanup.
1.12.3:
-Refactoring improving the code design.
+refactoring improving the code design.
* [@] refactoring.
1.12.2:
-Internal refactoring and performance regression fix.
+internal refactoring and performance regression fix.
* [@] refactoring. Performances are normal.
diff --git a/documents/Getting-Started.md b/documents/Getting-Started.md
index 8db32a9..78b9a65 100644
--- a/documents/Getting-Started.md
+++ b/documents/Getting-Started.md
@@ -608,7 +608,7 @@ The document can be exported as `DOMDocument`.
$dom = $book->dom();
```
-Or as XML string.
+Or as **XML string**.
```php
$xml = $book->xml();
@@ -645,6 +645,34 @@ $xml = $book->query('//chapter')->xml();
The Expanding Universe
```
+The document can be **saved on a file** too.
+
+```php
+$book->save('book.xml');
+```
+
+As for `->xml()`, the output document can be saved without the XML declaration
+
+```php
+$book->save('book.xml', true);
+```
+
+or only specific nodes can be saved.
+
+```php
+$book->query('//chapter')
+ ->save('book_chapters.xml');
+```
+
+Saving is fluid too.
+
+```php
+$book->save('book.xml')
+ ->save('book_tidy.xml', true)
+ ->query('//chapter')
+ ->save('book_chapters.xml');
+```
+
## Importing Existing Documents
diff --git a/source/FluidXml.php b/source/FluidXml.php
index ac52530..9520daf 100644
--- a/source/FluidXml.php
+++ b/source/FluidXml.php
@@ -46,6 +46,7 @@
use \FluidXml\Core\FluidInsertionHandler;
use \FluidXml\Core\FluidContext;
use \FluidXml\Core\NewableTrait;
+use \FluidXml\Core\SaveableTrait;
use \FluidXml\Core\ReservedCallTrait;
use \FluidXml\Core\ReservedCallStaticTrait;
@@ -137,6 +138,7 @@ function simplexml_to_string_without_headers(\SimpleXMLElement $element)
class FluidXml implements FluidInterface
{
use NewableTrait,
+ SaveableTrait,
ReservedCallTrait, // For compatibility with PHP 5.6.
ReservedCallStaticTrait; // For compatibility with PHP 5.6.
@@ -571,6 +573,7 @@ public function setCdata($text);
public function appendCdata($text);
public function remove(...$xpath);
public function xml($strip = false);
+ public function save($file, $strip = false);
// Aliases:
public function add($child, ...$optionals);
public function prepend($sibling, ...$optionals);
@@ -620,6 +623,20 @@ public static function new_(...$arguments)
}
}
+trait SaveableTrait
+{
+ public function save($file, $strip = false)
+ {
+ $status = \file_put_contents($file, $this->xml($strip));
+
+ if (! $status) {
+ throw new \Exception("The file '$file' is not writable.");
+ }
+
+ return $this;
+ }
+}
+
class FluidDocument
{
public $dom;
@@ -1058,6 +1075,7 @@ protected function insertIntegerFluidcontext($parent, $k, $v, $fn)
class FluidContext implements FluidInterface, \ArrayAccess, \Iterator
{
use NewableTrait,
+ SaveableTrait,
ReservedCallTrait, // For compatibility with PHP 5.6.
ReservedCallStaticTrait; // For compatibility with PHP 5.6.
diff --git a/specs/FluidXml.php b/specs/FluidXml.php
index c6dd594..ed7ca86 100644
--- a/specs/FluidXml.php
+++ b/specs/FluidXml.php
@@ -153,6 +153,9 @@
});
describe('FluidXml', function() {
+ $ds = \DIRECTORY_SEPARATOR;
+ $this->out_dir = __DIR__ . "{$ds}..{$ds}sandbox{$ds}";
+
it('should throw invoking not existing staic method', function() {
try {
FluidXml::lload();
@@ -188,8 +191,7 @@
});
it('should import an XML file', function() use ($doc) {
- $ds = \DIRECTORY_SEPARATOR;
- $file = __DIR__ . "{$ds}..{$ds}sandbox{$ds}.fixture.xml";
+ $file = "{$this->out_dir}.test_load.xml";
\file_put_contents($file, $doc);
$xml = FluidXml::load($file);
\unlink($file);
@@ -1685,6 +1687,63 @@ function addchild($parent, $i)
});
});
+ describe('.save', function() {
+ it('should be fluid', function() {
+ $file = "{$this->out_dir}.test_save0.xml";
+ assert_is_fluid('save', $file);
+ \unlink($file);
+ });
+
+ it('should store the entire XML document in a file', function() {
+ $xml = new FluidXml();
+ $xml->appendChild('parent', true)
+ ->appendChild('child', 'content');
+
+ $file = "{$this->out_dir}.test_save1.xml";
+ $xml->save($file);
+
+ $actual = \trim(\file_get_contents($file));
+ $expected = "\n"
+ . "\n"
+ . " \n"
+ . " content\n"
+ . " \n"
+ . "";
+
+ \unlink($file);
+
+ \assert($actual === $expected, __($actual, $expected));
+ });
+
+ it('should store a fragment of the XML document in a file', function() {
+ $xml = new FluidXml();
+ $xml->appendChild('parent', true)
+ ->appendChild('child', 'content');
+
+ $file = "{$this->out_dir}.test_save2.xml";
+ $xml->query('//child')->save($file);
+
+ $actual = \trim(\file_get_contents($file));
+ $expected = "content";
+
+ \unlink($file);
+
+ \assert($actual === $expected, __($actual, $expected));
+ });
+
+ it('should throw for not writable file', function() {
+ $xml = new FluidXml();
+
+ try {
+ $xml->save('/.impossible/tmp/out.xml');
+ } catch (\Exception $e) {
+ $actual = $e;
+ }
+
+ assert_is_a($actual, \Exception::class);
+ });
+ });
+
describe('.add', function() {
it('should be fluid', function() {
assert_is_fluid('add', 'a');