Skip to content

Commit 3172e96

Browse files
authored
Merge pull request #65 from veewee/writer-improvements
Improve writer implementation
2 parents 78a4ba4 + e85cb58 commit 3172e96

21 files changed

+868
-16
lines changed

docs/writer.md

Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ The Writer consists out of following composable blocks:
4242

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

4748
## Builders
@@ -123,6 +124,24 @@ element('foo',
123124
<foo hello="world" bar="baz" />
124125
```
125126

127+
#### cdata
128+
129+
Writes a CDATA section:
130+
131+
```php
132+
use function VeeWee\Xml\Dom\Builder\value;
133+
use function VeeWee\Xml\Writer\Builder\cdata;
134+
use function VeeWee\Xml\Writer\Builder\element;
135+
136+
element('foo',
137+
cdata(value('some cdata'))
138+
);
139+
```
140+
141+
```xml
142+
<foo><![CDATA[some cdata]]></foo>
143+
```
144+
126145
#### children
127146

128147
Inserts multiple nodes at current position in the writer.
@@ -164,6 +183,24 @@ function myOwnDataBuilder(): Generator
164183
children(myOwnDataBuilder());
165184
```
166185

186+
#### comment
187+
188+
Writes a comment section:
189+
190+
```php
191+
use function VeeWee\Xml\Dom\Builder\value;
192+
use function VeeWee\Xml\Writer\Builder\comment;
193+
use function VeeWee\Xml\Writer\Builder\element;
194+
195+
element('foo',
196+
comment(value('some comment'))
197+
);
198+
```
199+
200+
```xml
201+
<foo><!--some comment--></foo>
202+
```
203+
167204
#### document
168205

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

258+
259+
#### namespaced_attribute
260+
261+
Can be used to add a namespaced attribute with or without prefix.
262+
This function will also add the xmlns attribute.
263+
264+
```php
265+
use function VeeWee\Xml\Writer\Builder\element;
266+
use function VeeWee\Xml\Writer\Builder\namespaced_attribute;
267+
268+
element('foo',
269+
namespaced_attribute('https://acme.com', 'acme', 'hello', world)
270+
);
271+
```
272+
273+
```xml
274+
<foo xmlns:acme="https://acme.com" acme:hello="world" />
275+
```
276+
277+
#### namespaced_attributes
278+
279+
Can be used to add multiple namespaced attributes with or without prefix at once.
280+
This function will add the xmlns attribute.
281+
282+
```php
283+
use function VeeWee\Xml\Writer\Builder\element;
284+
use function VeeWee\Xml\Writer\Builder\namespaced_attributes;
285+
286+
element('foo',
287+
namespaced_attributes('https://acme.com', [
288+
'acme:hello' => 'world',
289+
'acme:foo' => 'bar',
290+
])
291+
);
292+
```
293+
294+
```xml
295+
<foo xmlns:acme="https://acme.com" acme:hello="world" acme:foo="bar" />
296+
```
297+
298+
#### namespaced_element
299+
300+
Build a namespaced element.
301+
It can contain a set of configurators that can be used to specify the attributes, children, value, ... of the element with or without prefix.
302+
This function will add the xmlns attribute.
303+
304+
```php
305+
use function VeeWee\Xml\Writer\Builder\namespace_attribute;
306+
use function VeeWee\Xml\Writer\Builder\prefixed_element;
307+
308+
namespaced_element('http://acme.com', 'acme', 'hello',
309+
...$configurators
310+
);
311+
```
312+
313+
```xml
314+
<acme:hello xmlns:acme="http://acme.com" />
315+
```
316+
221317
#### prefixed_attribute
222318

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

380+
#### raw
381+
382+
Can be used to insert raw strings into the XML.
383+
Be careful: these strings won't be validated or escaped and are just appended to the XML without any sort of validation.
384+
385+
```php
386+
use function VeeWee\Xml\Writer\Builder\raw;
387+
388+
raw('<hello>world</hello>');
389+
```
390+
391+
```xml
392+
<hello>world</hello>
393+
```
394+
284395
#### value
285396

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

503+
## Mapper
504+
505+
#### memory_output
506+
507+
If you are using an in-memory writer, you can use the `memory_output()` mapper to get the written content as a string.
508+
509+
```php
510+
use VeeWee\Xml\Writer\Writer;
511+
use function VeeWee\Xml\Writer\Mapper\memory_output;
512+
513+
$doc = Writer::inMemory()
514+
->write($yourXml)
515+
->map(memory_output());
516+
```
517+
392518
## Openers
393519

520+
#### memory_opener
521+
522+
Starts a writer that stores the written XML in-memory.
523+
You can use the [memory_output](#memoryoutput) mapper to retrieve the written XML.
524+
525+
```php
526+
use VeeWee\Xml\Writer\Writer;
527+
use function VeeWee\Xml\Writer\Mapper\memory_output;
528+
529+
$doc = Writer::inMemory(...$configurators)
530+
->write($yourXml)
531+
->map(memory_output());
532+
```
533+
394534
#### xml_file_opener
395535

396536
Loads an XML document from a file.

src/Xml/Writer/Builder/cdata.php

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace VeeWee\Xml\Writer\Builder;
6+
7+
use Closure;
8+
use Generator;
9+
use XMLWriter;
10+
11+
/**
12+
* @param list<(callable(XMLWriter): Generator<bool>)> $configurators
13+
*
14+
* @return Closure(XMLWriter): Generator<bool>
15+
*/
16+
function cdata(callable ...$configurators): Closure
17+
{
18+
return
19+
/**
20+
* @return Generator<bool>
21+
*/
22+
static function (XMLWriter $writer) use ($configurators): Generator {
23+
yield $writer->startCdata();
24+
foreach ($configurators as $configurator) {
25+
yield from $configurator($writer);
26+
}
27+
28+
yield $writer->endCdata();
29+
};
30+
}

src/Xml/Writer/Builder/comment.php

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace VeeWee\Xml\Writer\Builder;
6+
7+
use Closure;
8+
use Generator;
9+
use XMLWriter;
10+
11+
/**
12+
* @param list<(callable(XMLWriter): Generator<bool>)> $configurators
13+
*
14+
* @return Closure(XMLWriter): Generator<bool>
15+
*/
16+
function comment(callable ...$configurators): Closure
17+
{
18+
return
19+
/**
20+
* @return Generator<bool>
21+
*/
22+
static function (XMLWriter $writer) use ($configurators): Generator {
23+
yield $writer->startComment();
24+
foreach ($configurators as $configurator) {
25+
yield from $configurator($writer);
26+
}
27+
28+
yield $writer->endComment();
29+
};
30+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace VeeWee\Xml\Writer\Builder;
6+
7+
use Closure;
8+
use Generator;
9+
use XMLWriter;
10+
11+
/**
12+
* @return Closure(XMLWriter): Generator<bool>
13+
*/
14+
function namespaced_attribute(string $namespace, ?string $prefix, string $name, string $value): Closure
15+
{
16+
return
17+
/**
18+
* @return Generator<bool>
19+
*/
20+
static function (XMLWriter $writer) use ($namespace, $prefix, $name, $value): Generator {
21+
yield $writer->startAttributeNs($prefix, $name, $namespace);
22+
yield $writer->text($value);
23+
yield $writer->endAttribute();
24+
};
25+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace VeeWee\Xml\Writer\Builder;
6+
7+
use Closure;
8+
use Generator;
9+
use XMLWriter;
10+
11+
/**
12+
* @param array<string, string> $attributes
13+
* @return Closure(XMLWriter): Generator<bool>
14+
*/
15+
function namespaced_attributes(string $namespace, array $attributes): Closure
16+
{
17+
return
18+
/**
19+
* @return Generator<bool>
20+
*/
21+
static function (XMLWriter $writer) use ($namespace, $attributes): Generator {
22+
foreach ($attributes as $key => $value) {
23+
$parts = explode(':', $key, 2);
24+
$name = array_pop($parts);
25+
$prefix = $parts ? $parts[0] : null;
26+
27+
yield from namespaced_attribute($namespace, $prefix, $name, $value)($writer);
28+
}
29+
};
30+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace VeeWee\Xml\Writer\Builder;
6+
7+
use Closure;
8+
use Generator;
9+
use XMLWriter;
10+
11+
/**
12+
* @param list<(callable(XMLWriter): Generator<bool>)> $configurators
13+
*
14+
* @return Closure(XMLWriter): Generator<bool>
15+
*/
16+
function namespaced_element(string $namespace, ?string $prefix, string $name, callable ...$configurators): Closure
17+
{
18+
return
19+
/**
20+
* @return Generator<bool>
21+
*/
22+
static function (XMLWriter $writer) use ($namespace, $prefix, $name, $configurators): Generator {
23+
yield $writer->startElementNs($prefix, $name, $namespace);
24+
foreach ($configurators as $configurator) {
25+
yield from $configurator($writer);
26+
}
27+
28+
yield $writer->endElement();
29+
};
30+
}

src/Xml/Writer/Builder/raw.php

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace VeeWee\Xml\Writer\Builder;
6+
7+
use Closure;
8+
use Generator;
9+
use XMLWriter;
10+
11+
/**
12+
* @return Closure(XMLWriter): Generator<bool>
13+
*/
14+
function raw(string $value): Closure
15+
{
16+
return
17+
/**
18+
* @return Generator<bool>
19+
*/
20+
static function (XMLWriter $writer) use ($value): Generator {
21+
yield $writer->writeRaw($value);
22+
};
23+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace VeeWee\Xml\Writer\Mapper;
6+
7+
use Closure;
8+
use XMLWriter;
9+
10+
/**
11+
* @return Closure(XMLWriter): string XMLWriter
12+
*/
13+
function memory_output(): Closure
14+
{
15+
return static function (XMLWriter $writer): string {
16+
return $writer->outputMemory();
17+
};
18+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace VeeWee\Xml\Writer\Opener;
6+
7+
use Closure;
8+
use XMLWriter;
9+
10+
/**
11+
* @return Closure(XMLWriter): bool XMLWriter
12+
*/
13+
function memory_opener(): Closure
14+
{
15+
return static function (XMLWriter $writer): bool {
16+
return $writer->openMemory();
17+
};
18+
}

0 commit comments

Comments
 (0)