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 ae90b22
Show file tree
Hide file tree
Showing 38 changed files with 1,496 additions and 64 deletions.
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();
};
}
18 changes: 18 additions & 0 deletions src/Xml/Reader/Matcher/element_local_name.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 element_local_name(string $localName): Closure
{
return static function (NodeSequence $sequence) use ($localName): bool {
return $sequence->current()->localName() === $localName;
};
}
18 changes: 18 additions & 0 deletions src/Xml/Reader/Matcher/element_name.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 element_name(string $name): Closure
{
return static function (NodeSequence $sequence) use ($name): bool {
return $sequence->current()->name() === $name;
};
}
18 changes: 18 additions & 0 deletions src/Xml/Reader/Matcher/element_position.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 element_position(int $position): Closure
{
return static function (NodeSequence $sequence) use ($position): bool {
return $sequence->current()->position() === $position;
};
}
23 changes: 23 additions & 0 deletions src/Xml/Reader/Matcher/namespaced_attribute.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 namespaced_attribute(string $namespace, string $localName): Closure
{
return static function (NodeSequence $sequence) use ($namespace, $localName): bool {
return any(
$sequence->current()->attributes(),
static fn (AttributeNode $attribute): bool => $attribute->localName() === $localName && $attribute->namespace() === $namespace
);
};
}
26 changes: 26 additions & 0 deletions src/Xml/Reader/Matcher/namespaced_attribute_value.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?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 namespaced_attribute_value(string $namespace, string $localName, string $value): Closure
{
return static function (NodeSequence $sequence) use ($namespace, $localName, $value): bool {
return any(
$sequence->current()->attributes(),
static fn (AttributeNode $attribute): bool =>
$attribute->localName() === $localName
&& $attribute->namespace() === $namespace
&& $attribute->value() === $value
);
};
}
20 changes: 20 additions & 0 deletions src/Xml/Reader/Matcher/namespaced_element.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?php

declare(strict_types=1);

namespace VeeWee\Xml\Reader\Matcher;

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

/**
* @return \Closure(NodeSequence): bool
*/
function namespaced_element(string $namespace, string $localName): Closure
{
return static function (NodeSequence $sequence) use ($namespace, $localName): bool {
$current = $sequence->current();

return $current->localName() === $localName && $current->namespace() === $namespace;
};
}
1 change: 1 addition & 0 deletions src/Xml/Reader/Matcher/node_attribute.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
use function Psl\Iter\any;

/**
* @deprecated Use attribute_value instead! This will be removed in next major version
* @return \Closure(NodeSequence): bool
*/
function node_attribute(string $key, string $value): Closure
Expand Down
1 change: 1 addition & 0 deletions src/Xml/Reader/Matcher/node_name.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
use VeeWee\Xml\Reader\Node\NodeSequence;

/**
* @deprecated Use element_name instead! This will be removed in next major version
* @return \Closure(NodeSequence): bool
*/
function node_name(string $name): Closure
Expand Down
18 changes: 18 additions & 0 deletions src/Xml/Reader/Matcher/not.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;

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

declare(strict_types=1);

namespace VeeWee\Xml\Reader\Matcher;

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

/**
* A sequence can be used to match a full XML path to the node you are interested in.
*
* ```php
* sequence(element_name('root'), all(element_name('item'), element_position(1)), element_name('name'));
* ```
*
* @param non-empty-list<callable(NodeSequence): bool> $matcherSequence
*
* @return \Closure(NodeSequence): bool
*/
function sequence(callable ... $matcherSequence): Closure
{
return static function (NodeSequence $sequence) use ($matcherSequence) : bool {
$nodeSequence = $sequence->sequence();
if (count($matcherSequence) !== count($nodeSequence)) {
return false;
}

$currentSequence = new NodeSequence();
foreach ($nodeSequence as $i => $node) {
$currentSequence = $currentSequence->append($node);
$matcher = $matcherSequence[$i];
if (!$matcher($currentSequence)) {
return false;
}
}

return true;
};
}
14 changes: 14 additions & 0 deletions src/bootstrap.php
Original file line number Diff line number Diff line change
Expand Up @@ -124,8 +124,22 @@
require_once __DIR__.'/Xml/Reader/Loader/xml_file_loader.php';
require_once __DIR__.'/Xml/Reader/Loader/xml_string_loader.php';
require_once __DIR__.'/Xml/Reader/Matcher/all.php';
require_once __DIR__.'/Xml/Reader/Matcher/any.php';
require_once __DIR__.'/Xml/Reader/Matcher/attribute_local_name.php';
require_once __DIR__.'/Xml/Reader/Matcher/attribute_local_value.php';
require_once __DIR__.'/Xml/Reader/Matcher/attribute_name.php';
require_once __DIR__.'/Xml/Reader/Matcher/attribute_value.php';
require_once __DIR__.'/Xml/Reader/Matcher/document_element.php';
require_once __DIR__.'/Xml/Reader/Matcher/element_local_name.php';
require_once __DIR__.'/Xml/Reader/Matcher/element_name.php';
require_once __DIR__.'/Xml/Reader/Matcher/element_position.php';
require_once __DIR__.'/Xml/Reader/Matcher/namespaced_attribute.php';
require_once __DIR__.'/Xml/Reader/Matcher/namespaced_attribute_value.php';
require_once __DIR__.'/Xml/Reader/Matcher/namespaced_element.php';
require_once __DIR__.'/Xml/Reader/Matcher/node_attribute.php';
require_once __DIR__.'/Xml/Reader/Matcher/node_name.php';
require_once __DIR__.'/Xml/Reader/Matcher/not.php';
require_once __DIR__.'/Xml/Reader/Matcher/sequence.php';
require_once __DIR__.'/Xml/Writer/Builder/attribute.php';
require_once __DIR__.'/Xml/Writer/Builder/attributes.php';
require_once __DIR__.'/Xml/Writer/Builder/children.php';
Expand Down
Loading

0 comments on commit ae90b22

Please sign in to comment.