Skip to content

Commit

Permalink
New namspaces system
Browse files Browse the repository at this point in the history
  • Loading branch information
veewee committed Feb 23, 2024
1 parent 74328c7 commit 8a61a7b
Show file tree
Hide file tree
Showing 15 changed files with 49 additions and 47 deletions.
15 changes: 4 additions & 11 deletions src/Xml/Dom/Locator/Attribute/xmlns_attributes_list.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,16 @@

namespace VeeWee\Xml\Dom\Locator\Attribute;

use \DOM\NameSpaceNode;
use \DOM\Node;
use VeeWee\Xml\Dom\Collection\NodeList;
use VeeWee\Xml\Exception\RuntimeException;
use function VeeWee\Xml\Dom\Locator\Xmlns\linked_namespaces;
use function VeeWee\Xml\Dom\Predicate\is_element;
use function VeeWee\Xml\Dom\Predicate\is_xmlns_attribute;

/**
* @return NodeList<\DOM\NameSpaceNode>
* @return NodeList<\DOM\Attr>
* @throws RuntimeException
*/
function xmlns_attributes_list(\DOM\Node $node): NodeList
{
if (! is_element($node)) {
return NodeList::empty();
}

return linked_namespaces($node)
->filter(static fn (\DOM\NameSpaceNode $namespace): bool => $node->hasAttribute($namespace->nodeName));
return attributes_list($node)
->filter(static fn (\DOM\Attr $attribute): bool => is_xmlns_attribute($attribute));
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,16 @@

namespace VeeWee\Xml\Dom\Manipulator\Element;

use \DOM\Element;
use \DOM\NameSpaceNode;
use VeeWee\Xml\Exception\RuntimeException;
use function VeeWee\Xml\Dom\Builder\xmlns_attribute;
use function VeeWee\Xml\Dom\Locator\Xmlns\linked_namespaces;
use function VeeWee\Xml\Dom\Locator\Attribute\xmlns_attributes_list;

/**
* @throws RuntimeException
*/
function copy_named_xmlns_attributes(\DOM\Element $target, \DOM\Element $source): void
{
linked_namespaces($source)->forEach(static function (\DOM\NameSpaceNode $xmlns) use ($target) {
xmlns_attributes_list($source)->forEach(static function (\DOM\Attr $xmlns) use ($target) {
if ($xmlns->prefix && !$target->hasAttribute($xmlns->nodeName)) {
xmlns_attribute($xmlns->prefix, $xmlns->namespaceURI)($target);
}
Expand Down
3 changes: 1 addition & 2 deletions src/Xml/Dom/Manipulator/Element/rename.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

namespace VeeWee\Xml\Dom\Manipulator\Element;

use \DOM\NameSpaceNode;
use VeeWee\Xml\Exception\RuntimeException;
use function VeeWee\Xml\Dom\Builder\element;
use function VeeWee\Xml\Dom\Builder\namespaced_element;
Expand Down Expand Up @@ -33,7 +32,7 @@ function rename(\DOM\Element $target, string $newQName, ?string $newNamespaceURI
append(...children($target))($newElement);

xmlns_attributes_list($target)->forEach(
static function (\DOM\NameSpaceNode $attribute) use ($target, $newElement): void {
static function (\DOM\Attr $attribute) use ($target, $newElement): void {
if (is_default_xmlns_attribute($attribute) || $target->prefix === $attribute->prefix) {
return;
}
Expand Down
8 changes: 3 additions & 5 deletions src/Xml/Dom/Manipulator/Node/remove_namespace.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,24 +4,22 @@

namespace VeeWee\Xml\Dom\Manipulator\Node;

use \DOM\Element;
use \DOM\NameSpaceNode;
use VeeWee\Xml\Exception\RuntimeException;
use function VeeWee\Xml\ErrorHandling\disallow_issues;
use function VeeWee\Xml\ErrorHandling\disallow_libxml_false_returns;

/**
* @throws RuntimeException
*/
function remove_namespace(\DOM\NameSpaceNode $target, \DOM\Element $parent): \DOM\NameSpaceNode
function remove_namespace(\DOM\Attr $target, \DOM\Element $parent): \DOM\Attr
{
return disallow_issues(
/**
* @throws RuntimeException
*/
static function () use ($target, $parent): \DOM\NameSpaceNode {
static function () use ($target, $parent): \DOM\Attr {
disallow_libxml_false_returns(
$parent->removeAttributeNS($target->namespaceURI, $target->prefix),
$parent->removeAttributeNode($target),
'Could not remove xmlns attribute from dom element'
);

Expand Down
2 changes: 1 addition & 1 deletion src/Xml/Dom/Manipulator/Xmlns/rename.php
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ static function (\DOM\Node $node) use ($namespaceURI, $newPrefix, $predicate, $r
// Remove old xmlns declarations:
$namespaceNodes = xmlns_attributes_list($node)
->filter(
static fn (\DOM\NameSpaceNode $xmlns): bool
static fn (\DOM\Attr $xmlns): bool
=> $xmlns->namespaceURI === $namespaceURI && $xmlns->prefix !== $newPrefix
);

Expand Down
10 changes: 10 additions & 0 deletions src/Xml/Dom/Manipulator/append.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@
use Closure;
use \DOM\Node;
use VeeWee\Xml\Exception\RuntimeException;
use function VeeWee\Xml\Dom\Predicate\is_attribute;
use function VeeWee\Xml\Dom\Predicate\is_element;
use function VeeWee\Xml\ErrorHandling\disallow_issues;
use function VeeWee\Xml\ErrorHandling\disallow_libxml_false_returns;

/**
* @no-named-arguments
Expand All @@ -19,6 +22,13 @@ function append(\DOM\Node ... $nodes): Closure
return static fn (\DOM\Node $target): \DOM\Node => disallow_issues(
static function () use ($target, $nodes) {
foreach ($nodes as $node) {
// Attributes cannot be appended with appendChild.
// Setting the attribute node to the element is the correct way to append an attribute.
if (is_attribute($node) && is_element($target)) {
$target->setAttributeNode($node);
continue;
}

$target->appendChild($node);
}

Expand Down
3 changes: 1 addition & 2 deletions src/Xml/Dom/Predicate/is_default_xmlns_attribute.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,9 @@

namespace VeeWee\Xml\Dom\Predicate;

use \DOM\NameSpaceNode;
use \DOM\Node;

function is_default_xmlns_attribute(\DOM\Node|\DOM\NameSpaceNode $node): bool
function is_default_xmlns_attribute(\DOM\Node $node): bool
{
return is_xmlns_attribute($node) && $node->prefix === '';
}
3 changes: 1 addition & 2 deletions src/Xml/Dom/Predicate/is_document_element.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,10 @@

namespace VeeWee\Xml\Dom\Predicate;

use \DOM\NameSpaceNode;
use \DOM\Node;
use function VeeWee\Xml\Dom\Locator\Node\detect_document;

function is_document_element(\DOM\Node|\DOM\NameSpaceNode $node): bool
function is_document_element(\DOM\Node $node): bool
{
return is_element($node) && detect_document($node)->documentElement === $node;
}
8 changes: 4 additions & 4 deletions src/Xml/Dom/Predicate/is_xmlns_attribute.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@

namespace VeeWee\Xml\Dom\Predicate;

use \DOM\NameSpaceNode;
use \DOM\Node;
use VeeWee\Xml\Xmlns\Xmlns;

/**
* @psalm-assert-if-true \DOM\NameSpaceNode $node
* @psalm-assert-if-true \DOM\Attr $node
*/
function is_xmlns_attribute(\DOM\Node|\DOM\NameSpaceNode $node): bool
function is_xmlns_attribute(\DOM\Node $node): bool
{
return $node instanceof \DOM\NameSpaceNode;
return is_attribute($node) && $node->namespaceURI === Xmlns::xmlns()->value();
}
15 changes: 8 additions & 7 deletions src/Xml/Dom/Traverser/Visitor/RemoveNamespaces.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,24 @@

namespace VeeWee\Xml\Dom\Traverser\Visitor;

use \DOM\NameSpaceNode;
use \DOM\Attr;
use \DOM\Node;
use VeeWee\Xml\Dom\Traverser\Action;
use VeeWee\Xml\Exception\RuntimeException;
use function Psl\Iter\contains;
use function VeeWee\Xml\Dom\Locator\Attribute\xmlns_attributes_list;
use function VeeWee\Xml\Dom\Predicate\is_element;
use function VeeWee\Xml\Dom\Predicate\is_xmlns_attribute;

final class RemoveNamespaces extends AbstractVisitor
{
/**
* @var null | callable(\DOM\NameSpaceNode): bool
* @var null | callable(\DOM\Attr): bool
*/
private $filter;

/**
* @param null | callable(\DOM\NameSpaceNode): bool $filter
* @param null | callable(\DOM\Attr): bool $filter
*/
public function __construct(
?callable $filter = null
Expand All @@ -35,14 +36,14 @@ public static function all(): self
public static function prefixed(): self
{
return new self(
static fn (\DOM\NameSpaceNode $node): bool => $node->prefix !== ''
static fn (\DOM\Attr $node): bool => $node->prefix !== ''
);
}

public static function unprefixed(): self
{
return new self(
static fn (\DOM\NameSpaceNode $node): bool => $node->prefix === ''
static fn (\DOM\Attr $node): bool => $node->prefix === ''
);
}

Expand All @@ -52,7 +53,7 @@ public static function unprefixed(): self
public static function byPrefixNames(array $prefixes): self
{
return new self(
static fn (\DOM\NameSpaceNode $node): bool => contains($prefixes, $node->prefix)
static fn (\DOM\Attr $node): bool => contains($prefixes, $node->prefix)
);
}

Expand All @@ -62,7 +63,7 @@ public static function byPrefixNames(array $prefixes): self
public static function byNamespaceURIs(array $URIs): self
{
return new self(
static fn (\DOM\NameSpaceNode $node): bool => contains($URIs, $node->namespaceURI)
static fn (\DOM\Attr $node): bool => contains($URIs, $node->namespaceURI)
);
}

Expand Down
6 changes: 4 additions & 2 deletions src/Xml/Dom/Traverser/Visitor/SortAttributes.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@

use VeeWee\Xml\Dom\Traverser\Action;
use function VeeWee\Xml\Dom\Locator\Attribute\attributes_list;
use function VeeWee\Xml\Dom\Manipulator\append;
use function VeeWee\Xml\Dom\Manipulator\Node\remove;
use function VeeWee\Xml\Dom\Predicate\is_element;
use function VeeWee\Xml\ErrorHandling\disallow_issues;

Expand All @@ -22,8 +24,8 @@ public function onNodeEnter(\DOM\Node $node): Action
->forEach(
static function (\DOM\Attr $attr) use ($node): void {
disallow_issues(static function () use ($node, $attr) {
$node->removeAttributeNode($attr);
$node->setAttributeNode($attr);
remove($attr);
append($attr)($node);
});
}
);
Expand Down
4 changes: 3 additions & 1 deletion src/Xml/Encoding/Internal/Decoder/Builder/attributes.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
use function Psl\Dict\filter;
use function Psl\Dict\merge;
use function Psl\Iter\reduce;
use function VeeWee\Xml\Dom\Locator\Attribute\attributes_list;
use function VeeWee\Xml\Dom\Predicate\is_xmlns_attribute;

/**
* @psalm-internal VeeWee\Xml\Encoding
Expand All @@ -17,7 +19,7 @@ function attributes(\DOM\Element $element): array
{
return filter([
'@attributes' => reduce(
$element->attributes,
attributes_list($element)->filter(static fn(\DOM\Attr $attr): bool => !is_xmlns_attribute($attr)),
static fn (array $attributes, \DOM\Attr $attr): array
=> merge($attributes, attribute($attr)),
[]
Expand Down
7 changes: 4 additions & 3 deletions src/Xml/Encoding/Internal/Decoder/Builder/namespaces.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
namespace VeeWee\Xml\Encoding\Internal\Decoder\Builder;

use \DOM\Element;
use \DOM\NameSpaceNode;
use VeeWee\Xml\Exception\RuntimeException;
use function Psl\Dict\filter;
use function Psl\Dict\merge;
Expand All @@ -20,9 +19,11 @@ function namespaces(\DOM\Element $element): array
{
return filter([
'@namespaces' => xmlns_attributes_list($element)->reduce(
static fn (array $namespaces, \DOM\NameSpaceNode $node)
static fn (array $namespaces, \DOM\Attr $node)
=> $node->namespaceURI
? merge($namespaces, [(string) $node->prefix => $node->namespaceURI])
? merge($namespaces, [
($node->prefix ? $node->localName : '') => $node->value
])
: $namespaces,
[]
),
Expand Down
2 changes: 1 addition & 1 deletion tests/Xml/Dom/Manipulator/Xmlns/RenameTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public function test_it_can_rename_namespaces(string $input, string $expected):
static::assertSame($expected, $actual);
}


public function test_it_can_not_rename_existing_prefix_to_other_uri(): void
{
$document = Document::fromXmlString('<hello xmlns:ns1="http://ok" />')->toUnsafeDocument();
Expand Down
4 changes: 2 additions & 2 deletions tests/Xml/Encoding/EncodingTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@

final class EncodingTest extends TestCase
{
private const XML_HEADER = '<?xml version="1.0"?>';
private const XML_HEADER = '<?xml version="1.0" encoding="UTF-8"?>';

/**
* @dataProvider provideBidirectionalCases
Expand Down Expand Up @@ -263,8 +263,8 @@ public function provideRiskyBidirectionalCases()
EOXML,
'data' => ['root' => [
'@namespaces' => [
'test' => 'http://testy.test',
'' => 'http://rooty.root',
'test' => 'http://testy.test',
],
'test:item' => [
'id:int' => [
Expand Down

0 comments on commit 8a61a7b

Please sign in to comment.