Skip to content

Commit b5debff

Browse files
committed
Inherit XMLNS during encoding like we did in v3
1 parent 86a8497 commit b5debff

File tree

11 files changed

+83
-18
lines changed

11 files changed

+83
-18
lines changed

src/Xml/Dom/Builder/nodes.php

+3-4
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,14 @@
66

77
use Closure;
88
use Dom\Node;
9-
use Dom\XMLDocument;
109
use function is_array;
1110
use function Psl\Iter\reduce;
1211
use function VeeWee\Xml\Dom\Locator\Node\detect_document;
1312

1413
/**
15-
* @param list<callable(XMLDocument): (list<Node>|Node)> $builders
14+
* @param list<callable(Node): (list<Node>|Node)> $builders
1615
*
17-
* @return Closure(XMLDocument): list<Node>
16+
* @return Closure(Node): list<Node>
1817
*/
1918
function nodes(callable ... $builders): Closure
2019
{
@@ -27,7 +26,7 @@ function nodes(callable ... $builders): Closure
2726
$builders,
2827
/**
2928
* @param list<Node> $builds
30-
* @param callable(XMLDocument): (Node|list<Node>) $builder
29+
* @param callable(Node): (Node|list<Node>) $builder
3130
* @return list<Node>
3231
*/
3332
static function (array $builds, callable $builder) use ($node): array {

src/Xml/Dom/Document.php

+2
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,8 @@ public function manipulate(callable $manipulator): self
130130
}
131131

132132
/**
133+
* @psalm-suppress ArgumentTypeCoercion - nodes() works on node but we provide the parent type XMLDocument.
134+
*
133135
* @param list<callable(XMLDocument): (list<Node>|Node)> $builders
134136
*
135137
* @return list<Node>
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\Dom\Locator\Xmlns;
6+
7+
use Dom\Element;
8+
9+
function closest_unprefixed_xmlns(Element $node): ?string
10+
{
11+
foreach (linked_namespaces($node) as $namespace) {
12+
if ($namespace->prefix === null) {
13+
return $namespace->namespaceURI;
14+
}
15+
}
16+
17+
return null;
18+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace VeeWee\Xml\Dom\Predicate;
6+
7+
use function Psl\Result\wrap;
8+
use function VeeWee\Xml\Assertion\assert_strict_prefixed_name;
9+
10+
function is_prefixed_node_name(string $nodeName): bool
11+
{
12+
return wrap(static fn () => assert_strict_prefixed_name($nodeName))->proceed(
13+
static fn() => true,
14+
static fn() => false,
15+
);
16+
}

src/Xml/Encoding/Internal/Decoder/Builder/namespaces.php

+3-6
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,9 @@ function namespaces(Element $element): array
2020
{
2121
return filter([
2222
'@namespaces' => xmlns_attributes_list($element)->reduce(
23-
static fn (array $namespaces, Attr $node)
24-
=> $node->value
25-
? merge($namespaces, [
26-
($node->prefix !== null ? $node->localName : '') => $node->value
27-
])
28-
: $namespaces,
23+
static fn (array $namespaces, Attr $node) => merge($namespaces, [
24+
($node->prefix !== null ? $node->localName : '') => $node->value
25+
]),
2926
[]
3027
),
3128
]);

src/Xml/Encoding/Internal/Encoder/Builder/children.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ function children(string $name, array $children): Closure
2828
*/
2929
static fn (array|string $data): Closure => is_array($data)
3030
? element($name, $data)
31-
: elementBuilder($name, value($data))
31+
: xmlns_inheriting_element($name, [value($data)])
3232
)
3333
);
3434
}

src/Xml/Encoding/Internal/Encoder/Builder/element.php

+1-5
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,7 @@
1919
use function VeeWee\Xml\Dom\Builder\attributes;
2020
use function VeeWee\Xml\Dom\Builder\cdata;
2121
use function VeeWee\Xml\Dom\Builder\children as childrenBuilder;
22-
use function VeeWee\Xml\Dom\Builder\element as elementBuilder;
2322
use function VeeWee\Xml\Dom\Builder\escaped_value;
24-
use function VeeWee\Xml\Dom\Builder\namespaced_element as namespacedElementBuilder;
2523
use function VeeWee\Xml\Dom\Builder\xmlns_attributes;
2624

2725
/**
@@ -66,7 +64,5 @@ function element(string $name, array $data): Closure
6664
)),
6765
]);
6866

69-
return $currentNamespace !== null
70-
? namespacedElementBuilder($currentNamespace, $name, ...$children)
71-
: elementBuilder($name, ...$children);
67+
return xmlns_inheriting_element($name, $children, $currentNamespace);
7268
}

src/Xml/Encoding/Internal/Encoder/Builder/parent_node.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
function parent_node(string $name, array|string $data): Closure
2626
{
2727
if (is_string($data)) {
28-
return buildChildren(elementBuilder($name, escaped_value($data)));
28+
return buildChildren(xmlns_inheriting_element($name, [escaped_value($data)]));
2929
}
3030

3131
if (is_node_list($data)) {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace VeeWee\Xml\Encoding\Internal\Encoder\Builder;
6+
7+
use Closure;
8+
use Dom\Element;
9+
use Dom\XMLDocument;
10+
use VeeWee\Xml\Xmlns\Xmlns;
11+
use function VeeWee\Xml\Dom\Builder\element as elementBuilder;
12+
use function VeeWee\Xml\Dom\Builder\namespaced_element as namespacedElementBuilder;
13+
use function VeeWee\Xml\Dom\Locator\Xmlns\closest_unprefixed_xmlns;
14+
use function VeeWee\Xml\Dom\Predicate\is_element;
15+
use function VeeWee\Xml\Dom\Predicate\is_prefixed_node_name;
16+
17+
/**
18+
* This function can create element nodes that inherit the local xmlns namespace of their parent if none is configured.
19+
*
20+
* @param list<Closure(Element): Element> $children
21+
* @return Closure(Element): Element
22+
*/
23+
function xmlns_inheriting_element(string $name, array $children, ?string $localNamespace = null): Closure
24+
{
25+
return function (XMLDocument|Element $parent) use ($localNamespace, $name, $children): Element {
26+
if ($localNamespace === null && is_element($parent) && !is_prefixed_node_name($name)) {
27+
$localNamespace = closest_unprefixed_xmlns($parent);
28+
}
29+
30+
return $localNamespace !== null
31+
? namespacedElementBuilder($localNamespace, $name, ...$children)($parent)
32+
: elementBuilder($name, ...$children)($parent);
33+
};
34+
}

src/bootstrap.php

+3
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
'Xml\Dom\Locator\Node\children' => __DIR__.'/Xml/Dom/Locator/Node/children.php',
4848
'Xml\Dom\Locator\Node\detect_document' => __DIR__.'/Xml/Dom/Locator/Node/detect_document.php',
4949
'Xml\Dom\Locator\Node\value' => __DIR__.'/Xml/Dom/Locator/Node/value.php',
50+
'Xml\Dom\Locator\Xmlns\closest_unprefixed_xmlns' => __DIR__ . '/Xml/Dom/Locator/Xmlns/closest_unprefixed_xmlns.php',
5051
'Xml\Dom\Locator\Xmlns\linked_namespaces' => __DIR__.'/Xml/Dom/Locator/Xmlns/linked_namespaces.php',
5152
'Xml\Dom\Locator\Xmlns\recursive_linked_namespaces' => __DIR__.'/Xml/Dom/Locator/Xmlns/recursive_linked_namespaces.php',
5253
'Xml\Dom\Locator\Xsd\locate_all_xsd_schemas' => __DIR__.'/Xml/Dom/Locator/Xsd/locate_all_xsd_schemas.php',
@@ -79,6 +80,7 @@
7980
'Xml\Dom\Predicate\is_document_element' => __DIR__.'/Xml/Dom/Predicate/is_document_element.php',
8081
'Xml\Dom\Predicate\is_element' => __DIR__.'/Xml/Dom/Predicate/is_element.php',
8182
'Xml\Dom\Predicate\is_non_empty_text' => __DIR__.'/Xml/Dom/Predicate/is_non_empty_text.php',
83+
'Xml\Dom\Predicate\is_prefixed_node_name' => __DIR__.'/Xml/Dom/Predicate/is_prefixed_node_name.php',
8284
'Xml\Dom\Predicate\is_text' => __DIR__.'/Xml/Dom/Predicate/is_text.php',
8385
'Xml\Dom\Predicate\is_whitespace' => __DIR__.'/Xml/Dom/Predicate/is_whitespace.php',
8486
'Xml\Dom\Predicate\is_xmlns_attribute' => __DIR__.'/Xml/Dom/Predicate/is_xmlns_attribute.php',
@@ -107,6 +109,7 @@
107109
'Xml\Encoding\Internal\Encoder\Builder\normalize_data' => __DIR__.'/Xml/Encoding/Internal/Encoder/Builder/normalize_data.php',
108110
'Xml\Encoding\Internal\Encoder\Builder\parent_node' => __DIR__.'/Xml/Encoding/Internal/Encoder/Builder/parent_node.php',
109111
'Xml\Encoding\Internal\Encoder\Builder\root' => __DIR__.'/Xml/Encoding/Internal/Encoder/Builder/root.php',
112+
'Xml\Encoding\Internal\Encoder\Builder\xmlns_inheriting_element' => __DIR__.'/Xml/Encoding/Internal/Encoder/Builder/xmlns_inheriting_element.php',
110113
'Xml\Encoding\Internal\wrap_exception' => __DIR__.'/Xml/Encoding/Internal/wrap_exception.php',
111114
'Xml\Encoding\document_encode' => __DIR__.'/Xml/Encoding/document_encode.php',
112115
'Xml\Encoding\element_decode' => __DIR__.'/Xml/Encoding/element_decode.php',

tests/Xml/Encoding/EncodingTest.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -250,7 +250,7 @@ public static function provideRiskyBidirectionalCases()
250250
yield 'namespaced' => [
251251
'xml' => <<<EOXML
252252
<root xmlns="http://rooty.root" xmlns:test="http://testy.test">
253-
<test:item xmlns="">
253+
<test:item>
254254
<id:int xmlns:id="http://identity.id">1</id:int>
255255
</test:item>
256256
</root>

0 commit comments

Comments
 (0)