Skip to content

Commit

Permalink
Merge pull request #24 from veewee/copy-xmlns
Browse files Browse the repository at this point in the history
Introduce copy_named_xmlns_attributes
  • Loading branch information
veewee committed Dec 17, 2021
2 parents aea7bfd + 1dd815c commit 5f4b53c
Show file tree
Hide file tree
Showing 4 changed files with 191 additions and 0 deletions.
29 changes: 29 additions & 0 deletions docs/dom.md
Original file line number Diff line number Diff line change
Expand Up @@ -860,6 +860,35 @@ $doc->manipulate(
);
```

### Element

Element specific manipulators operate on `DOMElement` instances.

#### copy_named_xmlns_attributes

Makes it possible to copy all names xmlns attributes from one element to an other element.

```php
use VeeWee\Xml\Dom\Document;
use function VeeWee\Xml\Dom\Manipulator\Element\copy_named_xmlns_attributes;

$doc = Document::fromXmlString(
<<<EOXML
<root>
<a xmlns:foo="http://foo" />
<b />
</root>
EOXML
);

$a = $doc->xpath()->querySingle('//a');
$b = $doc->xpath()->querySingle('//b');

copy_named_xmlns_attributes($b, $a);

// > $b will contain xmlns:foo="http://foo"
```

### Node

Node specific manipulators operate on `DOMNode` instances.
Expand Down
23 changes: 23 additions & 0 deletions src/Xml/Dom/Manipulator/Element/copy_named_xmlns_attributes.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?php

declare(strict_types=1);

namespace VeeWee\Xml\Dom\Manipulator\Element;

use DOMElement;
use DOMNameSpaceNode;
use VeeWee\Xml\Exception\RuntimeException;
use function VeeWee\Xml\Dom\Builder\xmlns_attribute;
use function VeeWee\Xml\Dom\Locator\Xmlns\linked_namespaces;

/**
* @throws RuntimeException
*/
function copy_named_xmlns_attributes(DOMElement $target, DOMElement $source): void
{
linked_namespaces($source)->forEach(static function (DOMNameSpaceNode $xmlns) use ($target) {
if ($xmlns->prefix && !$target->hasAttribute($xmlns->nodeName)) {
xmlns_attribute($xmlns->prefix, $xmlns->namespaceURI)($target);
}
});
}
1 change: 1 addition & 0 deletions src/bootstrap.php
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
require_once __DIR__.'/Xml/Dom/Locator/root_namespace.php';
require_once __DIR__.'/Xml/Dom/Manipulator/Attribute/rename.php';
require_once __DIR__.'/Xml/Dom/Manipulator/Document/optimize_namespaces.php';
require_once __DIR__.'/Xml/Dom/Manipulator/Element/copy_named_xmlns_attributes.php';
require_once __DIR__.'/Xml/Dom/Manipulator/Element/rename.php';
require_once __DIR__.'/Xml/Dom/Manipulator/Node/append_external_node.php';
require_once __DIR__.'/Xml/Dom/Manipulator/Node/import_node_deeply.php';
Expand Down
138 changes: 138 additions & 0 deletions tests/Xml/Dom/Manipulator/Element/CopyNamedXmlnsAttributesTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
<?php

declare(strict_types=1);

namespace VeeWee\Tests\Xml\Dom\Manipulator\Element;

use PHPUnit\Framework\TestCase;
use VeeWee\Xml\Dom\Document;
use function VeeWee\Xml\Dom\Manipulator\Element\copy_named_xmlns_attributes;
use function VeeWee\Xml\Dom\Mapper\xml_string;
use function VeeWee\Xml\Dom\Xpath\Configurator\namespaces;

final class CopyNamedXmlnsAttributesTest extends TestCase
{
public function test_it_can_copy_names_xmlns_attributes_in_the_same_doc(): void
{
$doc = Document::fromXmlString(
<<<EOXML
<root>
<a xmlns:foo="http://foo" />
<b />
</root>
EOXML
);

$a = $doc->xpath()->querySingle('//a');
$b = $doc->xpath()->querySingle('//b');

copy_named_xmlns_attributes($b, $a);

static::assertXmlStringEqualsXmlString('<b xmlns:foo="http://foo" />', xml_string()($b));
}

public function test_it_does_not_copy_root_xmlns(): void
{
$doc = Document::fromXmlString(
<<<EOXML
<root>
<a xmlns="http://foo" />
<b />
</root>
EOXML
);

$a = $doc->xpath(namespaces(['a' => "http://foo"]))->querySingle('//a:a');
$b = $doc->xpath()->querySingle('//b');

copy_named_xmlns_attributes($b, $a);

static::assertXmlStringEqualsXmlString('<b />', xml_string()($b));
}

public function test_it_does_not_overwrite_the_same_name(): void
{
$doc = Document::fromXmlString(
<<<EOXML
<root>
<a xmlns:foo="http://foo" />
<b xmlns:foo="http://bar" />
</root>
EOXML
);

$a = $doc->xpath()->querySingle('//a');
$b = $doc->xpath()->querySingle('//b');

copy_named_xmlns_attributes($b, $a);

static::assertXmlStringEqualsXmlString('<b xmlns:foo="http://bar" />', xml_string()($b));
}

public function test_it_can_do_many_namespaces_as_well(): void
{
$doc = Document::fromXmlString(
<<<EOXML
<root>
<a xmlns:foo="http://foo" xmlns:bar="http://bar" xmlns:baz="http://baz" />
<b />
</root>
EOXML
);

$a = $doc->xpath()->querySingle('//a');
$b = $doc->xpath()->querySingle('//b');

copy_named_xmlns_attributes($b, $a);

static::assertXmlStringEqualsXmlString('<b xmlns:foo="http://foo" xmlns:bar="http://bar" xmlns:baz="http://baz" />', xml_string()($b));
}

public function test_it_does_not_include_internally_added_namespaces(): void
{
$doc = Document::fromXmlString(
<<<EOXML
<root>
<a xmlns:foo="http://foo">
<barbaz xmlns:bar="http://bar" xmlns:baz="http://baz" />
</a>
<b />
</root>
EOXML
);

$a = $doc->xpath()->querySingle('//a');
$b = $doc->xpath()->querySingle('//b');

copy_named_xmlns_attributes($b, $a);

static::assertXmlStringEqualsXmlString('<b xmlns:foo="http://foo" />', xml_string()($b));
}

public function test_it_can_copy_cross_docs(): void
{
$doc1 = Document::fromXmlString(
<<<EOXML
<root>
<a xmlns:foo="http://foo">
<barbaz xmlns:bar="http://bar" xmlns:baz="http://baz" />
</a>
</root>
EOXML
);
$doc2 = Document::fromXmlString(
<<<EOXML
<root>
<b />
</root>
EOXML
);

$a = $doc1->xpath()->querySingle('//a');
$b = $doc2->xpath()->querySingle('//b');

copy_named_xmlns_attributes($b, $a);

static::assertXmlStringEqualsXmlString('<b xmlns:foo="http://foo" />', xml_string()($b));
}
}

0 comments on commit 5f4b53c

Please sign in to comment.