Skip to content

Commit

Permalink
Improve writer implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
veewee committed Dec 1, 2023
1 parent 78a4ba4 commit e85cb58
Show file tree
Hide file tree
Showing 21 changed files with 868 additions and 16 deletions.
140 changes: 140 additions & 0 deletions docs/writer.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ The Writer consists out of following composable blocks:

- [Builders](#builders): Lets you build XML by using a declarative API.
- [Configurators](#configurators): Configure how the Writer behaves.
- [Mappers](#mappers): Map the XMLWriter to something else.
- [Openers](#openers): Specify where you want to write to.

## Builders
Expand Down Expand Up @@ -123,6 +124,24 @@ element('foo',
<foo hello="world" bar="baz" />
```

#### cdata

Writes a CDATA section:

```php
use function VeeWee\Xml\Dom\Builder\value;
use function VeeWee\Xml\Writer\Builder\cdata;
use function VeeWee\Xml\Writer\Builder\element;

element('foo',
cdata(value('some cdata'))
);
```

```xml
<foo><![CDATA[some cdata]]></foo>
```

#### children

Inserts multiple nodes at current position in the writer.
Expand Down Expand Up @@ -164,6 +183,24 @@ function myOwnDataBuilder(): Generator
children(myOwnDataBuilder());
```

#### comment

Writes a comment section:

```php
use function VeeWee\Xml\Dom\Builder\value;
use function VeeWee\Xml\Writer\Builder\comment;
use function VeeWee\Xml\Writer\Builder\element;

element('foo',
comment(value('some comment'))
);
```

```xml
<foo><!--some comment--></foo>
```

#### document

This builder can be used to specify an XML version and charset.
Expand Down Expand Up @@ -218,6 +255,65 @@ element('foo',
<foo xmlns="https://acme.com" xmlns:hello="https://helloworld.com" />
```


#### namespaced_attribute

Can be used to add a namespaced attribute with or without prefix.
This function will also add the xmlns attribute.

```php
use function VeeWee\Xml\Writer\Builder\element;
use function VeeWee\Xml\Writer\Builder\namespaced_attribute;

element('foo',
namespaced_attribute('https://acme.com', 'acme', 'hello', world)
);
```

```xml
<foo xmlns:acme="https://acme.com" acme:hello="world" />
```

#### namespaced_attributes

Can be used to add multiple namespaced attributes with or without prefix at once.
This function will add the xmlns attribute.

```php
use function VeeWee\Xml\Writer\Builder\element;
use function VeeWee\Xml\Writer\Builder\namespaced_attributes;

element('foo',
namespaced_attributes('https://acme.com', [
'acme:hello' => 'world',
'acme:foo' => 'bar',
])
);
```

```xml
<foo xmlns:acme="https://acme.com" acme:hello="world" acme:foo="bar" />
```

#### namespaced_element

Build a namespaced element.
It can contain a set of configurators that can be used to specify the attributes, children, value, ... of the element with or without prefix.
This function will add the xmlns attribute.

```php
use function VeeWee\Xml\Writer\Builder\namespace_attribute;
use function VeeWee\Xml\Writer\Builder\prefixed_element;

namespaced_element('http://acme.com', 'acme', 'hello',
...$configurators
);
```

```xml
<acme:hello xmlns:acme="http://acme.com" />
```

#### prefixed_attribute

Can be used to add a namespaced prefixed attribute.
Expand Down Expand Up @@ -281,6 +377,21 @@ prefixed_element('acme', 'hello',
<acme:hello xmlns:acme="http://acme.com" />
```

#### raw

Can be used to insert raw strings into the XML.
Be careful: these strings won't be validated or escaped and are just appended to the XML without any sort of validation.

```php
use function VeeWee\Xml\Writer\Builder\raw;

raw('<hello>world</hello>');
```

```xml
<hello>world</hello>
```

#### value

Can set a value to any XML element.
Expand Down Expand Up @@ -389,8 +500,37 @@ use VeeWee\Xml\Writer\Writer;
$document = Writer::configure(...$configurators);
```

## Mapper

#### memory_output

If you are using an in-memory writer, you can use the `memory_output()` mapper to get the written content as a string.

```php
use VeeWee\Xml\Writer\Writer;
use function VeeWee\Xml\Writer\Mapper\memory_output;

$doc = Writer::inMemory()
->write($yourXml)
->map(memory_output());
```

## Openers

#### memory_opener

Starts a writer that stores the written XML in-memory.
You can use the [memory_output](#memoryoutput) mapper to retrieve the written XML.

```php
use VeeWee\Xml\Writer\Writer;
use function VeeWee\Xml\Writer\Mapper\memory_output;

$doc = Writer::inMemory(...$configurators)
->write($yourXml)
->map(memory_output());
```

#### xml_file_opener

Loads an XML document from a file.
Expand Down
30 changes: 30 additions & 0 deletions src/Xml/Writer/Builder/cdata.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?php

declare(strict_types=1);

namespace VeeWee\Xml\Writer\Builder;

use Closure;
use Generator;
use XMLWriter;

/**
* @param list<(callable(XMLWriter): Generator<bool>)> $configurators
*
* @return Closure(XMLWriter): Generator<bool>
*/
function cdata(callable ...$configurators): Closure
{
return
/**
* @return Generator<bool>
*/
static function (XMLWriter $writer) use ($configurators): Generator {
yield $writer->startCdata();
foreach ($configurators as $configurator) {
yield from $configurator($writer);
}

yield $writer->endCdata();
};
}
30 changes: 30 additions & 0 deletions src/Xml/Writer/Builder/comment.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?php

declare(strict_types=1);

namespace VeeWee\Xml\Writer\Builder;

use Closure;
use Generator;
use XMLWriter;

/**
* @param list<(callable(XMLWriter): Generator<bool>)> $configurators
*
* @return Closure(XMLWriter): Generator<bool>
*/
function comment(callable ...$configurators): Closure
{
return
/**
* @return Generator<bool>
*/
static function (XMLWriter $writer) use ($configurators): Generator {
yield $writer->startComment();
foreach ($configurators as $configurator) {
yield from $configurator($writer);
}

yield $writer->endComment();
};
}
25 changes: 25 additions & 0 deletions src/Xml/Writer/Builder/namespaced_attribute.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?php

declare(strict_types=1);

namespace VeeWee\Xml\Writer\Builder;

use Closure;
use Generator;
use XMLWriter;

/**
* @return Closure(XMLWriter): Generator<bool>
*/
function namespaced_attribute(string $namespace, ?string $prefix, string $name, string $value): Closure
{
return
/**
* @return Generator<bool>
*/
static function (XMLWriter $writer) use ($namespace, $prefix, $name, $value): Generator {
yield $writer->startAttributeNs($prefix, $name, $namespace);
yield $writer->text($value);
yield $writer->endAttribute();
};
}
30 changes: 30 additions & 0 deletions src/Xml/Writer/Builder/namespaced_attributes.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?php

declare(strict_types=1);

namespace VeeWee\Xml\Writer\Builder;

use Closure;
use Generator;
use XMLWriter;

/**
* @param array<string, string> $attributes
* @return Closure(XMLWriter): Generator<bool>
*/
function namespaced_attributes(string $namespace, array $attributes): Closure
{
return
/**
* @return Generator<bool>
*/
static function (XMLWriter $writer) use ($namespace, $attributes): Generator {
foreach ($attributes as $key => $value) {
$parts = explode(':', $key, 2);
$name = array_pop($parts);
$prefix = $parts ? $parts[0] : null;

yield from namespaced_attribute($namespace, $prefix, $name, $value)($writer);
}
};
}
30 changes: 30 additions & 0 deletions src/Xml/Writer/Builder/namespaced_element.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?php

declare(strict_types=1);

namespace VeeWee\Xml\Writer\Builder;

use Closure;
use Generator;
use XMLWriter;

/**
* @param list<(callable(XMLWriter): Generator<bool>)> $configurators
*
* @return Closure(XMLWriter): Generator<bool>
*/
function namespaced_element(string $namespace, ?string $prefix, string $name, callable ...$configurators): Closure
{
return
/**
* @return Generator<bool>
*/
static function (XMLWriter $writer) use ($namespace, $prefix, $name, $configurators): Generator {
yield $writer->startElementNs($prefix, $name, $namespace);
foreach ($configurators as $configurator) {
yield from $configurator($writer);
}

yield $writer->endElement();
};
}
23 changes: 23 additions & 0 deletions src/Xml/Writer/Builder/raw.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?php

declare(strict_types=1);

namespace VeeWee\Xml\Writer\Builder;

use Closure;
use Generator;
use XMLWriter;

/**
* @return Closure(XMLWriter): Generator<bool>
*/
function raw(string $value): Closure
{
return
/**
* @return Generator<bool>
*/
static function (XMLWriter $writer) use ($value): Generator {
yield $writer->writeRaw($value);
};
}
18 changes: 18 additions & 0 deletions src/Xml/Writer/Mapper/memory_output.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?php

declare(strict_types=1);

namespace VeeWee\Xml\Writer\Mapper;

use Closure;
use XMLWriter;

/**
* @return Closure(XMLWriter): string XMLWriter
*/
function memory_output(): Closure
{
return static function (XMLWriter $writer): string {
return $writer->outputMemory();
};
}
18 changes: 18 additions & 0 deletions src/Xml/Writer/Opener/memory_opener.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?php

declare(strict_types=1);

namespace VeeWee\Xml\Writer\Opener;

use Closure;
use XMLWriter;

/**
* @return Closure(XMLWriter): bool XMLWriter
*/
function memory_opener(): Closure
{
return static function (XMLWriter $writer): bool {
return $writer->openMemory();
};
}
Loading

0 comments on commit e85cb58

Please sign in to comment.