Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve writer implementation #65

Merged
merged 1 commit into from
Dec 1, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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