Skip to content

Commit ed1677e

Browse files
committed
Add support of document fragments
1 parent 1d49997 commit ed1677e

File tree

6 files changed

+203
-17
lines changed

6 files changed

+203
-17
lines changed

src/DiDom/Document.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,14 @@ public function createCdataSection($data)
164164
return new Element(new DOMCdataSection($data));
165165
}
166166

167+
/**
168+
* @return DocumentFragment
169+
*/
170+
public function createDocumentFragment()
171+
{
172+
return new DocumentFragment($this->document->createDocumentFragment());
173+
}
174+
167175
/**
168176
* Adds a new child at the end of the children.
169177
*

src/DiDom/DocumentFragment.php

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
<?php
2+
3+
namespace DiDom;
4+
5+
use DOMDocumentFragment;
6+
use InvalidArgumentException;
7+
8+
/**
9+
* @property string $tag
10+
*/
11+
class DocumentFragment extends Node
12+
{
13+
/**
14+
* @param DOMDocumentFragment $documentFragment
15+
*/
16+
public function __construct($documentFragment)
17+
{
18+
if ( ! $documentFragment instanceof DOMDocumentFragment) {
19+
throw new InvalidArgumentException(sprintf('Argument 1 passed to %s must be an instance of DOMDocumentFragment, %s given', __METHOD__, (is_object($documentFragment) ? get_class($documentFragment) : gettype($documentFragment))));
20+
}
21+
22+
$this->setNode($documentFragment);
23+
}
24+
25+
/**
26+
* Append raw XML data.
27+
*
28+
* @param string $data
29+
*/
30+
public function appendXml($data)
31+
{
32+
$this->node->appendXML($data);
33+
}
34+
}

src/DiDom/Node.php

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
use DOMCdataSection;
77
use DOMComment;
88
use DOMDocument;
9+
use DOMDocumentFragment;
910
use DOMElement;
1011
use DOMNode;
1112
use DOMText;
@@ -21,14 +22,14 @@ abstract class Node
2122
/**
2223
* The DOM element instance.
2324
*
24-
* @var DOMElement|DOMText|DOMComment|DOMCdataSection
25+
* @var DOMElement|DOMText|DOMComment|DOMCdataSection|DOMDocumentFragment
2526
*/
2627
protected $node;
2728

2829
/**
2930
* Adds a new child at the start of the children.
3031
*
31-
* @param Element|DOMNode|array $nodes The prepended child
32+
* @param Node|DOMNode|array $nodes The prepended child
3233
*
3334
* @return Element|Element[]
3435
*
@@ -67,7 +68,7 @@ public function prependChild($nodes)
6768
/**
6869
* Adds a new child at the end of the children.
6970
*
70-
* @param Element|DOMNode|array $nodes The appended child
71+
* @param Node|DOMNode|array $nodes The appended child
7172
*
7273
* @return Element|Element[]
7374
*
@@ -119,7 +120,7 @@ public function appendChild($nodes)
119120
/**
120121
* Adds a new child before a reference node.
121122
*
122-
* @param Element|DOMNode $node The new node
123+
* @param Node|DOMNode $node The new node
123124
* @param Element|DOMNode|null $referenceNode The reference node
124125
*
125126
* @return Element
@@ -167,7 +168,7 @@ public function insertBefore($node, $referenceNode = null)
167168
/**
168169
* Adds a new child after a reference node.
169170
*
170-
* @param Element|DOMNode $node The new node
171+
* @param Node|DOMNode $node The new node
171172
* @param Element|DOMNode|null $referenceNode The reference node
172173
*
173174
* @return Element
@@ -378,9 +379,10 @@ public function innerXml($delimiter = '')
378379
*
379380
* @param string $html
380381
*
381-
* @return Element
382+
* @return static
382383
*
383384
* @throws InvalidArgumentException if passed argument is not a string
385+
* @throws InvalidSelectorException
384386
*/
385387
public function setInnerHtml($html)
386388
{
@@ -438,7 +440,7 @@ public function text()
438440
*
439441
* @param string $value The new value of the node
440442
*
441-
* @return Element
443+
* @return static
442444
*
443445
* @throws InvalidArgumentException if value is not string
444446
*/
@@ -907,7 +909,7 @@ public function children()
907909
/**
908910
* Removes child from list of children.
909911
*
910-
* @param DOMNode|Element $childNode
912+
* @param Node|DOMNode $childNode
911913
*
912914
* @return Element the node that has been removed
913915
*/
@@ -973,7 +975,7 @@ public function remove()
973975
/**
974976
* Replaces a child.
975977
*
976-
* @param DOMNode|Element $newNode The new node
978+
* @param Node|DOMNode $newNode The new node
977979
* @param bool $clone Clone the node if true, otherwise move it
978980
*
979981
* @return Element The node that has been replaced
@@ -1032,16 +1034,16 @@ public function cloneNode($deep = true)
10321034
/**
10331035
* Sets current node instance.
10341036
*
1035-
* @param DOMElement|DOMText|DOMComment|DOMCdataSection $node
1037+
* @param DOMElement|DOMText|DOMComment|DOMCdataSection|DOMDocumentFragment $node
10361038
*
1037-
* @return Element
1039+
* @return static
10381040
*/
10391041
protected function setNode($node)
10401042
{
1041-
$allowedClasses = ['DOMElement', 'DOMText', 'DOMComment', 'DOMCdataSection'];
1043+
$allowedClasses = ['DOMElement', 'DOMText', 'DOMComment', 'DOMCdataSection', 'DOMDocumentFragment'];
10421044

10431045
if ( ! is_object($node) || ! in_array(get_class($node), $allowedClasses, true)) {
1044-
throw new InvalidArgumentException(sprintf('Argument 1 passed to %s must be an instance of DOMElement, DOMText, DOMComment or DOMCdataSection, %s given', __METHOD__, (is_object($node) ? get_class($node) : gettype($node))));
1046+
throw new InvalidArgumentException(sprintf('Argument 1 passed to %s must be an instance of DOMElement, DOMText, DOMComment, DOMCdataSection or DOMDocumentFragment, %s given', __METHOD__, (is_object($node) ? get_class($node) : gettype($node))));
10451047
}
10461048

10471049
$this->node = $node;
@@ -1052,7 +1054,7 @@ protected function setNode($node)
10521054
/**
10531055
* Returns current node instance.
10541056
*
1055-
* @return DOMElement|DOMText|DOMComment|DOMCdataSection
1057+
* @return DOMElement|DOMText|DOMComment|DOMCdataSection|DOMDocumentFragment
10561058
*/
10571059
public function getNode()
10581060
{

tests/DocumentFragmentTest.php

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<?php
2+
3+
namespace DiDom\Tests;
4+
5+
use DiDom\Document;
6+
use DiDom\DocumentFragment;
7+
use DOMElement;
8+
use InvalidArgumentException;
9+
10+
class DocumentFragmentTest extends TestCase
11+
{
12+
/**
13+
* @expectedException InvalidArgumentException
14+
*/
15+
public function testConstructorWithInvalidNodeType()
16+
{
17+
new DocumentFragment(new DOMElement('span'));
18+
}
19+
20+
public function testAppendXml()
21+
{
22+
$document = new Document();
23+
24+
$documentFragment = $document->createDocumentFragment();
25+
26+
$documentFragment->appendXml('<foo>bar</foo>');
27+
28+
$this->assertEquals('<foo>bar</foo>', $documentFragment->innerXml());
29+
}
30+
}

tests/DocumentTest.php

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ public function testCreateComment()
143143
$this->assertEquals('foo bar baz', $comment->text());
144144
}
145145

146-
public function testCreateCDATASection()
146+
public function testCreateCdataSection()
147147
{
148148
$document = new Document();
149149

@@ -154,6 +154,16 @@ public function testCreateCDATASection()
154154
$this->assertEquals('foo bar baz', $cdataSection->text());
155155
}
156156

157+
public function testCreateDocumentFragment()
158+
{
159+
$document = new Document();
160+
161+
$documentFragment = $document->createDocumentFragment();
162+
163+
$this->assertInstanceOf('DiDom\DocumentFragment', $documentFragment);
164+
$this->assertInstanceOf('DOMDocumentFragment', $documentFragment->getNode());
165+
}
166+
157167
/**
158168
* @expectedException InvalidArgumentException
159169
* @expectedExceptionMessage Argument 1 passed to DiDom\Document::appendChild must be an instance of DiDom\Element or DOMNode, string given

tests/ElementTest.php

Lines changed: 104 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,40 @@ public function testPrependChildWithArrayOfNodes()
179179
}
180180
}
181181

182+
public function testPrependDocumentFragment()
183+
{
184+
$xml = '
185+
<list>
186+
<item>Foo</item>
187+
<item>Bar</item>
188+
<item>Baz</item>
189+
</list>
190+
';
191+
192+
$document = new Document();
193+
194+
$document->loadXml($xml);
195+
196+
$fragmentXml = '
197+
<item>Qux</item>
198+
<item>Quux</item>
199+
<item>Quuz</item>
200+
';
201+
202+
$documentFragment = $document->createDocumentFragment();
203+
204+
$documentFragment->appendXml($fragmentXml);
205+
206+
$document->first('list')->prependChild($documentFragment);
207+
208+
$expectedContent = ['Qux', 'Quux', 'Quuz', 'Foo', 'Bar', 'Baz'];
209+
210+
foreach ($document->find('item') as $index => $childNode) {
211+
$this->assertEquals('item', $childNode->tag);
212+
$this->assertEquals($expectedContent[$index], $childNode->text());
213+
}
214+
}
215+
182216
/**
183217
* @expectedException InvalidArgumentException
184218
*/
@@ -253,6 +287,40 @@ public function testAppendChildWithArray()
253287
}
254288
}
255289

290+
public function testAppendDocumentFragment()
291+
{
292+
$xml = '
293+
<list>
294+
<item>Foo</item>
295+
<item>Bar</item>
296+
<item>Baz</item>
297+
</list>
298+
';
299+
300+
$document = new Document();
301+
302+
$document->loadXml($xml);
303+
304+
$fragmentXml = '
305+
<item>Qux</item>
306+
<item>Quux</item>
307+
<item>Quuz</item>
308+
';
309+
310+
$documentFragment = $document->createDocumentFragment();
311+
312+
$documentFragment->appendXml($fragmentXml);
313+
314+
$document->first('list')->appendChild($documentFragment);
315+
316+
$expectedContent = ['Foo', 'Bar', 'Baz', 'Qux', 'Quux', 'Quuz'];
317+
318+
foreach ($document->find('item') as $index => $childNode) {
319+
$this->assertEquals('item', $childNode->tag);
320+
$this->assertEquals($expectedContent[$index], $childNode->text());
321+
}
322+
}
323+
256324
/**
257325
* @expectedException InvalidArgumentException
258326
*/
@@ -1918,7 +1986,7 @@ public function testReplace()
19181986
$this->assertCount(2, $document->find('li'));
19191987
}
19201988

1921-
public function testReplaceToNewElement()
1989+
public function testReplaceWithNewElement()
19221990
{
19231991
$html = '<ul><li>One</li><li>Two</li><li>Three</li></ul>';
19241992

@@ -1944,7 +2012,7 @@ public function testReplaceToNewElement()
19442012
$anchor->replace($textNode);
19452013
}
19462014

1947-
public function testReplaceWithDifferentDocuments()
2015+
public function testReplaceWithElementFromAnotherDocument()
19482016
{
19492017
$html = '<ul><li>One</li><li>Two</li><li>Three</li></ul>';
19502018

@@ -1957,6 +2025,40 @@ public function testReplaceWithDifferentDocuments()
19572025
$first->replace($third);
19582026
}
19592027

2028+
public function testReplaceWithDocumentFragment()
2029+
{
2030+
$xml = '
2031+
<list>
2032+
<item>Foo</item>
2033+
<item>Bar</item>
2034+
<item>Baz</item>
2035+
</list>
2036+
';
2037+
2038+
$document = new Document();
2039+
2040+
$document->loadXml($xml);
2041+
2042+
$fragmentXml = '
2043+
<item>Qux</item>
2044+
<item>Quux</item>
2045+
<item>Quuz</item>
2046+
';
2047+
2048+
$documentFragment = $document->createDocumentFragment();
2049+
2050+
$documentFragment->appendXml($fragmentXml);
2051+
2052+
$document->first('item:nth-child(2)')->replace($documentFragment);
2053+
2054+
$expectedContent = ['Foo', 'Qux', 'Quux', 'Quuz', 'Baz'];
2055+
2056+
foreach ($document->find('item') as $index => $childNode) {
2057+
$this->assertEquals('item', $childNode->tag);
2058+
$this->assertEquals($expectedContent[$index], $childNode->text());
2059+
}
2060+
}
2061+
19602062
/**
19612063
* @expectedException InvalidArgumentException
19622064
*/

0 commit comments

Comments
 (0)