diff --git a/src/Html.php b/src/Html.php index 5d512ed..d6f207b 100644 --- a/src/Html.php +++ b/src/Html.php @@ -3,6 +3,9 @@ use DOMDocument; use DOMDocumentType; +use DOMElement; +use DOMNode; +use DOMText; class Html { @@ -69,6 +72,39 @@ public function toSnippet(string $id): Snippet { return new SimpleSnippet($id, $imported); } + public function extractAsSnippets(Selector $selector, string $targetId): SnippetList { + $selection = $selector->select($this->dom->documentElement); + if ($selection->isEmpty()) { + throw new TempladoException('Selection result is empty - cannot extract'); + } + + $list = new SnippetList(); + foreach($selection as $item) { + assert($item instanceof DOMNode); + + if ($item instanceof DOMText) { + $list->addSnippet( + new TextSnippet($targetId, $item) + ); + + continue; + } + + if ($item instanceof DOMElement) { + $list->addSnippet( + new SimpleSnippet($targetId, $item) + ); + + continue; + } + + throw new TempladoException('Unspported node type - cannot extract to snippet'); + } + + return $list; + } + + public function asString(Filter $filter = null): string { $content = $this->serializeDomDocument(); $content = (new EmptyElementsFilter())->apply($content); diff --git a/tests/HTMLTest.php b/tests/HTMLTest.php index aa2eb7f..961cc85 100644 --- a/tests/HTMLTest.php +++ b/tests/HTMLTest.php @@ -228,4 +228,96 @@ public function testCanBeConvertedToSnippet(): void { $this->assertInstanceOf(Snippet::class, $snippet); $this->assertEquals('test', $snippet->getTargetId()); } + + /** + * @uses \Templado\Engine\XPathSelector + * @uses \Templado\Engine\Selection + * @uses \Templado\Engine\TempladoException + */ + public function testEmptySelectionOnExtractThrowsException(): void { + $dom = new \DOMDocument(); + $dom->loadXML(''); + + $selector = new XPathSelector('//no-match'); + + $this->expectException(TempladoException::class); + (new Html($dom))->extractAsSnippets($selector, 'some-id'); + } + + /** + * @uses \Templado\Engine\XPathSelector + * @uses \Templado\Engine\SimpleSnippet + * @uses \Templado\Engine\SnippetList + * @uses \Templado\Engine\Selection + */ + public function testSimpleSnippetsCanBeExtracted(): void { + $dom = new \DOMDocument(); + $dom->loadXML(''); + + $selector = new XPathSelector('//a'); + + $list = (new Html($dom))->extractAsSnippets($selector, 'some-id'); + + $testDom = new DOMDocument(); + + $this->assertCount(3, $list); + foreach($list as $snippet) { + $this->assertInstanceOf(SimpleSnippet::class, $snippet); + $this->assertSame('some-id', $snippet->getTargetId()); + + $targetNode = $testDom->createElement('target'); + + $snippet->applyTo($targetNode); + + $this->assertSame('', $testDom->saveXML($targetNode)); + } + } + + /** + * @uses \Templado\Engine\XPathSelector + * @uses \Templado\Engine\SimpleSnippet + * @uses \Templado\Engine\TextSnippet + * @uses \Templado\Engine\SnippetList + * @uses \Templado\Engine\Selection + */ + public function testTextSnippetsCanBeExtracted(): void { + $dom = new \DOMDocument(); + $dom->loadXML('Text'); + + $selector = new XPathSelector('/root/text()'); + + $list = (new Html($dom))->extractAsSnippets($selector, 'some-id'); + + $testDom = new DOMDocument(); + + $this->assertCount(1, $list); + + foreach($list as $snippet) { + $this->assertInstanceOf(TextSnippet::class, $snippet); + $this->assertSame('some-id', $snippet->getTargetId()); + + $targetNode = $testDom->createElement('target'); + + $snippet->applyTo($targetNode); + + $this->assertSame('Text', $testDom->saveXML($targetNode)); + } + } + + /** + * @uses \Templado\Engine\Selection + * @uses \Templado\Engine\TempladoException + * @uses \Templado\Engine\XPathSelector + */ + public function testTryingToExtractNonElementNodeThrowsException(): void { + $dom = new \DOMDocument(); + $dom->loadXML(''); + + $selector = new XPathSelector('//processing-instruction("php")'); + + $this->expectException(TempladoException::class); + (new Html($dom))->extractAsSnippets($selector, 'some-id'); + + } + }