-
-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Inherit XMLNS during encoding like we did in v3
- Loading branch information
Showing
13 changed files
with
229 additions
and
21 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace VeeWee\Xml\Dom\Builder; | ||
|
||
use Closure; | ||
use Dom\Element; | ||
use VeeWee\Xml\Xmlns\Xmlns; | ||
|
||
/** | ||
* @return Closure(Element): Element | ||
*/ | ||
function default_xmlns_attribute(string $namespaceURI): Closure | ||
{ | ||
return static function (Element $node) use ($namespaceURI): Element { | ||
$node->setAttributeNS(Xmlns::xmlns()->value(), 'xmlns', $namespaceURI); | ||
|
||
return $node; | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace VeeWee\Xml\Dom\Predicate; | ||
|
||
function is_prefixed_node_name(string $nodeName): bool | ||
{ | ||
return (bool)preg_match('/^[^:]+:[^:]+$/', $nodeName); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
62 changes: 62 additions & 0 deletions
62
src/Xml/Encoding/Internal/Encoder/Builder/xmlns_inheriting_element.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace VeeWee\Xml\Encoding\Internal\Encoder\Builder; | ||
|
||
use Closure; | ||
use Dom\Element; | ||
use Dom\XMLDocument; | ||
use Webmozart\Assert\Assert; | ||
use function VeeWee\Xml\Dom\Builder\default_xmlns_attribute; | ||
use function VeeWee\Xml\Dom\Builder\element as elementBuilder; | ||
use function VeeWee\Xml\Dom\Builder\namespaced_element as namespacedElementBuilder; | ||
use function VeeWee\Xml\Dom\Predicate\is_element; | ||
use function VeeWee\Xml\Dom\Predicate\is_prefixed_node_name; | ||
|
||
/** | ||
* This function can create element nodes that inherit the local xmlns namespace of their parent if none is configured. | ||
* | ||
* @param list<Closure(Element): Element> $children | ||
* @param array<string, string> $namespaces | ||
* | ||
* @return Closure(Element): Element | ||
*/ | ||
function xmlns_inheriting_element(string $name, array $children, ?array $namespaces = []): Closure | ||
{ | ||
return static function (XMLDocument|Element $parent) use ($namespaces, $name, $children): Element { | ||
|
||
$defaultNamespace = $namespaces[''] ?? null; | ||
|
||
// These rules apply for non prefixed elements only: | ||
// If no local namespace has been defined: lookup the default local namespace of the closest parent element. | ||
// Use that specific local namespace to create the element if one could be found. | ||
// Otherwise, just create a non-namespaced element. | ||
if (!is_prefixed_node_name($name)) { | ||
// Try to find the inherited default XMLNS for non prefixed elements without a desired local namespace. | ||
if ($defaultNamespace === null && is_element($parent)) { | ||
$defaultNamespace = $parent->lookupNamespaceURI(''); | ||
} | ||
|
||
return $defaultNamespace !== null | ||
? namespacedElementBuilder($defaultNamespace, $name, ...$children)($parent) | ||
: elementBuilder($name, ...$children)($parent); | ||
} | ||
|
||
// Prefixed elements can be created as regular elements: | ||
// The configured xmlns attributes will be added by the $children. | ||
// If a local namespace is configured, make sure to register it on the node manually. | ||
[$prefix] = explode(':', $name); | ||
$prefixedNamespace = $namespaces[$prefix] ?? (is_element($parent) ? $parent->lookupNamespaceURI($prefix) : null); | ||
|
||
Assert::notNull($prefixedNamespace, 'No namespace URI could be found for prefix: '.$prefix); | ||
|
||
$defaultXmlns = $defaultNamespace !== null ? [default_xmlns_attribute($defaultNamespace)] : []; | ||
return namespacedElementBuilder( | ||
$prefixedNamespace, | ||
$name, | ||
...$defaultXmlns, | ||
...$children, | ||
)($parent); | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace VeeWee\Tests\Xml\Dom\Builder; | ||
|
||
use PHPUnit\Framework\TestCase; | ||
use VeeWee\Xml\Dom\Document; | ||
use function VeeWee\Xml\Dom\Builder\default_xmlns_attribute; | ||
use function VeeWee\Xml\Dom\Builder\element; | ||
use function VeeWee\Xml\Dom\Builder\namespaced_element; | ||
|
||
final class DefaultXmlnsAttributeTest extends TestCase | ||
{ | ||
public function test_it_can_build_an_element_with_default_xmlns_on_namespaced_element(): void | ||
{ | ||
$doc = Document::empty()->toUnsafeDocument(); | ||
|
||
$node = namespaced_element( | ||
'uri://x', | ||
'x:foo', | ||
default_xmlns_attribute('uri://default') | ||
)($doc); | ||
|
||
static::assertSame('<x:foo xmlns:x="uri://x" xmlns="uri://default"/>', $doc->saveXml($node)); | ||
} | ||
|
||
public function test_it_can_not_build_an_element_with_default_xmlns_on_regular_element(): void | ||
{ | ||
$doc = Document::empty()->toUnsafeDocument(); | ||
|
||
$node = element( | ||
'foo', | ||
default_xmlns_attribute('uri://default') | ||
)($doc); | ||
|
||
static::assertSame('<foo/>', $doc->saveXml($node)); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace VeeWee\Tests\Xml\Dom\Predicate; | ||
|
||
use PHPUnit\Framework\TestCase; | ||
use function VeeWee\Xml\Dom\Predicate\is_prefixed_node_name; | ||
|
||
final class IsPrefixedNodeNameTest extends TestCase | ||
{ | ||
/** | ||
* | ||
* @dataProvider provideValidQNames | ||
*/ | ||
public function test_it_does_nothing_on_valid_qnames(string $input): void | ||
{ | ||
static::assertTrue(is_prefixed_node_name($input)); | ||
} | ||
|
||
/** | ||
* | ||
* @dataProvider provideInvalidQNames | ||
*/ | ||
public function test_it_throws_on_invalid_qnames(string $input): void | ||
{ | ||
static::assertFalse(is_prefixed_node_name($input)); | ||
} | ||
|
||
public static function provideValidQNames() | ||
{ | ||
yield ['hello:world']; | ||
yield ['a:b']; | ||
yield ['---a----:----b---']; | ||
} | ||
|
||
public static function provideInvalidQNames() | ||
{ | ||
yield ['']; | ||
yield ['aa']; | ||
yield ['aa:']; | ||
yield [':bb']; | ||
yield [':b:c:cd:dz']; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters