Skip to content

Commit

Permalink
Provide better reader matchers
Browse files Browse the repository at this point in the history
  • Loading branch information
veewee committed Oct 30, 2023
1 parent 3efeabd commit 33570df
Show file tree
Hide file tree
Showing 39 changed files with 1,682 additions and 70 deletions.
192 changes: 186 additions & 6 deletions docs/reader.md
Original file line number Diff line number Diff line change
Expand Up @@ -146,31 +146,211 @@ $reader = Reader::configure($yourLoader, ...$configurators);

#### all

All provided matchers need to match in order for this matcher to succceed:
All provided matchers need to match in order for this matcher to succeed:

```php
use \VeeWee\Xml\Reader\Matcher;

Matcher\all(
Matcher\node_name('item'),
Matcher\node_attribute('locale', 'nl-BE')
);
```

#### node_attribute
#### any

One of the provided matchers need to match in order for this matcher to succeed:

```php
use \VeeWee\Xml\Reader\Matcher;

Matcher\any(
Matcher\node_name('item'),
Matcher\node_name('product'),
);
```

#### attribute_local_name

Matches current element based on attribute exists: `locale`.
Also prefixed attributes will be matched `some:locale`.

```php
use \VeeWee\Xml\Reader\Matcher;

Matcher\attribute_local_name('locale');
```

#### attribute_local_value

Matches current element based on attribute value `locale="nl-BE"`.
Also prefixed attributes will be matched `some:locale="nl-BE"`.

```php
use \VeeWee\Xml\Reader\Matcher;

Matcher\attribute_local_value('locale', 'nl-BE');
```

#### attribute_name

Matches current element based on attribute exists: `locale`.

```php
use \VeeWee\Xml\Reader\Matcher;

Matcher\attribute_name('locale');
// OR
Matcher\attribute_name('prefixed:locale');
```

#### attribute_value

Matches current element based on attribute value `locale="nl-BE"`.

```php
use \VeeWee\Xml\Reader\Matcher;

Matcher\attribute_value('locale', 'nl-BE');
// OR
Matcher\attribute_value('prefixed:locale', 'nl-BE');
```

#### document_element

Matches current element on attribute `locale="nl-BE"`.
Matches on the root document element only.

```php
Matcher\node_attribute('locale', 'nl-BE');
use \VeeWee\Xml\Reader\Matcher;

Matcher\document_element();
```

#### node_name
#### element_local_name

Matches current element on node name `<item />`.
Also prefixed elements will be matched: `<some:item />`.

```php
Matcher\node_name('item');
use \VeeWee\Xml\Reader\Matcher;

Matcher\element_local_name('item');
```

#### element_name

Matches current element on full node name `<item />`.

```php
use \VeeWee\Xml\Reader\Matcher;

Matcher\element_name('item');
// OR
Matcher\element_name('some:item');
```

#### element_position

Matches current element on the position of the element in the XML tree.
Given following example:

```xml
<items>
<item />
<item />
<item />
</items>
```

Only the middle `<item />` will be matched.

```php
use \VeeWee\Xml\Reader\Matcher;

Matcher\element_position(1);
```

#### namespaced_attribute

Matches current element based on attribute XMLNS namespace `https://some` and attribute key `locale`.

```php
use \VeeWee\Xml\Reader\Matcher;

Matcher\namespaced_attribute('https://some', 'locale');
```

#### namespaced_attribute_value

Matches current element based on attribute namespace `https://some` and value `locale="nl-BE"`.

```php
use \VeeWee\Xml\Reader\Matcher;

Matcher\namespaced_attribute_value('https://some', 'locale', 'nl-BE');
```

#### namespaced_element

Matches current element on namespace and element name `<item xmlns="https://some" />`.

```php
use \VeeWee\Xml\Reader\Matcher;

Matcher\namespaced_element('https://some', 'item');
```

#### not

Inverses a matcher's result.

```php
use \VeeWee\Xml\Reader\Matcher;

Matcher\not(
Matcher\element_name('item')
);
```

#### sequence

Provide a sequence of matchers that represents the XML tree.
Only the items that are described by the sequence will match.

Given:

```xml
<root>
<users>
<user locale="nl">Jos</user>
<user>Bos</user>
<user>Mos</user>
</users>
</root>
```

This matcher will grab the `user` element with `locale="nl"`

```php
use \VeeWee\Xml\Reader\Matcher;

Matcher\not(
// Level 0: <root />
Matcher\document_element(),
// Level 1: <users />
// all() Acts as a wildcard to grab any element under document element.
// You could also go for the more exact element_name('users')
Matcher\all(),
// Level 2: <user locale="nl">Jos</user>
// Searches for all elements that matches `<user />` and attribute `locale="nl"`
Matcher\all(
element_name('user'),
attribute_value('locale', 'nl')
)
);
```


#### Writing your own matcher

A matcher can be any `callable` that takes a `NodeSequence` as input and returns a `bool` that specifies if it matches or not:
Expand Down
5 changes: 5 additions & 0 deletions psalm.xml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,11 @@
<directory name="tests"/>
</errorLevel>
</UndefinedClass>
<MissingDependency>
<errorLevel type="suppress">
<directory name="tests"/>
</errorLevel>
</MissingDependency>
<MixedArgumentTypeCoercion>
<errorLevel type="suppress">
<directory name="src/Xml/Encoding/Internal/Encoder/Builder" />
Expand Down
2 changes: 1 addition & 1 deletion src/Xml/Dom/Loader/xml_file_loader.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ function xml_file_loader(string $file, int $options = 0): Closure
load(
static function () use ($document, $file, $options): bool {
Assert::fileExists($file);
return (bool) $document->load($file, $options);
return $document->load($file, $options);
}
);
};
Expand Down
2 changes: 1 addition & 1 deletion src/Xml/Dom/Loader/xml_string_loader.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,6 @@
function xml_string_loader(string $xml, int $options = 0): Closure
{
return static function (DOMDocument $document) use ($xml, $options): void {
load(static fn (): bool => (bool) $document->loadXML($xml, $options));
load(static fn (): bool => $document->loadXML($xml, $options));
};
}
25 changes: 25 additions & 0 deletions src/Xml/Reader/Matcher/any.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?php

declare(strict_types=1);

namespace VeeWee\Xml\Reader\Matcher;

use Closure;
use Psl\Iter;
use VeeWee\Xml\Reader\Node\NodeSequence;

/**
* @param list<callable(NodeSequence): bool> $matchers
*
* @return \Closure(NodeSequence): bool
*/
function any(callable ... $matchers): Closure
{
return static fn (NodeSequence $sequence): bool => Iter\any(
$matchers,
/**
* @param callable(NodeSequence): bool $matcher
*/
static fn (callable $matcher): bool => $matcher($sequence)
);
}
23 changes: 23 additions & 0 deletions src/Xml/Reader/Matcher/attribute_local_name.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?php

declare(strict_types=1);

namespace VeeWee\Xml\Reader\Matcher;

use Closure;
use VeeWee\Xml\Reader\Node\AttributeNode;
use VeeWee\Xml\Reader\Node\NodeSequence;
use function Psl\Iter\any;

/**
* @return \Closure(NodeSequence): bool
*/
function attribute_local_name(string $localName): Closure
{
return static function (NodeSequence $sequence) use ($localName): bool {
return any(
$sequence->current()->attributes(),
static fn (AttributeNode $attribute): bool => $attribute->localName() === $localName
);
};
}
23 changes: 23 additions & 0 deletions src/Xml/Reader/Matcher/attribute_local_value.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?php

declare(strict_types=1);

namespace VeeWee\Xml\Reader\Matcher;

use Closure;
use VeeWee\Xml\Reader\Node\AttributeNode;
use VeeWee\Xml\Reader\Node\NodeSequence;
use function Psl\Iter\any;

/**
* @return \Closure(NodeSequence): bool
*/
function attribute_local_value(string $localName, string $value): Closure
{
return static function (NodeSequence $sequence) use ($localName, $value): bool {
return any(
$sequence->current()->attributes(),
static fn (AttributeNode $attribute): bool => $attribute->localName() === $localName && $attribute->value() === $value
);
};
}
23 changes: 23 additions & 0 deletions src/Xml/Reader/Matcher/attribute_name.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?php

declare(strict_types=1);

namespace VeeWee\Xml\Reader\Matcher;

use Closure;
use VeeWee\Xml\Reader\Node\AttributeNode;
use VeeWee\Xml\Reader\Node\NodeSequence;
use function Psl\Iter\any;

/**
* @return \Closure(NodeSequence): bool
*/
function attribute_name(string $name): Closure
{
return static function (NodeSequence $sequence) use ($name): bool {
return any(
$sequence->current()->attributes(),
static fn (AttributeNode $attribute): bool => $attribute->name() === $name
);
};
}
23 changes: 23 additions & 0 deletions src/Xml/Reader/Matcher/attribute_value.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?php

declare(strict_types=1);

namespace VeeWee\Xml\Reader\Matcher;

use Closure;
use VeeWee\Xml\Reader\Node\AttributeNode;
use VeeWee\Xml\Reader\Node\NodeSequence;
use function Psl\Iter\any;

/**
* @return \Closure(NodeSequence): bool
*/
function attribute_value(string $name, string $value): Closure
{
return static function (NodeSequence $sequence) use ($name, $value): bool {
return any(
$sequence->current()->attributes(),
static fn (AttributeNode $attribute): bool => $attribute->name() === $name && $attribute->value() === $value
);
};
}
18 changes: 18 additions & 0 deletions src/Xml/Reader/Matcher/document_element.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?php

declare(strict_types=1);

namespace VeeWee\Xml\Reader\Matcher;

use Closure;
use VeeWee\Xml\Reader\Node\NodeSequence;

/**
* @return \Closure(NodeSequence): bool
*/
function document_element(): Closure
{
return static function (NodeSequence $sequence): bool {
return !$sequence->parent();
};
}
Loading

0 comments on commit 33570df

Please sign in to comment.