From 4a1dcdf26913f76de10aba15645a5d2ef9cae58b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20M=C3=B6ller?= Date: Wed, 12 Jun 2013 22:55:23 +0200 Subject: [PATCH 01/20] Resolved merge conflicts from commit 83ba3cf --- src/NodeList.php | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/NodeList.php b/src/NodeList.php index 2d1c44c..51a54ab 100644 --- a/src/NodeList.php +++ b/src/NodeList.php @@ -19,10 +19,7 @@ /** * Nodelist for DOM XPath query */ -class NodeList implements - Iterator, - Countable, - ArrayAccess +class NodeList implements Iterator, Countable, ArrayAccess { /** * CSS Selector query From e50702421f4a12f48f7e727baa06367f3a95fc68 Mon Sep 17 00:00:00 2001 From: Thomas Cantonnet Date: Sat, 26 Oct 2013 13:30:16 +0200 Subject: [PATCH 02/20] Review fixes --- src/Document.php | 112 ++++++++++++++++++++++++++++++++---------- test/DocumentTest.php | 50 +++++++++---------- 2 files changed, 110 insertions(+), 52 deletions(-) diff --git a/src/Document.php b/src/Document.php index 4b4ed97..b4f4ce1 100644 --- a/src/Document.php +++ b/src/Document.php @@ -22,9 +22,16 @@ class Document /**#@+ * Document types */ - const DOC_XML = 'DOC_XML'; - const DOC_HTML = 'DOC_HTML'; - const DOC_XHTML = 'DOC_XHTML'; + const DOC_HTML = 'DOC_HTML'; + const DOC_XHTML = 'DOC_XHTML'; + const DOC_XML = 'DOC_XML'; + /**#@-*/ + + /**#@+ + * Query types + */ + const QUERY_XPATH = 'QUERY_XPATH'; + const QUERY_CSS = 'QUERY_CSS'; /**#@-*/ /** @@ -65,6 +72,7 @@ class Document /** * Constructor + * * @param string|null $document * @param string|null $encoding */ @@ -75,7 +83,8 @@ public function __construct($document = null, $encoding = null) } /** - * Get raw document + * Get raw set document + * * @return null|string */ public function getStringDocument() @@ -85,10 +94,11 @@ public function getStringDocument() /** * Set raw document - * @param string|null $document - * @param string|null $forcedType Type for the provided document (see constants) - * @param string|null $forcedEncoding Encoding for the provided document - * @return Document + * + * @param null|string $document + * @param null|string $forcedType Type for the provided document (see constants) + * @param null|string $forcedEncoding Encoding for the provided document + * @return self */ public function setStringDocument($document, $forcedType = null, $forcedEncoding = null) { @@ -112,15 +122,27 @@ public function setStringDocument($document, $forcedType = null, $forcedEncoding $this->setType($forcedType ?: (!empty($document) ? $type : null)); $this->setEncoding($forcedEncoding); + $this->setErrors(array()); return $this; } + /** + * Get raw document type + * + * @return null|string + */ public function getType() { return $this->type; } + /** + * Set raw document type + * + * @param string $type + * @return self + */ protected function setType($type) { $this->type = $type; @@ -128,6 +150,12 @@ protected function setType($type) return $this; } + /** + * Get DOMDocument generated from set raw document + * + * @return null|string + * @throws Exception\RuntimeException + */ public function getDomDocument() { if (null === ($stringDocument = $this->getStringDocument())) { @@ -135,12 +163,18 @@ public function getDomDocument() } if (null === $this->domDocument) { - $this->domDocument = $this->getDomFromString($stringDocument); + $this->domDocument = $this->getDomDocumentFromString($stringDocument); } return $this->domDocument; } + /** + * Set DOMDocument + * + * @param DOMDocument $domDocument + * @return self + */ protected function setDomDocument(DOMDocument $domDocument) { $this->domDocument = $domDocument; @@ -148,11 +182,22 @@ protected function setDomDocument(DOMDocument $domDocument) return $this; } + /** + * Get set document encoding + * + * @return null|string + */ public function getEncoding() { return $this->encoding; } + /** + * Set raw document encoding for DOMDocument generation + * + * @param null|string $encoding + * @return self + */ public function setEncoding($encoding) { $this->encoding = $encoding; @@ -160,11 +205,22 @@ public function setEncoding($encoding) return $this->encoding; } + /** + * Get DOMDocument generation errors + * + * @return array + */ public function getErrors() { return $this->errors; } + /** + * Set document errors from DOMDocument generation + * + * @param array $errors + * @return self + */ protected function setErrors($errors) { $this->errors = $errors; @@ -172,7 +228,13 @@ protected function setErrors($errors) return $this; } - protected function getDomFromString($stringDocument) + /** + * Get DOMDocument from set raw document + * + * @return DOMDocument + * @throws Exception\RuntimeException + */ + protected function getDomDocumentFromString($stringDocument) { libxml_use_internal_errors(true); libxml_disable_entity_loader(true); @@ -216,31 +278,27 @@ protected function getDomFromString($stringDocument) } /** - * Perform a CSS selector query + * Perform a query on generated DOMDocument * * @param string $query - * @return NodeList - */ - public function queryCss($query) - { - $xpathQuery = Css2Xpath::transform($query); - return $this->queryXpath($xpathQuery, $query); - } - - /** - * Perform an XPath query - * - * @param string|array $xpathQuery - * @param string|null $query CSS selector query + * @param string $queryType * @throws Exception\RuntimeException * @return NodeList */ - public function queryXpath($xpathQuery, $query = null) + public function query($query, $queryType = self::QUERY_XPATH) { - $domDoc = $this->getDomDocument(); + $domDoc = $this->getDomDocument(); + $xpathQuery = $query; + $cssQuery = null; + + if ($queryType === static::QUERY_CSS) { + $xpathQuery = Css2Xpath::transform($query); + $cssQuery = $query; + } + $nodeList = $this->getNodeList($domDoc, $xpathQuery); - return new NodeList($query, $xpathQuery, $domDoc, $nodeList); + return new NodeList($cssQuery, $xpathQuery, $domDoc, $nodeList); } /** diff --git a/test/DocumentTest.php b/test/DocumentTest.php index e46f6f1..f7b772e 100644 --- a/test/DocumentTest.php +++ b/test/DocumentTest.php @@ -119,7 +119,7 @@ public function testDocumentTypeShouldBeAutomaticallyDiscovered() public function testQueryingWithoutRegisteringDocumentShouldThrowException() { $this->setExpectedException('\Zend\Dom\Exception\RuntimeException', 'no document'); - $this->document->queryCss('.foo'); + $this->document->query('.foo', Document::QUERY_CSS); } public function testQueryingInvalidDocumentShouldThrowException() @@ -127,7 +127,7 @@ public function testQueryingInvalidDocumentShouldThrowException() set_error_handler(array($this, 'handleError')); $this->document->setStringDocument('some bogus string', Document::DOC_XML); try { - $this->document->queryCss('.foo'); + $this->document->query('.foo', Document::QUERY_CSS); restore_error_handler(); $this->fail('Querying invalid document should throw exception'); } catch (DOMException $e) { @@ -174,14 +174,14 @@ public function testSettingNewEmptyDocumentsResetsAllPreviousDocumentAttributes( public function testQueryShouldReturnResultObject() { $this->loadHtml(); - $test = $this->document->queryCss('.foo'); + $test = $this->document->query('.foo', Document::QUERY_CSS); $this->assertTrue($test instanceof NodeList); } public function testResultShouldIndicateNumberOfFoundNodes() { $this->loadHtml(); - $result = $this->document->queryCss('.foo'); + $result = $this->document->query('.foo', Document::QUERY_CSS); $message = 'Xpath: ' . $result->getXpathQuery() . "\n"; $this->assertEquals(3, count($result), $message); } @@ -189,7 +189,7 @@ public function testResultShouldIndicateNumberOfFoundNodes() public function testResultShouldAllowIteratingOverFoundNodes() { $this->loadHtml(); - $result = $this->document->queryCss('.foo'); + $result = $this->document->query('.foo', Document::QUERY_CSS); $this->assertEquals(3, count($result)); foreach ($result as $node) { $this->assertTrue($node instanceof \DOMNode, var_export($result, 1)); @@ -199,35 +199,35 @@ public function testResultShouldAllowIteratingOverFoundNodes() public function testQueryShouldFindNodesWithMultipleClasses() { $this->loadHtml(); - $result = $this->document->queryCss('.footerblock .last'); + $result = $this->document->query('.footerblock .last', Document::QUERY_CSS); $this->assertEquals(1, count($result), $result->getXpathQuery()); } public function testQueryShouldFindNodesWithArbitraryAttributeSelectorsExactly() { $this->loadHtml(); - $result = $this->document->queryCss('div[dojoType="FilteringSelect"]'); + $result = $this->document->query('div[dojoType="FilteringSelect"]', Document::QUERY_CSS); $this->assertEquals(1, count($result), $result->getXpathQuery()); } public function testQueryShouldFindNodesWithArbitraryAttributeSelectorsAsDiscreteWords() { $this->loadHtml(); - $result = $this->document->queryCss('li[dojoType~="bar"]'); + $result = $this->document->query('li[dojoType~="bar"]', Document::QUERY_CSS); $this->assertEquals(2, count($result), $result->getXpathQuery()); } public function testQueryShouldFindNodesWithArbitraryAttributeSelectorsAndAttributeValue() { $this->loadHtml(); - $result = $this->document->queryCss('li[dojoType*="bar"]'); + $result = $this->document->query('li[dojoType*="bar"]', Document::QUERY_CSS); $this->assertEquals(2, count($result), $result->getXpathQuery()); } public function testQueryXpathShouldAllowQueryingArbitraryUsingXpath() { $this->loadHtml(); - $result = $this->document->queryXpath('//li[contains(@dojotype, "bar")]'); + $result = $this->document->query('//li[contains(@dojotype, "bar")]'); $this->assertEquals(2, count($result), $result->getXpathQuery()); } @@ -235,7 +235,7 @@ public function testXpathPhpFunctionsShouldBeDisabledByDefault() { $this->loadHtml(); try { - $this->document->queryXpath('//meta[php:functionString("strtolower", @http-equiv) = "content-type"]'); + $this->document->query('//meta[php:functionString("strtolower", @http-equiv) = "content-type"]'); } catch (\Exception $e) { return; } @@ -246,7 +246,7 @@ public function testXpathPhpFunctionsShouldBeEnabledWithoutParameter() { $this->loadHtml(); $this->document->registerXpathPhpFunctions(); - $result = $this->document->queryXpath('//meta[php:functionString("strtolower", @http-equiv) = "content-type"]'); + $result = $this->document->query('//meta[php:functionString("strtolower", @http-equiv) = "content-type"]'); $this->assertEquals( 'content-type', strtolower($result->current()->getAttribute('http-equiv')), @@ -259,7 +259,7 @@ public function testXpathPhpFunctionsShouldBeNotCalledWhenSpecifiedFunction() $this->loadHtml(); try { $this->document->registerXpathPhpFunctions('stripos'); - $this->document->queryXpath('//meta[php:functionString("strtolower", @http-equiv) = "content-type"]'); + $this->document->query('//meta[php:functionString("strtolower", @http-equiv) = "content-type"]'); } catch (\Exception $e) { // $e->getMessage() - Not allowed to call handler 'strtolower() return; @@ -274,7 +274,7 @@ public function testLoadingDocumentWithErrorsShouldNotRaisePhpErrors() { $file = file_get_contents(__DIR__ . '/_files/bad-sample.html'); $this->document->setStringDocument($file); - $this->document->queryCss('p'); + $this->document->query('p', Document::QUERY_CSS); $errors = $this->document->getErrors(); $this->assertTrue(is_array($errors)); $this->assertTrue(0 < count($errors)); @@ -300,11 +300,11 @@ public function testCssSelectorShouldFindNodesWhenMatchingMultipleAttributes() EOF; $this->document->setStringDocument($html); - $results = $this->document->queryCss('input[type="hidden"][value="1"]'); + $results = $this->document->query('input[type="hidden"][value="1"]', Document::QUERY_CSS); $this->assertEquals(2, count($results), $results->getXpathQuery()); - $results = $this->document->queryCss('input[value="1"][type~="hidden"]'); + $results = $this->document->query('input[value="1"][type~="hidden"]', Document::QUERY_CSS); $this->assertEquals(2, count($results), $results->getXpathQuery()); - $results = $this->document->queryCss('input[type="hidden"][value="0"]'); + $results = $this->document->query('input[type="hidden"][value="0"]', Document::QUERY_CSS); $this->assertEquals(1, count($results)); } @@ -341,7 +341,7 @@ public function testAllowsSpecifyingEncodingViaSetter() public function testSpecifyingEncodingSetsEncodingOnDomDocument() { $this->document->setStringDocument($this->getHtml(), 'utf-8'); - $test = $this->document->queryCss('.foo'); + $test = $this->document->query('.foo', Document::QUERY_CSS); $this->assertInstanceof('\\Zend\\Dom\\NodeList', $test); $doc = $test->getDocument(); $this->assertInstanceof('\\DOMDocument', $doc); @@ -361,7 +361,7 @@ public function testXhtmlDocumentWithXmlDeclaration() EOB; $this->document->setStringDocument($xhtmlWithXmlDecl, 'utf-8'); - $this->assertEquals(1, $this->document->queryCss('//p')->count()); + $this->assertEquals(1, $this->document->query('//p', Document::QUERY_CSS)->count()); } /** @@ -384,7 +384,7 @@ public function testXhtmlDocumentWithXmlAndDoctypeDeclaration() EOB; $this->document->setStringDocument($xhtmlWithXmlDecl, 'utf-8'); - $this->assertEquals(1, $this->document->queryCss('//p')->count()); + $this->assertEquals(1, $this->document->query('//p', Document::QUERY_CSS)->count()); } public function testLoadingXmlContainingDoctypeShouldFailToPreventXxeAndXeeAttacks() @@ -398,13 +398,13 @@ public function testLoadingXmlContainingDoctypeShouldFailToPreventXxeAndXeeAttac XML; $this->document->setStringDocument($xml); $this->setExpectedException("\Zend\Dom\Exception\RuntimeException"); - $this->document->queryXpath('/'); + $this->document->query('/'); } public function testOffsetExists() { $this->loadHtml(); - $results = $this->document->queryCss('input'); + $results = $this->document->query('input', Document::QUERY_CSS); $this->assertEquals(3, $results->count()); $this->assertFalse($results->offsetExists(3)); @@ -414,7 +414,7 @@ public function testOffsetExists() public function testOffsetGet() { $this->loadHtml(); - $results = $this->document->queryCss('input'); + $results = $this->document->query('input', Document::QUERY_CSS); $this->assertEquals(3, $results->count()); $this->assertEquals('login', $results[2]->getAttribute('id')); @@ -426,7 +426,7 @@ public function testOffsetGet() public function testOffsetSet() { $this->loadHtml(); - $results = $this->document->queryCss('input'); + $results = $this->document->query('input', Document::QUERY_CSS); $this->assertEquals(3, $results->count()); $results[0] = ''; @@ -439,7 +439,7 @@ public function testOffsetSet() public function testOffsetUnset() { $this->loadHtml(); - $results = $this->document->queryCss('input'); + $results = $this->document->query('input', Document::QUERY_CSS); $this->assertEquals(3, $results->count()); unset($results[2]); From 877ed36ab00de83b0d67c4cd4677a83e7d39b3c9 Mon Sep 17 00:00:00 2001 From: Steve Rhoades Date: Sat, 26 Oct 2013 11:24:59 -0700 Subject: [PATCH 03/20] fixes zendframework/zf2#5310 updated QueryTest and sample html file --- test/QueryTest.php | 13 +++++++++++++ test/_files/sample.xhtml | 2 +- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/test/QueryTest.php b/test/QueryTest.php index 84803e1..86150a0 100644 --- a/test/QueryTest.php +++ b/test/QueryTest.php @@ -396,4 +396,17 @@ public function testOffsetUnset() unset($results[2]); } + + /** + * @group ZF-5310 + */ + public function testCssSelectorShouldFindNodesWhenMatchingAttributeWithDot() + { + $this->loadHtml(); + $results = $this->query->execute('a[href="http://www.about.com"]'); + + $this->assertEquals(1, $results->count()); + $this->assertEquals('About', $results[0]->nodeValue); + + } } diff --git a/test/_files/sample.xhtml b/test/_files/sample.xhtml index c250c54..9e2432d 100644 --- a/test/_files/sample.xhtml +++ b/test/_files/sample.xhtml @@ -16,7 +16,7 @@ From 0e1dbfb7bf3b78df0d956cbf48caed62d6dd7ec1 Mon Sep 17 00:00:00 2001 From: Steve Rhoades Date: Sat, 26 Oct 2013 18:51:07 -0700 Subject: [PATCH 04/20] make test method name more clear --- test/QueryTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/QueryTest.php b/test/QueryTest.php index 86150a0..b67b93c 100644 --- a/test/QueryTest.php +++ b/test/QueryTest.php @@ -400,13 +400,13 @@ public function testOffsetUnset() /** * @group ZF-5310 */ - public function testCssSelectorShouldFindNodesWhenMatchingAttributeWithDot() + public function testCssSelectorShouldFindNodesWhenMatchingAttributeValueWithDot() { $this->loadHtml(); $results = $this->query->execute('a[href="http://www.about.com"]'); $this->assertEquals(1, $results->count()); $this->assertEquals('About', $results[0]->nodeValue); - + } } From 5555a589666c18fce68341f61d55f35c8cd2745e Mon Sep 17 00:00:00 2001 From: Thomas Cantonnet Date: Wed, 30 Oct 2013 18:57:36 +0100 Subject: [PATCH 05/20] Add Query class & deprecated NodeList in favor of Document\NodeList --- src/Css2Xpath.php | 2 + src/Document.php | 54 ++++------ src/Document/NodeList.php | 160 ++++++++++++++++++++++++++++ src/Document/Query.php | 212 ++++++++++++++++++++++++++++++++++++++ src/NodeList.php | 2 + src/Query.php | 2 +- test/Css2XpathTest.php | 36 +++---- test/DocumentTest.php | 144 +++++++++++--------------- test/NodeListTest.php | 6 +- 9 files changed, 480 insertions(+), 138 deletions(-) create mode 100644 src/Document/NodeList.php create mode 100644 src/Document/Query.php diff --git a/src/Css2Xpath.php b/src/Css2Xpath.php index c2acf15..0321989 100644 --- a/src/Css2Xpath.php +++ b/src/Css2Xpath.php @@ -11,6 +11,8 @@ /** * Transform CSS selectors to XPath + * @deprecated + * @see \Zend\Dom\Document\Query */ class Css2Xpath { diff --git a/src/Document.php b/src/Document.php index b4f4ce1..040322e 100644 --- a/src/Document.php +++ b/src/Document.php @@ -11,6 +11,7 @@ use DOMDocument; use DOMXPath; +use Zend\Dom\Document; use Zend\Dom\Exception; use Zend\Stdlib\ErrorHandler; @@ -27,13 +28,6 @@ class Document const DOC_XML = 'DOC_XML'; /**#@-*/ - /**#@+ - * Query types - */ - const QUERY_XPATH = 'QUERY_XPATH'; - const QUERY_CSS = 'QUERY_CSS'; - /**#@-*/ - /** * Raw document * @var string @@ -73,19 +67,19 @@ class Document /** * Constructor * - * @param string|null $document - * @param string|null $encoding + * @param string|null $document String containing the document + * @param string|null $type Force the document to be of a certain type, bypassing setStringDocument's detection + * @param string|null $encoding Encoding for the document (used for DOMDocument generation) */ - public function __construct($document = null, $encoding = null) + public function __construct($document = null, $type = null, $encoding = null) { - $this->setStringDocument($document); - $this->setEncoding($encoding); + $this->setStringDocument($document, $type, $encoding); } /** * Get raw set document * - * @return null|string + * @return string|null */ public function getStringDocument() { @@ -95,12 +89,12 @@ public function getStringDocument() /** * Set raw document * - * @param null|string $document - * @param null|string $forcedType Type for the provided document (see constants) - * @param null|string $forcedEncoding Encoding for the provided document + * @param string|null $document + * @param string|null $forcedType Type for the provided document (see constants) + * @param string|null $forcedEncoding Encoding for the provided document * @return self */ - public function setStringDocument($document, $forcedType = null, $forcedEncoding = null) + protected function setStringDocument($document, $forcedType = null, $forcedEncoding = null) { $type = static::DOC_HTML; if (strstr($document, 'DTD XHTML')) { @@ -130,7 +124,7 @@ public function setStringDocument($document, $forcedType = null, $forcedEncoding /** * Get raw document type * - * @return null|string + * @return string|null */ public function getType() { @@ -153,7 +147,7 @@ protected function setType($type) /** * Get DOMDocument generated from set raw document * - * @return null|string + * @return string|null * @throws Exception\RuntimeException */ public function getDomDocument() @@ -185,7 +179,7 @@ protected function setDomDocument(DOMDocument $domDocument) /** * Get set document encoding * - * @return null|string + * @return string|null */ public function getEncoding() { @@ -195,7 +189,7 @@ public function getEncoding() /** * Set raw document encoding for DOMDocument generation * - * @param null|string $encoding + * @param string|null $encoding * @return self */ public function setEncoding($encoding) @@ -280,25 +274,17 @@ protected function getDomDocumentFromString($stringDocument) /** * Perform a query on generated DOMDocument * - * @param string $query + * @param Document\Query $query * @param string $queryType * @throws Exception\RuntimeException * @return NodeList */ - public function query($query, $queryType = self::QUERY_XPATH) + public function execute(Document\Query $query) { - $domDoc = $this->getDomDocument(); - $xpathQuery = $query; - $cssQuery = null; - - if ($queryType === static::QUERY_CSS) { - $xpathQuery = Css2Xpath::transform($query); - $cssQuery = $query; - } - - $nodeList = $this->getNodeList($domDoc, $xpathQuery); + $domDoc = $this->getDomDocument(); + $nodeList = $this->getNodeList($domDoc, $query->getContent()); - return new NodeList($cssQuery, $xpathQuery, $domDoc, $nodeList); + return new Document\NodeList($nodeList); } /** diff --git a/src/Document/NodeList.php b/src/Document/NodeList.php new file mode 100644 index 0000000..8c09f58 --- /dev/null +++ b/src/Document/NodeList.php @@ -0,0 +1,160 @@ +list = $list; + } + + /** + * Iterator: rewind to first element + * + * @return DOMNode + */ + public function rewind() + { + $this->position = 0; + + return $this->list->item(0); + } + + /** + * Iterator: is current position valid? + * + * @return bool + */ + public function valid() + { + if (in_array($this->position, range(0, $this->list->length - 1)) && $this->list->length > 0) { + return true; + } + + return false; + } + + /** + * Iterator: return current element + * + * @return DOMNode + */ + public function current() + { + return $this->list->item($this->position); + } + + /** + * Iterator: return key of current element + * + * @return int + */ + public function key() + { + return $this->position; + } + + /** + * Iterator: move to next element + * + * @return DOMNode + */ + public function next() + { + ++$this->position; + + return $this->list->item($this->position); + } + + /** + * Countable: get count + * + * @return int + */ + public function count() + { + return $this->list->length; + } + + /** + * ArrayAccess: offset exists + * + * @param int $key + * @return bool + */ + public function offsetExists($key) + { + if (in_array($key, range(0, $this->list->length - 1)) && $this->list->length > 0) { + return true; + } + return false; + } + + /** + * ArrayAccess: get offset + * + * @param int $key + * @return mixed + */ + public function offsetGet($key) + { + return $this->list->item($key); + } + + /** + * ArrayAccess: set offset + * + * @param mixed $key + * @param mixed $value + * @throws Exception\BadMethodCallException when attemptingn to write to a read-only item + */ + public function offsetSet($key, $value) + { + throw new Exception\BadMethodCallException('Attempting to write to a read-only list'); + } + + /** + * ArrayAccess: unset offset + * + * @param mixed $key + * @throws Exception\BadMethodCallException when attemptingn to unset a read-only item + */ + public function offsetUnset($key) + { + throw new Exception\BadMethodCallException('Attempting to unset on a read-only list'); + } +} diff --git a/src/Document/Query.php b/src/Document/Query.php new file mode 100644 index 0000000..60bc84a --- /dev/null +++ b/src/Document/Query.php @@ -0,0 +1,212 @@ +setContent($content); + $this->setType($type); + } + + /** + * Get query content + * + * @return string|null + */ + public function getContent() + { + return $this->content; + } + + /** + * Set query content + * + * @param string $content + * @return self + */ + public function setContent($content) + { + $this->content = $content; + + return $this; + } + + /** + * Get query type + * + * @return string|null + */ + public function getType() + { + return $this->type; + } + + /** + * Set query type + * + * @param string $type + * @return self + */ + public function setType($type) + { + switch ($type) { + case static::TYPE_CSS: + case static::TYPE_XPATH: + $this->type = $type; + break; + default: + break; + } + + return $this; + } + + /** + * Transform CSS expression to XPath + * + * @param string $path + * @return string + */ + public static function cssToXpath($path) + { + $path = (string) $path; + if (strstr($path, ',')) { + $paths = explode(',', $path); + $expressions = array(); + foreach ($paths as $path) { + $xpath = static::cssToXpath(trim($path)); + if (is_string($xpath)) { + $expressions[] = $xpath; + } elseif (is_array($xpath)) { + $expressions = array_merge($expressions, $xpath); + } + } + return implode('|', $expressions); + } + + $paths = array('//'); + $path = preg_replace('|\s+>\s+|', '>', $path); + $segments = preg_split('/\s+/', $path); + foreach ($segments as $key => $segment) { + $pathSegment = static::_tokenize($segment); + if (0 == $key) { + if (0 === strpos($pathSegment, '[contains(')) { + $paths[0] .= '*' . ltrim($pathSegment, '*'); + } else { + $paths[0] .= $pathSegment; + } + continue; + } + if (0 === strpos($pathSegment, '[contains(')) { + foreach ($paths as $pathKey => $xpath) { + $paths[$pathKey] .= '//*' . ltrim($pathSegment, '*'); + $paths[] = $xpath . $pathSegment; + } + } else { + foreach ($paths as $pathKey => $xpath) { + $paths[$pathKey] .= '//' . $pathSegment; + } + } + } + + if (1 == count($paths)) { + return $paths[0]; + } + return implode('|', $paths); + } + + /** + * Tokenize CSS expressions to XPath + * + * @param string $expression + * @return string + */ + protected static function _tokenize($expression) + { + // Child selectors + $expression = str_replace('>', '/', $expression); + + // IDs + $expression = preg_replace('|#([a-z][a-z0-9_-]*)|i', '[@id=\'$1\']', $expression); + $expression = preg_replace('|(?assertTrue(is_string($test)); } @@ -34,7 +34,7 @@ public function testTransformShouldReturnStringByDefault() */ public function testTransformShouldReturnMultiplePathsWhenExpressionContainsCommas() { - $test = Css2Xpath::transform('#foo, #bar'); + $test = Query::cssToXpath('#foo, #bar'); $this->assertTrue(is_string($test)); $this->assertContains('|', $test); $this->assertEquals(2, count(explode('|', $test))); @@ -42,19 +42,19 @@ public function testTransformShouldReturnMultiplePathsWhenExpressionContainsComm public function testTransformShouldRecognizeHashSymbolAsId() { - $test = Css2Xpath::transform('#foo'); + $test = Query::cssToXpath('#foo'); $this->assertEquals("//*[@id='foo']", $test); } public function testTransformShouldRecognizeDotSymbolAsClass() { - $test = Css2Xpath::transform('.foo'); + $test = Query::cssToXpath('.foo'); $this->assertEquals("//*[contains(concat(' ', normalize-space(@class), ' '), ' foo ')]", $test); } public function testTransformShouldAssumeSpacesToIndicateRelativeXpathQueries() { - $test = Css2Xpath::transform('div#foo .bar'); + $test = Query::cssToXpath('div#foo .bar'); $this->assertContains('|', $test); $expected = array( "//div[@id='foo']//*[contains(concat(' ', normalize-space(@class), ' '), ' bar ')]", @@ -67,7 +67,7 @@ public function testTransformShouldAssumeSpacesToIndicateRelativeXpathQueries() public function testTransformShouldWriteChildSelectorsAsAbsoluteXpathRelations() { - $test = Css2Xpath::transform('div#foo>span'); + $test = Query::cssToXpath('div#foo>span'); $this->assertEquals("//div[@id='foo']/span", $test); } @@ -76,7 +76,7 @@ public function testTransformShouldWriteChildSelectorsAsAbsoluteXpathRelations() */ public function testMultipleComplexCssSpecificationShouldTransformToExpectedXpath() { - $test = Css2Xpath::transform('div#foo span.bar, #bar li.baz a'); + $test = Query::cssToXpath('div#foo span.bar, #bar li.baz a'); $this->assertTrue(is_string($test)); $this->assertContains('|', $test); $actual = explode('|', $test); @@ -92,7 +92,7 @@ public function testMultipleComplexCssSpecificationShouldTransformToExpectedXpat public function testClassNotationWithoutSpecifiedTagShouldResultInMultipleQueries() { - $test = Css2Xpath::transform('div.foo .bar a .baz span'); + $test = Query::cssToXpath('div.foo .bar a .baz span'); $this->assertContains('|', $test); $segments = array( "//div[contains(concat(' ', normalize-space(@class), ' '), ' foo ')]//*[contains(concat(' ', normalize-space(@class), ' '), ' bar ')]//a//*[contains(concat(' ', normalize-space(@class), ' '), ' baz ')]//span", @@ -107,25 +107,25 @@ public function testClassNotationWithoutSpecifiedTagShouldResultInMultipleQuerie public function testShouldAllowEqualitySelectionOfArbitraryAttributes() { - $test = Css2Xpath::transform('div[foo="bar"]'); + $test = Query::cssToXpath('div[foo="bar"]'); $this->assertEquals("//div[@foo='bar']", $test); } public function testShouldCastAttributeNamesToLowerCase() { - $test = Css2Xpath::transform('div[dojoType="bar"]'); + $test = Query::cssToXpath('div[dojoType="bar"]'); $this->assertEquals("//div[@dojotype='bar']", $test); } public function testShouldAllowContentSubSelectionOfArbitraryAttributes() { - $test = Css2Xpath::transform('div[foo~="bar"]'); + $test = Query::cssToXpath('div[foo~="bar"]'); $this->assertEquals("//div[contains(concat(' ', normalize-space(@foo), ' '), ' bar ')]", $test); } public function testShouldAllowContentMatchingOfArbitraryAttributes() { - $test = Css2Xpath::transform('div[foo*="bar"]'); + $test = Query::cssToXpath('div[foo*="bar"]'); $this->assertEquals("//div[contains(@foo, 'bar')]", $test); } @@ -134,7 +134,7 @@ public function testShouldAllowContentMatchingOfArbitraryAttributes() */ public function testShouldAllowMatchingOfAttributeValues() { - $test = Css2Xpath::transform('tag#id @attribute'); + $test = Query::cssToXpath('tag#id @attribute'); $this->assertEquals("//tag[@id='id']//@attribute", $test); } @@ -143,7 +143,7 @@ public function testShouldAllowMatchingOfAttributeValues() */ public function testShouldAllowWhitespaceInDescendentSelectorExpressions() { - $test = Css2Xpath::transform('child > leaf'); + $test = Query::cssToXpath('child > leaf'); $this->assertEquals("//child/leaf", $test); } @@ -152,7 +152,7 @@ public function testShouldAllowWhitespaceInDescendentSelectorExpressions() */ public function testIdSelectorWithAttribute() { - $test = Css2Xpath::transform('#id[attribute="value"]'); + $test = Query::cssToXpath('#id[attribute="value"]'); $this->assertEquals("//*[@id='id'][@attribute='value']", $test); } @@ -161,7 +161,7 @@ public function testIdSelectorWithAttribute() */ public function testIdSelectorWithLeadingAsterix() { - $test = Css2Xpath::transform('*#id'); + $test = Query::cssToXpath('*#id'); $this->assertEquals("//*[@id='id']", $test); } } diff --git a/test/DocumentTest.php b/test/DocumentTest.php index f7b772e..0790994 100644 --- a/test/DocumentTest.php +++ b/test/DocumentTest.php @@ -44,7 +44,7 @@ public function getHtml() public function loadHtml() { - $this->document->setStringDocument($this->getHtml()); + $this->document = new Document($this->getHtml()); } public function handleError($msg, $code = 0) @@ -82,13 +82,6 @@ public function testDocShouldBeNullByEmptyStringConstructor() $this->assertNull($this->document->getStringDocument()); } - public function testDocShouldBeNullByEmptyStringSet() - { - $emptyStr = ''; - $this->document->setStringDocument($emptyStr); - $this->assertNull($this->document->getStringDocument()); - } - public function testDocTypeShouldBeNullByDefault() { $this->assertNull($this->document->getType()); @@ -110,24 +103,24 @@ public function testDocumentTypeShouldBeAutomaticallyDiscovered() { $this->loadHtml(); $this->assertEquals(Document::DOC_XHTML, $this->document->getType()); - $this->document->setStringDocument(''); + $this->document = new Document(''); $this->assertEquals(Document::DOC_XML, $this->document->getType()); - $this->document->setStringDocument(''); + $this->document = new Document(''); $this->assertEquals(Document::DOC_HTML, $this->document->getType()); } public function testQueryingWithoutRegisteringDocumentShouldThrowException() { $this->setExpectedException('\Zend\Dom\Exception\RuntimeException', 'no document'); - $this->document->query('.foo', Document::QUERY_CSS); + $this->document->execute(new Document\Query('.foo', Document\Query::TYPE_CSS)); } public function testQueryingInvalidDocumentShouldThrowException() { set_error_handler(array($this, 'handleError')); - $this->document->setStringDocument('some bogus string', Document::DOC_XML); + $this->document = new Document('some bogus string', Document::DOC_XML); try { - $this->document->query('.foo', Document::QUERY_CSS); + $this->document->execute(new Document\Query('.foo', Document\Query::TYPE_CSS)); restore_error_handler(); $this->fail('Querying invalid document should throw exception'); } catch (DOMException $e) { @@ -149,47 +142,26 @@ public function testgetDomMethodShouldReturnDomDocumentWithStringDocumentSetFrom $this->assertTrue($this->document->getDomDocument() instanceof \DOMDocument); } - public function testSettingNewDocumentResetsAllPreviousDocumentAttributes() - { - $document = new Document(); - $document->setStringDocument($this->getHtml(), Document::DOC_XHTML, 'ISO-8859-1'); - $oldDocument = clone $document; - $document->setStringDocument('

test

', Document::DOC_HTML, 'UTF-8'); - $this->assertNotEquals($document->getStringDocument(), $oldDocument->getStringDocument()); - $this->assertNotEquals($document->getType(), $oldDocument->getType()); - $this->assertNotEquals($document->getEncoding(), $oldDocument->getEncoding()); - } - - public function testSettingNewEmptyDocumentsResetsAllPreviousDocumentAttributes() - { - $document = new Document(); - $document->setStringDocument($this->getHtml(), Document::DOC_XHTML, 'ISO-8859-1'); - $oldDocument = clone $document; - $document->setStringDocument(null, Document::DOC_HTML, 'UTF-8'); - $this->assertNotEquals($document->getStringDocument(), $oldDocument->getStringDocument()); - $this->assertNotEquals($document->getType(), $oldDocument->getType()); - $this->assertNotEquals($document->getEncoding(), $oldDocument->getEncoding()); - } - public function testQueryShouldReturnResultObject() { $this->loadHtml(); - $test = $this->document->query('.foo', Document::QUERY_CSS); - $this->assertTrue($test instanceof NodeList); + $test = $this->document->execute(new Document\Query('.foo', Document\Query::TYPE_CSS)); + $this->assertTrue($test instanceof Document\NodeList); } public function testResultShouldIndicateNumberOfFoundNodes() { $this->loadHtml(); - $result = $this->document->query('.foo', Document::QUERY_CSS); - $message = 'Xpath: ' . $result->getXpathQuery() . "\n"; + $query = new Document\Query('.foo', Document\Query::TYPE_CSS); + $result = $this->document->execute($query); + $message = 'Xpath: ' . $query->getContent() . "\n"; $this->assertEquals(3, count($result), $message); } public function testResultShouldAllowIteratingOverFoundNodes() { $this->loadHtml(); - $result = $this->document->query('.foo', Document::QUERY_CSS); + $result = $this->document->execute(new Document\Query('.foo', Document\Query::TYPE_CSS)); $this->assertEquals(3, count($result)); foreach ($result as $node) { $this->assertTrue($node instanceof \DOMNode, var_export($result, 1)); @@ -199,58 +171,64 @@ public function testResultShouldAllowIteratingOverFoundNodes() public function testQueryShouldFindNodesWithMultipleClasses() { $this->loadHtml(); - $result = $this->document->query('.footerblock .last', Document::QUERY_CSS); - $this->assertEquals(1, count($result), $result->getXpathQuery()); + $query = new Document\Query('.footerblock .last', Document\Query::TYPE_CSS); + $result = $this->document->execute($query); + $this->assertEquals(1, count($result), $query->getContent()); } public function testQueryShouldFindNodesWithArbitraryAttributeSelectorsExactly() { $this->loadHtml(); - $result = $this->document->query('div[dojoType="FilteringSelect"]', Document::QUERY_CSS); - $this->assertEquals(1, count($result), $result->getXpathQuery()); + $query = new Document\Query('div[dojoType="FilteringSelect"]', Document\Query::TYPE_CSS); + $result = $this->document->execute($query); + $this->assertEquals(1, count($result), $query->getContent()); } public function testQueryShouldFindNodesWithArbitraryAttributeSelectorsAsDiscreteWords() { $this->loadHtml(); - $result = $this->document->query('li[dojoType~="bar"]', Document::QUERY_CSS); - $this->assertEquals(2, count($result), $result->getXpathQuery()); + $query = new Document\Query('li[dojoType~="bar"]', Document\Query::TYPE_CSS); + $result = $this->document->execute($query); + $this->assertEquals(2, count($result), $query->getContent()); } public function testQueryShouldFindNodesWithArbitraryAttributeSelectorsAndAttributeValue() { $this->loadHtml(); - $result = $this->document->query('li[dojoType*="bar"]', Document::QUERY_CSS); - $this->assertEquals(2, count($result), $result->getXpathQuery()); + $query = new Document\Query('li[dojoType*="bar"]', Document\Query::TYPE_CSS); + $result = $this->document->execute($query); + $this->assertEquals(2, count($result), $query->getContent()); } public function testQueryXpathShouldAllowQueryingArbitraryUsingXpath() { $this->loadHtml(); - $result = $this->document->query('//li[contains(@dojotype, "bar")]'); - $this->assertEquals(2, count($result), $result->getXpathQuery()); + $query = new Document\Query('//li[contains(@dojotype, "bar")]'); + $result = $this->document->execute($query); + $this->assertEquals(2, count($result), $query->getContent()); } public function testXpathPhpFunctionsShouldBeDisabledByDefault() { $this->loadHtml(); try { - $this->document->query('//meta[php:functionString("strtolower", @http-equiv) = "content-type"]'); + $this->document->execute(new Document\Query('//meta[php:functionString("strtolower", @http-equiv) = "content-type"]')); } catch (\Exception $e) { return; } - $this->assertFails('XPath PHPFunctions should be disabled by default'); + $this->assertTrue(false, 'XPath PHPFunctions should be disabled by default'); } public function testXpathPhpFunctionsShouldBeEnabledWithoutParameter() { $this->loadHtml(); $this->document->registerXpathPhpFunctions(); - $result = $this->document->query('//meta[php:functionString("strtolower", @http-equiv) = "content-type"]'); + $query = new Document\Query('//meta[php:functionString("strtolower", @http-equiv) = "content-type"]'); + $result = $this->document->execute($query); $this->assertEquals( 'content-type', strtolower($result->current()->getAttribute('http-equiv')), - $result->getXpathQuery() + $query->getContent() ); } @@ -259,12 +237,12 @@ public function testXpathPhpFunctionsShouldBeNotCalledWhenSpecifiedFunction() $this->loadHtml(); try { $this->document->registerXpathPhpFunctions('stripos'); - $this->document->query('//meta[php:functionString("strtolower", @http-equiv) = "content-type"]'); + $this->document->execute(new Document\Query('//meta[php:functionString("strtolower", @http-equiv) = "content-type"]')); } catch (\Exception $e) { // $e->getMessage() - Not allowed to call handler 'strtolower() return; } - $this->assertFails('Not allowed to call handler strtolower()'); + $this->assertTrue(false, 'Not allowed to call handler strtolower()'); } /** @@ -273,8 +251,8 @@ public function testXpathPhpFunctionsShouldBeNotCalledWhenSpecifiedFunction() public function testLoadingDocumentWithErrorsShouldNotRaisePhpErrors() { $file = file_get_contents(__DIR__ . '/_files/bad-sample.html'); - $this->document->setStringDocument($file); - $this->document->query('p', Document::QUERY_CSS); + $this->document = new Document($file); + $this->document->execute(new Document\Query('p', Document\Query::TYPE_CSS)); $errors = $this->document->getErrors(); $this->assertTrue(is_array($errors)); $this->assertTrue(0 < count($errors)); @@ -299,12 +277,15 @@ public function testCssSelectorShouldFindNodesWhenMatchingMultipleAttributes() EOF; - $this->document->setStringDocument($html); - $results = $this->document->query('input[type="hidden"][value="1"]', Document::QUERY_CSS); - $this->assertEquals(2, count($results), $results->getXpathQuery()); - $results = $this->document->query('input[value="1"][type~="hidden"]', Document::QUERY_CSS); - $this->assertEquals(2, count($results), $results->getXpathQuery()); - $results = $this->document->query('input[type="hidden"][value="0"]', Document::QUERY_CSS); + $this->document = new Document($html); + $query = new Document\Query('input[type="hidden"][value="1"]', Document\Query::TYPE_CSS); + $results = $this->document->execute($query); + $this->assertEquals(2, count($results), $query->getContent()); + $query = new Document\Query('input[value="1"][type~="hidden"]', Document\Query::TYPE_CSS); + $results = $this->document->execute($query); + $this->assertEquals(2, count($results), $query->getContent()); + $query = new Document\Query('input[type="hidden"][value="0"]', Document\Query::TYPE_CSS); + $results = $this->document->execute($query); $this->assertEquals(1, count($results)); } @@ -313,7 +294,7 @@ public function testCssSelectorShouldFindNodesWhenMatchingMultipleAttributes() */ public function testAllowsSpecifyingEncodingAtConstruction() { - $doc = new Document($this->getHtml(), 'iso-8859-1'); + $doc = new Document($this->getHtml(), null, 'iso-8859-1'); $this->assertEquals('iso-8859-1', $doc->getEncoding()); } @@ -322,7 +303,7 @@ public function testAllowsSpecifyingEncodingAtConstruction() */ public function testAllowsSpecifyingEncodingWhenSettingDocument() { - $this->document->setStringDocument($this->getHtml(), null, 'iso-8859-1'); + $this->document = new Document($this->getHtml(), null, 'iso-8859-1'); $this->assertEquals('iso-8859-1', $this->document->getEncoding()); } @@ -340,12 +321,11 @@ public function testAllowsSpecifyingEncodingViaSetter() */ public function testSpecifyingEncodingSetsEncodingOnDomDocument() { - $this->document->setStringDocument($this->getHtml(), 'utf-8'); - $test = $this->document->query('.foo', Document::QUERY_CSS); - $this->assertInstanceof('\\Zend\\Dom\\NodeList', $test); - $doc = $test->getDocument(); - $this->assertInstanceof('\\DOMDocument', $doc); - $this->assertEquals('utf-8', $doc->encoding); + $this->document = new Document($this->getHtml(), null, 'utf-8'); + $test = $this->document->execute(new Document\Query('.foo', Document\Query::TYPE_CSS)); + $this->assertInstanceof('\\Zend\\Dom\\Document\\NodeList', $test); + $this->assertInstanceof('\\DOMDocument', $this->document->getDomDocument()); + $this->assertEquals('utf-8', $this->document->getEncoding()); } /** @@ -360,8 +340,8 @@ public function testXhtmlDocumentWithXmlDeclaration()

Test paragraph.

EOB; - $this->document->setStringDocument($xhtmlWithXmlDecl, 'utf-8'); - $this->assertEquals(1, $this->document->query('//p', Document::QUERY_CSS)->count()); + $this->document = new Document($xhtmlWithXmlDecl, null, 'utf-8'); + $this->assertEquals(1, $this->document->execute(new Document\Query('//p', Document\Query::TYPE_CSS))->count()); } /** @@ -383,8 +363,8 @@ public function testXhtmlDocumentWithXmlAndDoctypeDeclaration() EOB; - $this->document->setStringDocument($xhtmlWithXmlDecl, 'utf-8'); - $this->assertEquals(1, $this->document->query('//p', Document::QUERY_CSS)->count()); + $this->document = new Document($xhtmlWithXmlDecl, null, 'utf-8'); + $this->assertEquals(1, $this->document->execute(new Document\Query('//p', Document\Query::TYPE_CSS))->count()); } public function testLoadingXmlContainingDoctypeShouldFailToPreventXxeAndXeeAttacks() @@ -396,15 +376,15 @@ public function testLoadingXmlContainingDoctypeShouldFailToPreventXxeAndXeeAttac This result is &harmless; XML; - $this->document->setStringDocument($xml); + $this->document = new Document($xml); $this->setExpectedException("\Zend\Dom\Exception\RuntimeException"); - $this->document->query('/'); + $this->document->execute(new Document\Query('/')); } public function testOffsetExists() { $this->loadHtml(); - $results = $this->document->query('input', Document::QUERY_CSS); + $results = $this->document->execute(new Document\Query('input', Document\Query::TYPE_CSS)); $this->assertEquals(3, $results->count()); $this->assertFalse($results->offsetExists(3)); @@ -414,7 +394,7 @@ public function testOffsetExists() public function testOffsetGet() { $this->loadHtml(); - $results = $this->document->query('input', Document::QUERY_CSS); + $results = $this->document->execute(new Document\Query('input', Document\Query::TYPE_CSS)); $this->assertEquals(3, $results->count()); $this->assertEquals('login', $results[2]->getAttribute('id')); @@ -426,7 +406,7 @@ public function testOffsetGet() public function testOffsetSet() { $this->loadHtml(); - $results = $this->document->query('input', Document::QUERY_CSS); + $results = $this->document->execute(new Document\Query('input', Document\Query::TYPE_CSS)); $this->assertEquals(3, $results->count()); $results[0] = ''; @@ -439,7 +419,7 @@ public function testOffsetSet() public function testOffsetUnset() { $this->loadHtml(); - $results = $this->document->query('input', Document::QUERY_CSS); + $results = $this->document->execute(new Document\Query('input', Document\Query::TYPE_CSS)); $this->assertEquals(3, $results->count()); unset($results[2]); diff --git a/test/NodeListTest.php b/test/NodeListTest.php index 06667f5..e630d42 100644 --- a/test/NodeListTest.php +++ b/test/NodeListTest.php @@ -9,7 +9,7 @@ namespace ZendTest\Dom; -use Zend\Dom\NodeList; +use Zend\Dom\Document\NodeList; /** * @group Zend_Dom @@ -22,8 +22,8 @@ class NodeListTest extends \PHPUnit_Framework_TestCase public function testEmptyResultDoesNotReturnIteratorValidTrue() { $dom = new \DOMDocument(); - $emptyNodeList = $dom->getElementsByTagName("a"); - $result = new NodeList("", "", $dom, $emptyNodeList); + $emptyNodeList = $dom->getElementsByTagName('a'); + $result = new NodeList($emptyNodeList); $this->assertFalse($result->valid()); } From ffeae630fa7dc95a0e8c8b70ec32622b4762da69 Mon Sep 17 00:00:00 2001 From: Thomas Cantonnet Date: Thu, 31 Oct 2013 10:02:20 +0100 Subject: [PATCH 06/20] Moved Query execution logic & added factory method for NodeList --- src/Document.php | 51 +++++++++--------------------- src/Document/NodeList.php | 30 ++++++++++++++++++ src/Document/Query.php | 15 +++++++++ test/DocumentTest.php | 65 ++++++++++++++++++++++++--------------- 4 files changed, 99 insertions(+), 62 deletions(-) diff --git a/src/Document.php b/src/Document.php index 040322e..f73e65a 100644 --- a/src/Document.php +++ b/src/Document.php @@ -272,19 +272,13 @@ protected function getDomDocumentFromString($stringDocument) } /** - * Perform a query on generated DOMDocument + * Get Document's registered XPath namespaces * - * @param Document\Query $query - * @param string $queryType - * @throws Exception\RuntimeException - * @return NodeList + * @return array */ - public function execute(Document\Query $query) + public function getXpathNamespaces() { - $domDoc = $this->getDomDocument(); - $nodeList = $this->getNodeList($domDoc, $query->getContent()); - - return new Document\NodeList($nodeList); + return $this->xpathNamespaces; } /** @@ -298,41 +292,24 @@ public function registerXpathNamespaces($xpathNamespaces) $this->xpathNamespaces = $xpathNamespaces; } + /** - * Register PHP Functions to use in internal DOMXPath + * Get Document's registered XPath PHP Functions * - * @param bool $xpathPhpFunctions - * @return void + * @return string|null */ - public function registerXpathPhpFunctions($xpathPhpFunctions = true) + public function getXpathPhpFunctions() { - $this->xpathPhpFunctions = $xpathPhpFunctions; + return $this->xpathPhpFunctions; } - /** - * Prepare node list + * Register PHP Functions to use in internal DOMXPath * - * @param DOMDocument $document - * @param string|array $xpathQuery - * @return array + * @param bool $xpathPhpFunctions + * @return void */ - protected function getNodeList($document, $xpathQuery) + public function registerXpathPhpFunctions($xpathPhpFunctions = true) { - $xpath = new DOMXPath($document); - - foreach ($this->xpathNamespaces as $prefix => $namespaceUri) { - $xpath->registerNamespace($prefix, $namespaceUri); - } - - if ($this->xpathPhpFunctions) { - $xpath->registerNamespace('php', 'http://php.net/xpath'); - ($this->xpathPhpFunctions === true) ? $xpath->registerPhpFunctions() : $xpath->registerPhpFunctions($this->xpathPhpFunctions); - } - - ErrorHandler::start(); - $nodeList = $xpath->query($xpathQuery); - ErrorHandler::stop(true); - - return $nodeList; + $this->xpathPhpFunctions = $xpathPhpFunctions; } } diff --git a/src/Document/NodeList.php b/src/Document/NodeList.php index 8c09f58..47c291d 100644 --- a/src/Document/NodeList.php +++ b/src/Document/NodeList.php @@ -13,8 +13,11 @@ use Countable; use DOMNode; use DOMNodeList; +use DOMXPath; use Iterator; +use Zend\Dom\Document; use Zend\Dom\Exception; +use Zend\Stdlib\ErrorHandler; /** * DOMNodeList wrapper for Zend\Dom\Document\Query results @@ -42,6 +45,33 @@ public function __construct(DOMNodeList $list) $this->list = $list; } + /** + * Prepare node list + * + * @param DOMDocument $document + * @param Document\Query $query + * @return array + */ + public static function factory(Document $document, Document\Query $query) + { + $xpath = new DOMXPath($document->getDomDocument()); + + $xpathNamespaces = $document->getXpathNamespaces(); + foreach ($xpathNamespaces as $prefix => $namespaceUri) { + $xpath->registerNamespace($prefix, $namespaceUri); + } + + if ($xpathPhpfunctions = $document->getXpathPhpFunctions()) { + $xpath->registerNamespace('php', 'http://php.net/xpath'); + ($xpathPhpfunctions === true) ? $xpath->registerPHPFunctions() : $xpath->registerPHPFunctions($xpathPhpfunctions); + } + + ErrorHandler::start(); + $nodeList = $xpath->query($query->getContent()); + ErrorHandler::stop(true); + + return new static($nodeList); + } /** * Iterator: rewind to first element * diff --git a/src/Document/Query.php b/src/Document/Query.php index 60bc84a..a855f81 100644 --- a/src/Document/Query.php +++ b/src/Document/Query.php @@ -9,6 +9,8 @@ namespace Zend\Dom\Document; +use Zend\Dom\Document; + /** * Query object executable in a Zend\Dom\Document */ @@ -99,6 +101,19 @@ public function setType($type) return $this; } + /** + * Perform the query on Document + * + * @param Document $document + * @return NodeList + */ + public function execute(Document $document) + { + $nodeList = NodeList::factory($document, $this); + + return $nodeList; + } + /** * Transform CSS expression to XPath * diff --git a/test/DocumentTest.php b/test/DocumentTest.php index 0790994..3dad0ae 100644 --- a/test/DocumentTest.php +++ b/test/DocumentTest.php @@ -112,7 +112,8 @@ public function testDocumentTypeShouldBeAutomaticallyDiscovered() public function testQueryingWithoutRegisteringDocumentShouldThrowException() { $this->setExpectedException('\Zend\Dom\Exception\RuntimeException', 'no document'); - $this->document->execute(new Document\Query('.foo', Document\Query::TYPE_CSS)); + $query = new Document\Query('.foo', Document\Query::TYPE_CSS); + $query->execute($this->document); } public function testQueryingInvalidDocumentShouldThrowException() @@ -120,7 +121,8 @@ public function testQueryingInvalidDocumentShouldThrowException() set_error_handler(array($this, 'handleError')); $this->document = new Document('some bogus string', Document::DOC_XML); try { - $this->document->execute(new Document\Query('.foo', Document\Query::TYPE_CSS)); + $query = new Document\Query('.foo', Document\Query::TYPE_CSS); + $query->execute($this->document); restore_error_handler(); $this->fail('Querying invalid document should throw exception'); } catch (DOMException $e) { @@ -145,7 +147,8 @@ public function testgetDomMethodShouldReturnDomDocumentWithStringDocumentSetFrom public function testQueryShouldReturnResultObject() { $this->loadHtml(); - $test = $this->document->execute(new Document\Query('.foo', Document\Query::TYPE_CSS)); + $query = new Document\Query('.foo', Document\Query::TYPE_CSS); + $test = $query->execute($this->document); $this->assertTrue($test instanceof Document\NodeList); } @@ -153,7 +156,7 @@ public function testResultShouldIndicateNumberOfFoundNodes() { $this->loadHtml(); $query = new Document\Query('.foo', Document\Query::TYPE_CSS); - $result = $this->document->execute($query); + $result = $query->execute($this->document); $message = 'Xpath: ' . $query->getContent() . "\n"; $this->assertEquals(3, count($result), $message); } @@ -161,7 +164,8 @@ public function testResultShouldIndicateNumberOfFoundNodes() public function testResultShouldAllowIteratingOverFoundNodes() { $this->loadHtml(); - $result = $this->document->execute(new Document\Query('.foo', Document\Query::TYPE_CSS)); + $query = new Document\Query('.foo', Document\Query::TYPE_CSS); + $result = $query->execute($this->document); $this->assertEquals(3, count($result)); foreach ($result as $node) { $this->assertTrue($node instanceof \DOMNode, var_export($result, 1)); @@ -172,7 +176,7 @@ public function testQueryShouldFindNodesWithMultipleClasses() { $this->loadHtml(); $query = new Document\Query('.footerblock .last', Document\Query::TYPE_CSS); - $result = $this->document->execute($query); + $result = $query->execute($this->document); $this->assertEquals(1, count($result), $query->getContent()); } @@ -180,7 +184,7 @@ public function testQueryShouldFindNodesWithArbitraryAttributeSelectorsExactly() { $this->loadHtml(); $query = new Document\Query('div[dojoType="FilteringSelect"]', Document\Query::TYPE_CSS); - $result = $this->document->execute($query); + $result = $query->execute($this->document); $this->assertEquals(1, count($result), $query->getContent()); } @@ -188,7 +192,7 @@ public function testQueryShouldFindNodesWithArbitraryAttributeSelectorsAsDiscret { $this->loadHtml(); $query = new Document\Query('li[dojoType~="bar"]', Document\Query::TYPE_CSS); - $result = $this->document->execute($query); + $result = $query->execute($this->document); $this->assertEquals(2, count($result), $query->getContent()); } @@ -196,7 +200,7 @@ public function testQueryShouldFindNodesWithArbitraryAttributeSelectorsAndAttrib { $this->loadHtml(); $query = new Document\Query('li[dojoType*="bar"]', Document\Query::TYPE_CSS); - $result = $this->document->execute($query); + $result = $query->execute($this->document); $this->assertEquals(2, count($result), $query->getContent()); } @@ -204,7 +208,7 @@ public function testQueryXpathShouldAllowQueryingArbitraryUsingXpath() { $this->loadHtml(); $query = new Document\Query('//li[contains(@dojotype, "bar")]'); - $result = $this->document->execute($query); + $result = $query->execute($this->document); $this->assertEquals(2, count($result), $query->getContent()); } @@ -212,7 +216,8 @@ public function testXpathPhpFunctionsShouldBeDisabledByDefault() { $this->loadHtml(); try { - $this->document->execute(new Document\Query('//meta[php:functionString("strtolower", @http-equiv) = "content-type"]')); + $query = new Document\Query('//meta[php:functionString("strtolower", @http-equiv) = "content-type"]'); + $query->execute($this->document); } catch (\Exception $e) { return; } @@ -224,7 +229,7 @@ public function testXpathPhpFunctionsShouldBeEnabledWithoutParameter() $this->loadHtml(); $this->document->registerXpathPhpFunctions(); $query = new Document\Query('//meta[php:functionString("strtolower", @http-equiv) = "content-type"]'); - $result = $this->document->execute($query); + $result = $query->execute($this->document); $this->assertEquals( 'content-type', strtolower($result->current()->getAttribute('http-equiv')), @@ -237,7 +242,8 @@ public function testXpathPhpFunctionsShouldBeNotCalledWhenSpecifiedFunction() $this->loadHtml(); try { $this->document->registerXpathPhpFunctions('stripos'); - $this->document->execute(new Document\Query('//meta[php:functionString("strtolower", @http-equiv) = "content-type"]')); + $query = new Document\Query('//meta[php:functionString("strtolower", @http-equiv) = "content-type"]'); + $query->execute($this->document); } catch (\Exception $e) { // $e->getMessage() - Not allowed to call handler 'strtolower() return; @@ -251,8 +257,9 @@ public function testXpathPhpFunctionsShouldBeNotCalledWhenSpecifiedFunction() public function testLoadingDocumentWithErrorsShouldNotRaisePhpErrors() { $file = file_get_contents(__DIR__ . '/_files/bad-sample.html'); + $query = new Document\Query('p', Document\Query::TYPE_CSS); $this->document = new Document($file); - $this->document->execute(new Document\Query('p', Document\Query::TYPE_CSS)); + $query->execute($this->document); $errors = $this->document->getErrors(); $this->assertTrue(is_array($errors)); $this->assertTrue(0 < count($errors)); @@ -279,13 +286,13 @@ public function testCssSelectorShouldFindNodesWhenMatchingMultipleAttributes() $this->document = new Document($html); $query = new Document\Query('input[type="hidden"][value="1"]', Document\Query::TYPE_CSS); - $results = $this->document->execute($query); + $results = $query->execute($this->document); $this->assertEquals(2, count($results), $query->getContent()); $query = new Document\Query('input[value="1"][type~="hidden"]', Document\Query::TYPE_CSS); - $results = $this->document->execute($query); + $results = $query->execute($this->document); $this->assertEquals(2, count($results), $query->getContent()); $query = new Document\Query('input[type="hidden"][value="0"]', Document\Query::TYPE_CSS); - $results = $this->document->execute($query); + $results = $query->execute($this->document); $this->assertEquals(1, count($results)); } @@ -322,7 +329,8 @@ public function testAllowsSpecifyingEncodingViaSetter() public function testSpecifyingEncodingSetsEncodingOnDomDocument() { $this->document = new Document($this->getHtml(), null, 'utf-8'); - $test = $this->document->execute(new Document\Query('.foo', Document\Query::TYPE_CSS)); + $query = new Document\Query('.foo', Document\Query::TYPE_CSS); + $test = $query->execute($this->document); $this->assertInstanceof('\\Zend\\Dom\\Document\\NodeList', $test); $this->assertInstanceof('\\DOMDocument', $this->document->getDomDocument()); $this->assertEquals('utf-8', $this->document->getEncoding()); @@ -341,7 +349,8 @@ public function testXhtmlDocumentWithXmlDeclaration() EOB; $this->document = new Document($xhtmlWithXmlDecl, null, 'utf-8'); - $this->assertEquals(1, $this->document->execute(new Document\Query('//p', Document\Query::TYPE_CSS))->count()); + $query = new Document\Query('//p', Document\Query::TYPE_CSS); + $this->assertEquals(1, $query->execute($this->document)->count()); } /** @@ -364,7 +373,8 @@ public function testXhtmlDocumentWithXmlAndDoctypeDeclaration() EOB; $this->document = new Document($xhtmlWithXmlDecl, null, 'utf-8'); - $this->assertEquals(1, $this->document->execute(new Document\Query('//p', Document\Query::TYPE_CSS))->count()); + $query = new Document\Query('//p', Document\Query::TYPE_CSS); + $this->assertEquals(1, $query->execute($this->document)->count()); } public function testLoadingXmlContainingDoctypeShouldFailToPreventXxeAndXeeAttacks() @@ -378,13 +388,15 @@ public function testLoadingXmlContainingDoctypeShouldFailToPreventXxeAndXeeAttac XML; $this->document = new Document($xml); $this->setExpectedException("\Zend\Dom\Exception\RuntimeException"); - $this->document->execute(new Document\Query('/')); + $query = new Document\Query('/'); + $query->execute($this->document); } public function testOffsetExists() { $this->loadHtml(); - $results = $this->document->execute(new Document\Query('input', Document\Query::TYPE_CSS)); + $query = new Document\Query('input', Document\Query::TYPE_CSS); + $results = $query->execute($this->document); $this->assertEquals(3, $results->count()); $this->assertFalse($results->offsetExists(3)); @@ -394,7 +406,8 @@ public function testOffsetExists() public function testOffsetGet() { $this->loadHtml(); - $results = $this->document->execute(new Document\Query('input', Document\Query::TYPE_CSS)); + $query = new Document\Query('input', Document\Query::TYPE_CSS); + $results = $query->execute($this->document); $this->assertEquals(3, $results->count()); $this->assertEquals('login', $results[2]->getAttribute('id')); @@ -406,7 +419,8 @@ public function testOffsetGet() public function testOffsetSet() { $this->loadHtml(); - $results = $this->document->execute(new Document\Query('input', Document\Query::TYPE_CSS)); + $query = new Document\Query('input', Document\Query::TYPE_CSS); + $results = $query->execute($this->document); $this->assertEquals(3, $results->count()); $results[0] = ''; @@ -419,7 +433,8 @@ public function testOffsetSet() public function testOffsetUnset() { $this->loadHtml(); - $results = $this->document->execute(new Document\Query('input', Document\Query::TYPE_CSS)); + $query = new Document\Query('input', Document\Query::TYPE_CSS); + $results = $query->execute($this->document); $this->assertEquals(3, $results->count()); unset($results[2]); From 27b4eb48477054ca6aa7a1556003b55a3c308854 Mon Sep 17 00:00:00 2001 From: Thomas Cantonnet Date: Fri, 1 Nov 2013 18:52:27 +0100 Subject: [PATCH 07/20] I might lose my sanity if this is not right --- src/Document/NodeList.php | 30 ---------- src/Document/Query.php | 98 +++++++----------------------- test/DocumentTest.php | 121 +++++++++++++++----------------------- 3 files changed, 68 insertions(+), 181 deletions(-) diff --git a/src/Document/NodeList.php b/src/Document/NodeList.php index 47c291d..8c09f58 100644 --- a/src/Document/NodeList.php +++ b/src/Document/NodeList.php @@ -13,11 +13,8 @@ use Countable; use DOMNode; use DOMNodeList; -use DOMXPath; use Iterator; -use Zend\Dom\Document; use Zend\Dom\Exception; -use Zend\Stdlib\ErrorHandler; /** * DOMNodeList wrapper for Zend\Dom\Document\Query results @@ -45,33 +42,6 @@ public function __construct(DOMNodeList $list) $this->list = $list; } - /** - * Prepare node list - * - * @param DOMDocument $document - * @param Document\Query $query - * @return array - */ - public static function factory(Document $document, Document\Query $query) - { - $xpath = new DOMXPath($document->getDomDocument()); - - $xpathNamespaces = $document->getXpathNamespaces(); - foreach ($xpathNamespaces as $prefix => $namespaceUri) { - $xpath->registerNamespace($prefix, $namespaceUri); - } - - if ($xpathPhpfunctions = $document->getXpathPhpFunctions()) { - $xpath->registerNamespace('php', 'http://php.net/xpath'); - ($xpathPhpfunctions === true) ? $xpath->registerPHPFunctions() : $xpath->registerPHPFunctions($xpathPhpfunctions); - } - - ErrorHandler::start(); - $nodeList = $xpath->query($query->getContent()); - ErrorHandler::stop(true); - - return new static($nodeList); - } /** * Iterator: rewind to first element * diff --git a/src/Document/Query.php b/src/Document/Query.php index a855f81..840cca3 100644 --- a/src/Document/Query.php +++ b/src/Document/Query.php @@ -9,7 +9,9 @@ namespace Zend\Dom\Document; +use DOMXPath; use Zend\Dom\Document; +use Zend\Stdlib\ErrorHandler; /** * Query object executable in a Zend\Dom\Document @@ -24,94 +26,34 @@ class Query /**#@-*/ /** - * @var string - */ - protected $type; - - /** - * @var string - */ - protected $content; - - /** - * Constructor + * Perform the query on Document * - * @param string|null $content - * @param string|null $type + * @param Document $document + * @return NodeList */ - public function __construct($content, $type = self::TYPE_XPATH) + public static function execute($expression, Document $document, $type = self::TYPE_XPATH) { + // Expression check if ($type === static::TYPE_CSS) { - $content = static::cssToXpath($content); + $expression = static::cssToXpath($expression); } - $this->setContent($content); - $this->setType($type); - } - - /** - * Get query content - * - * @return string|null - */ - public function getContent() - { - return $this->content; - } - - /** - * Set query content - * - * @param string $content - * @return self - */ - public function setContent($content) - { - $this->content = $content; + $xpath = new DOMXPath($document->getDomDocument()); - return $this; - } - - /** - * Get query type - * - * @return string|null - */ - public function getType() - { - return $this->type; - } - - /** - * Set query type - * - * @param string $type - * @return self - */ - public function setType($type) - { - switch ($type) { - case static::TYPE_CSS: - case static::TYPE_XPATH: - $this->type = $type; - break; - default: - break; + $xpathNamespaces = $document->getXpathNamespaces(); + foreach ($xpathNamespaces as $prefix => $namespaceUri) { + $xpath->registerNamespace($prefix, $namespaceUri); } - return $this; - } + if ($xpathPhpfunctions = $document->getXpathPhpFunctions()) { + $xpath->registerNamespace('php', 'http://php.net/xpath'); + ($xpathPhpfunctions === true) ? $xpath->registerPHPFunctions() : $xpath->registerPHPFunctions($xpathPhpfunctions); + } - /** - * Perform the query on Document - * - * @param Document $document - * @return NodeList - */ - public function execute(Document $document) - { - $nodeList = NodeList::factory($document, $this); + ErrorHandler::start(); + $nodeList = $xpath->query($expression); + ErrorHandler::stop(true); - return $nodeList; + return new NodeList($nodeList); } /** diff --git a/test/DocumentTest.php b/test/DocumentTest.php index 3dad0ae..c4b6bbb 100644 --- a/test/DocumentTest.php +++ b/test/DocumentTest.php @@ -112,8 +112,7 @@ public function testDocumentTypeShouldBeAutomaticallyDiscovered() public function testQueryingWithoutRegisteringDocumentShouldThrowException() { $this->setExpectedException('\Zend\Dom\Exception\RuntimeException', 'no document'); - $query = new Document\Query('.foo', Document\Query::TYPE_CSS); - $query->execute($this->document); + $result = Document\Query::execute('.foo', $this->document, Document\Query::TYPE_CSS); } public function testQueryingInvalidDocumentShouldThrowException() @@ -121,8 +120,7 @@ public function testQueryingInvalidDocumentShouldThrowException() set_error_handler(array($this, 'handleError')); $this->document = new Document('some bogus string', Document::DOC_XML); try { - $query = new Document\Query('.foo', Document\Query::TYPE_CSS); - $query->execute($this->document); + $result = Document\Query::execute('.foo', $this->document, Document\Query::TYPE_CSS); restore_error_handler(); $this->fail('Querying invalid document should throw exception'); } catch (DOMException $e) { @@ -147,25 +145,21 @@ public function testgetDomMethodShouldReturnDomDocumentWithStringDocumentSetFrom public function testQueryShouldReturnResultObject() { $this->loadHtml(); - $query = new Document\Query('.foo', Document\Query::TYPE_CSS); - $test = $query->execute($this->document); - $this->assertTrue($test instanceof Document\NodeList); + $result = Document\Query::execute('.foo', $this->document, Document\Query::TYPE_CSS); + $this->assertTrue($result instanceof Document\NodeList); } public function testResultShouldIndicateNumberOfFoundNodes() { $this->loadHtml(); - $query = new Document\Query('.foo', Document\Query::TYPE_CSS); - $result = $query->execute($this->document); - $message = 'Xpath: ' . $query->getContent() . "\n"; - $this->assertEquals(3, count($result), $message); + $result = Document\Query::execute('.foo', $this->document, Document\Query::TYPE_CSS); + $this->assertEquals(3, count($result)); } public function testResultShouldAllowIteratingOverFoundNodes() { $this->loadHtml(); - $query = new Document\Query('.foo', Document\Query::TYPE_CSS); - $result = $query->execute($this->document); + $result = Document\Query::execute('.foo', $this->document, Document\Query::TYPE_CSS); $this->assertEquals(3, count($result)); foreach ($result as $node) { $this->assertTrue($node instanceof \DOMNode, var_export($result, 1)); @@ -175,49 +169,43 @@ public function testResultShouldAllowIteratingOverFoundNodes() public function testQueryShouldFindNodesWithMultipleClasses() { $this->loadHtml(); - $query = new Document\Query('.footerblock .last', Document\Query::TYPE_CSS); - $result = $query->execute($this->document); - $this->assertEquals(1, count($result), $query->getContent()); + $result = Document\Query::execute('.footerblock .last', $this->document, Document\Query::TYPE_CSS); + $this->assertEquals(1, count($result)); } public function testQueryShouldFindNodesWithArbitraryAttributeSelectorsExactly() { $this->loadHtml(); - $query = new Document\Query('div[dojoType="FilteringSelect"]', Document\Query::TYPE_CSS); - $result = $query->execute($this->document); - $this->assertEquals(1, count($result), $query->getContent()); + $result = Document\Query::execute('div[dojoType="FilteringSelect"]', $this->document, Document\Query::TYPE_CSS); + $this->assertEquals(1, count($result)); } public function testQueryShouldFindNodesWithArbitraryAttributeSelectorsAsDiscreteWords() { $this->loadHtml(); - $query = new Document\Query('li[dojoType~="bar"]', Document\Query::TYPE_CSS); - $result = $query->execute($this->document); - $this->assertEquals(2, count($result), $query->getContent()); + $result = Document\Query::execute('li[dojoType~="bar"]', $this->document, Document\Query::TYPE_CSS); + $this->assertEquals(2, count($result)); } public function testQueryShouldFindNodesWithArbitraryAttributeSelectorsAndAttributeValue() { $this->loadHtml(); - $query = new Document\Query('li[dojoType*="bar"]', Document\Query::TYPE_CSS); - $result = $query->execute($this->document); - $this->assertEquals(2, count($result), $query->getContent()); + $result = Document\Query::execute('li[dojoType*="bar"]', $this->document, Document\Query::TYPE_CSS); + $this->assertEquals(2, count($result)); } public function testQueryXpathShouldAllowQueryingArbitraryUsingXpath() { $this->loadHtml(); - $query = new Document\Query('//li[contains(@dojotype, "bar")]'); - $result = $query->execute($this->document); - $this->assertEquals(2, count($result), $query->getContent()); + $result = Document\Query::execute('//li[contains(@dojotype, "bar")]', $this->document); + $this->assertEquals(2, count($result)); } public function testXpathPhpFunctionsShouldBeDisabledByDefault() { $this->loadHtml(); try { - $query = new Document\Query('//meta[php:functionString("strtolower", @http-equiv) = "content-type"]'); - $query->execute($this->document); + $result = Document\Query::execute('//meta[php:functionString("strtolower", @http-equiv) = "content-type"]', $this->document); } catch (\Exception $e) { return; } @@ -228,12 +216,10 @@ public function testXpathPhpFunctionsShouldBeEnabledWithoutParameter() { $this->loadHtml(); $this->document->registerXpathPhpFunctions(); - $query = new Document\Query('//meta[php:functionString("strtolower", @http-equiv) = "content-type"]'); - $result = $query->execute($this->document); + $result = Document\Query::execute('//meta[php:functionString("strtolower", @http-equiv) = "content-type"]', $this->document); $this->assertEquals( 'content-type', - strtolower($result->current()->getAttribute('http-equiv')), - $query->getContent() + strtolower($result->current()->getAttribute('http-equiv')) ); } @@ -242,8 +228,7 @@ public function testXpathPhpFunctionsShouldBeNotCalledWhenSpecifiedFunction() $this->loadHtml(); try { $this->document->registerXpathPhpFunctions('stripos'); - $query = new Document\Query('//meta[php:functionString("strtolower", @http-equiv) = "content-type"]'); - $query->execute($this->document); + $result = Document\Query::execute('//meta[php:functionString("strtolower", @http-equiv) = "content-type"]', $this->document); } catch (\Exception $e) { // $e->getMessage() - Not allowed to call handler 'strtolower() return; @@ -257,9 +242,8 @@ public function testXpathPhpFunctionsShouldBeNotCalledWhenSpecifiedFunction() public function testLoadingDocumentWithErrorsShouldNotRaisePhpErrors() { $file = file_get_contents(__DIR__ . '/_files/bad-sample.html'); - $query = new Document\Query('p', Document\Query::TYPE_CSS); $this->document = new Document($file); - $query->execute($this->document); + $result = Document\Query::execute('p', $this->document, Document\Query::TYPE_CSS); $errors = $this->document->getErrors(); $this->assertTrue(is_array($errors)); $this->assertTrue(0 < count($errors)); @@ -285,15 +269,12 @@ public function testCssSelectorShouldFindNodesWhenMatchingMultipleAttributes() EOF; $this->document = new Document($html); - $query = new Document\Query('input[type="hidden"][value="1"]', Document\Query::TYPE_CSS); - $results = $query->execute($this->document); - $this->assertEquals(2, count($results), $query->getContent()); - $query = new Document\Query('input[value="1"][type~="hidden"]', Document\Query::TYPE_CSS); - $results = $query->execute($this->document); - $this->assertEquals(2, count($results), $query->getContent()); - $query = new Document\Query('input[type="hidden"][value="0"]', Document\Query::TYPE_CSS); - $results = $query->execute($this->document); - $this->assertEquals(1, count($results)); + $result = Document\Query::execute('input[type="hidden"][value="1"]', $this->document, Document\Query::TYPE_CSS); + $this->assertEquals(2, count($result)); + $result = Document\Query::execute('input[value="1"][type~="hidden"]', $this->document, Document\Query::TYPE_CSS); + $this->assertEquals(2, count($result)); + $result = Document\Query::execute('input[type="hidden"][value="0"]', $this->document, Document\Query::TYPE_CSS); + $this->assertEquals(1, count($result)); } /** @@ -329,9 +310,8 @@ public function testAllowsSpecifyingEncodingViaSetter() public function testSpecifyingEncodingSetsEncodingOnDomDocument() { $this->document = new Document($this->getHtml(), null, 'utf-8'); - $query = new Document\Query('.foo', Document\Query::TYPE_CSS); - $test = $query->execute($this->document); - $this->assertInstanceof('\\Zend\\Dom\\Document\\NodeList', $test); + $result = Document\Query::execute('.foo', $this->document, Document\Query::TYPE_CSS); + $this->assertInstanceof('\\Zend\\Dom\\Document\\NodeList', $result); $this->assertInstanceof('\\DOMDocument', $this->document->getDomDocument()); $this->assertEquals('utf-8', $this->document->getEncoding()); } @@ -349,8 +329,8 @@ public function testXhtmlDocumentWithXmlDeclaration() EOB; $this->document = new Document($xhtmlWithXmlDecl, null, 'utf-8'); - $query = new Document\Query('//p', Document\Query::TYPE_CSS); - $this->assertEquals(1, $query->execute($this->document)->count()); + $result = Document\Query::execute('//p', $this->document, Document\Query::TYPE_CSS); + $this->assertEquals(1, $result->count()); } /** @@ -373,8 +353,8 @@ public function testXhtmlDocumentWithXmlAndDoctypeDeclaration() EOB; $this->document = new Document($xhtmlWithXmlDecl, null, 'utf-8'); - $query = new Document\Query('//p', Document\Query::TYPE_CSS); - $this->assertEquals(1, $query->execute($this->document)->count()); + $result = Document\Query::execute('//p', $this->document, Document\Query::TYPE_CSS); + $this->assertEquals(1, $result->count()); } public function testLoadingXmlContainingDoctypeShouldFailToPreventXxeAndXeeAttacks() @@ -388,29 +368,26 @@ public function testLoadingXmlContainingDoctypeShouldFailToPreventXxeAndXeeAttac XML; $this->document = new Document($xml); $this->setExpectedException("\Zend\Dom\Exception\RuntimeException"); - $query = new Document\Query('/'); - $query->execute($this->document); + $result = Document\Query::execute('/', $this->document); } public function testOffsetExists() { $this->loadHtml(); - $query = new Document\Query('input', Document\Query::TYPE_CSS); - $results = $query->execute($this->document); + $result = Document\Query::execute('input', $this->document, Document\Query::TYPE_CSS); - $this->assertEquals(3, $results->count()); - $this->assertFalse($results->offsetExists(3)); - $this->assertTrue($results->offsetExists(2)); + $this->assertEquals(3, $result->count()); + $this->assertFalse($result->offsetExists(3)); + $this->assertTrue($result->offsetExists(2)); } public function testOffsetGet() { $this->loadHtml(); - $query = new Document\Query('input', Document\Query::TYPE_CSS); - $results = $query->execute($this->document); + $result = Document\Query::execute('input', $this->document, Document\Query::TYPE_CSS); - $this->assertEquals(3, $results->count()); - $this->assertEquals('login', $results[2]->getAttribute('id')); + $this->assertEquals(3, $result->count()); + $this->assertEquals('login', $result[2]->getAttribute('id')); } /** @@ -419,11 +396,10 @@ public function testOffsetGet() public function testOffsetSet() { $this->loadHtml(); - $query = new Document\Query('input', Document\Query::TYPE_CSS); - $results = $query->execute($this->document); - $this->assertEquals(3, $results->count()); + $result = Document\Query::execute('input', $this->document, Document\Query::TYPE_CSS); + $this->assertEquals(3, $result->count()); - $results[0] = ''; + $result[0] = ''; } @@ -433,10 +409,9 @@ public function testOffsetSet() public function testOffsetUnset() { $this->loadHtml(); - $query = new Document\Query('input', Document\Query::TYPE_CSS); - $results = $query->execute($this->document); - $this->assertEquals(3, $results->count()); + $result = Document\Query::execute('input', $this->document, Document\Query::TYPE_CSS); + $this->assertEquals(3, $result->count()); - unset($results[2]); + unset($result[2]); } } From 10cf192b46a3d384edbbf5bdeeab26574a3a39c2 Mon Sep 17 00:00:00 2001 From: Matthew Weier O'Phinney Date: Fri, 1 Nov 2013 16:25:09 -0500 Subject: [PATCH 08/20] [zendframework/zf2#5356] Deprecate Css2Xpath - Marked Css2Xpath::transform as deprecated. It now triggers an E_USER_DEPRECATED error and proxies to Zend\Dom\Document\Query::cssToXpath(). --- src/Css2Xpath.php | 110 +++------------------------------------------- 1 file changed, 6 insertions(+), 104 deletions(-) diff --git a/src/Css2Xpath.php b/src/Css2Xpath.php index c84f6df..dba12e7 100644 --- a/src/Css2Xpath.php +++ b/src/Css2Xpath.php @@ -11,121 +11,23 @@ /** * Transform CSS selectors to XPath + * * @deprecated - * @see \Zend\Dom\Document\Query + * @see Document\Query */ class Css2Xpath { /** * Transform CSS expression to XPath * + * @deprecated + * @see Document\Query * @param string $path * @return string */ public static function transform($path) { - $path = (string) $path; - if (strstr($path, ',')) { - $paths = explode(',', $path); - $expressions = array(); - foreach ($paths as $path) { - $xpath = self::transform(trim($path)); - if (is_string($xpath)) { - $expressions[] = $xpath; - } elseif (is_array($xpath)) { - $expressions = array_merge($expressions, $xpath); - } - } - return implode('|', $expressions); - } - - $paths = array('//'); - $path = preg_replace('|\s+>\s+|', '>', $path); - $segments = preg_split('/\s+/', $path); - foreach ($segments as $key => $segment) { - $pathSegment = static::_tokenize($segment); - if (0 == $key) { - if (0 === strpos($pathSegment, '[contains(')) { - $paths[0] .= '*' . ltrim($pathSegment, '*'); - } else { - $paths[0] .= $pathSegment; - } - continue; - } - if (0 === strpos($pathSegment, '[contains(')) { - foreach ($paths as $pathKey => $xpath) { - $paths[$pathKey] .= '//*' . ltrim($pathSegment, '*'); - $paths[] = $xpath . $pathSegment; - } - } else { - foreach ($paths as $pathKey => $xpath) { - $paths[$pathKey] .= '//' . $pathSegment; - } - } - } - - if (1 == count($paths)) { - return $paths[0]; - } - return implode('|', $paths); - } - - /** - * Tokenize CSS expressions to XPath - * - * @param string $expression - * @return string - */ - protected static function _tokenize($expression) - { - // Child selectors - $expression = str_replace('>', '/', $expression); - - // IDs - $expression = preg_replace('|#([a-z][a-z0-9_-]*)|i', '[@id=\'$1\']', $expression); - $expression = preg_replace('|(? Date: Sun, 3 Nov 2013 08:33:40 +0100 Subject: [PATCH 09/20] [zendframework/zf2#5356] Fix constant Fix typo added in 064fb125603dede6a85a2a0c5409a078c69a12b5 --- src/Css2Xpath.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Css2Xpath.php b/src/Css2Xpath.php index dba12e7..d55881c 100644 --- a/src/Css2Xpath.php +++ b/src/Css2Xpath.php @@ -27,7 +27,7 @@ class Css2Xpath */ public static function transform($path) { - trigger_error(sprintf('%s is deprecated; please use %s\Document\Query::cssToXpath instead', __METHOD__, __NAMESPACE_), E_USER_DEPRECATED); + trigger_error(sprintf('%s is deprecated; please use %s\Document\Query::cssToXpath instead', __METHOD__, __NAMESPACE__), E_USER_DEPRECATED); return Document\Query::cssToXpath($path); } } From 3f6c1ee02bc9f1c976c4d165a83351c503dcace0 Mon Sep 17 00:00:00 2001 From: Maks3w Date: Sun, 3 Nov 2013 08:39:55 +0100 Subject: [PATCH 10/20] [zendframework/zf2#5356] Replace deprecated call Issued introduced by 064fb125603dede6a85a2a0c5409a078c69a12b5 --- src/Query.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Query.php b/src/Query.php index f36088f..8ff02eb 100644 --- a/src/Query.php +++ b/src/Query.php @@ -212,7 +212,7 @@ public function getDocumentErrors() */ public function execute($query) { - $xpathQuery = Css2Xpath::transform($query); + $xpathQuery = Document\Query::cssToXpath($query); return $this->queryXpath($xpathQuery, $query); } From 486891e066b4ceb51f501fa06a75fcca99f5c1a0 Mon Sep 17 00:00:00 2001 From: Maks3w Date: Sun, 3 Nov 2013 08:41:42 +0100 Subject: [PATCH 11/20] [zendframework/zf2#5356] Rename test case. Css2Xpath is not longer tested by the file. --- test/{Css2XpathTest.php => Document/QueryTest.php} | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) rename test/{Css2XpathTest.php => Document/QueryTest.php} (97%) diff --git a/test/Css2XpathTest.php b/test/Document/QueryTest.php similarity index 97% rename from test/Css2XpathTest.php rename to test/Document/QueryTest.php index 069f9c6..54b363b 100644 --- a/test/Css2XpathTest.php +++ b/test/Document/QueryTest.php @@ -7,16 +7,16 @@ * @license http://framework.zend.com/license/new-bsd New BSD License */ -namespace ZendTest\Dom; +namespace ZendTest\Dom\Document; use Zend\Dom\Document\Query; /** - * Test class for Css2Xpath. + * Test class for Zend\Dom\Document\Query. * * @group Zend_Dom */ -class Css2XpathTest extends \PHPUnit_Framework_TestCase +class QueryTest extends \PHPUnit_Framework_TestCase { public function testTransformShouldBeCalledStatically() { From f0d51438790c18cba37cc7a0fc94b45e4f457ba9 Mon Sep 17 00:00:00 2001 From: Maks3w Date: Sun, 3 Nov 2013 09:30:07 +0100 Subject: [PATCH 12/20] [zendframework/zf2#5356] Remove unnecessary/unused `use`s --- src/Document.php | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/Document.php b/src/Document.php index f73e65a..a6098b1 100644 --- a/src/Document.php +++ b/src/Document.php @@ -10,10 +10,6 @@ namespace Zend\Dom; use DOMDocument; -use DOMXPath; -use Zend\Dom\Document; -use Zend\Dom\Exception; -use Zend\Stdlib\ErrorHandler; /** * Class used to initialize DomDocument from string, with proper verifications From 1d9a741bd67a5b59a5076790b91b37b715165871 Mon Sep 17 00:00:00 2001 From: Maks3w Date: Sun, 3 Nov 2013 09:39:45 +0100 Subject: [PATCH 13/20] [zendframework/zf2#5356] Improve docblocks --- src/Document.php | 4 ++-- src/Document/Query.php | 4 +++- src/Query.php | 2 ++ 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/Document.php b/src/Document.php index a6098b1..d5b056d 100644 --- a/src/Document.php +++ b/src/Document.php @@ -143,8 +143,8 @@ protected function setType($type) /** * Get DOMDocument generated from set raw document * - * @return string|null - * @throws Exception\RuntimeException + * @return DOMDocument + * @throws Exception\RuntimeException If cannot get DOMDocument; no document registered */ public function getDomDocument() { diff --git a/src/Document/Query.php b/src/Document/Query.php index 7874538..94e7fb4 100644 --- a/src/Document/Query.php +++ b/src/Document/Query.php @@ -28,7 +28,9 @@ class Query /** * Perform the query on Document * - * @param Document $document + * @param string $expression CSS selector or XPath query + * @param Document $document Document to query + * @param string $type The type of $expression * @return NodeList */ public static function execute($expression, Document $document, $type = self::TYPE_XPATH) diff --git a/src/Query.php b/src/Query.php index 8ff02eb..2ce084f 100644 --- a/src/Query.php +++ b/src/Query.php @@ -11,6 +11,7 @@ use DOMDocument; use DOMXPath; +use ErrorException; use Zend\Stdlib\ErrorHandler; /** @@ -300,6 +301,7 @@ public function registerXpathPhpFunctions($xpathPhpFunctions = true) * @param DOMDocument $document * @param string|array $xpathQuery * @return array + * @throws ErrorException If query cannot be executed */ protected function getNodeList($document, $xpathQuery) { From 11f05e0fbff4a83ec640bc8d5691fb20e168a947 Mon Sep 17 00:00:00 2001 From: Maks3w Date: Sun, 3 Nov 2013 09:41:00 +0100 Subject: [PATCH 14/20] [zendframework/zf2#5356] Throws exception without save and throw again. --- src/Query.php | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/Query.php b/src/Query.php index 2ce084f..d1d9712 100644 --- a/src/Query.php +++ b/src/Query.php @@ -319,10 +319,8 @@ protected function getNodeList($document, $xpathQuery) ErrorHandler::start(); $nodeList = $xpath->query($xpathQuery); - $error = ErrorHandler::stop(); - if ($error) { - throw $error; - } + ErrorHandler::stop(true); + return $nodeList; } } From fb5aac272dfb5241575ff34a8f3fb90b563d8f11 Mon Sep 17 00:00:00 2001 From: Kathryn Reeve Date: Tue, 31 Dec 2013 16:11:41 +0000 Subject: [PATCH 15/20] copyright update for 2014 - Zend Library --- src/Css2Xpath.php | 2 +- src/Document.php | 2 +- src/Document/NodeList.php | 2 +- src/Document/Query.php | 2 +- src/Exception/BadMethodCallException.php | 2 +- src/Exception/ExceptionInterface.php | 2 +- src/Exception/RuntimeException.php | 2 +- src/NodeList.php | 2 +- src/Query.php | 2 +- 9 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/Css2Xpath.php b/src/Css2Xpath.php index d55881c..7aa7d50 100644 --- a/src/Css2Xpath.php +++ b/src/Css2Xpath.php @@ -3,7 +3,7 @@ * Zend Framework (http://framework.zend.com/) * * @link http://github.com/zendframework/zf2 for the canonical source repository - * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com) + * @copyright Copyright (c) 2005-2014 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License */ diff --git a/src/Document.php b/src/Document.php index d5b056d..8ece0b4 100644 --- a/src/Document.php +++ b/src/Document.php @@ -3,7 +3,7 @@ * Zend Framework (http://framework.zend.com/) * * @link http://github.com/zendframework/zf2 for the canonical source repository - * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com) + * @copyright Copyright (c) 2005-2014 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License */ diff --git a/src/Document/NodeList.php b/src/Document/NodeList.php index 8c09f58..09977fb 100644 --- a/src/Document/NodeList.php +++ b/src/Document/NodeList.php @@ -3,7 +3,7 @@ * Zend Framework (http://framework.zend.com/) * * @link http://github.com/zendframework/zf2 for the canonical source repository - * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com) + * @copyright Copyright (c) 2005-2014 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License */ diff --git a/src/Document/Query.php b/src/Document/Query.php index 94e7fb4..6d40884 100644 --- a/src/Document/Query.php +++ b/src/Document/Query.php @@ -3,7 +3,7 @@ * Zend Framework (http://framework.zend.com/) * * @link http://github.com/zendframework/zf2 for the canonical source repository - * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com) + * @copyright Copyright (c) 2005-2014 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License */ diff --git a/src/Exception/BadMethodCallException.php b/src/Exception/BadMethodCallException.php index efa6f2c..df3eb1f 100644 --- a/src/Exception/BadMethodCallException.php +++ b/src/Exception/BadMethodCallException.php @@ -3,7 +3,7 @@ * Zend Framework (http://framework.zend.com/) * * @link http://github.com/zendframework/zf2 for the canonical source repository - * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com) + * @copyright Copyright (c) 2005-2014 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License */ diff --git a/src/Exception/ExceptionInterface.php b/src/Exception/ExceptionInterface.php index ff866f0..f342f8f 100644 --- a/src/Exception/ExceptionInterface.php +++ b/src/Exception/ExceptionInterface.php @@ -3,7 +3,7 @@ * Zend Framework (http://framework.zend.com/) * * @link http://github.com/zendframework/zf2 for the canonical source repository - * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com) + * @copyright Copyright (c) 2005-2014 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License */ diff --git a/src/Exception/RuntimeException.php b/src/Exception/RuntimeException.php index 229e8e6..6cd15e2 100644 --- a/src/Exception/RuntimeException.php +++ b/src/Exception/RuntimeException.php @@ -3,7 +3,7 @@ * Zend Framework (http://framework.zend.com/) * * @link http://github.com/zendframework/zf2 for the canonical source repository - * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com) + * @copyright Copyright (c) 2005-2014 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License */ diff --git a/src/NodeList.php b/src/NodeList.php index ec7f152..0816a64 100644 --- a/src/NodeList.php +++ b/src/NodeList.php @@ -3,7 +3,7 @@ * Zend Framework (http://framework.zend.com/) * * @link http://github.com/zendframework/zf2 for the canonical source repository - * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com) + * @copyright Copyright (c) 2005-2014 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License */ diff --git a/src/Query.php b/src/Query.php index d1d9712..4a5e453 100644 --- a/src/Query.php +++ b/src/Query.php @@ -3,7 +3,7 @@ * Zend Framework (http://framework.zend.com/) * * @link http://github.com/zendframework/zf2 for the canonical source repository - * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com) + * @copyright Copyright (c) 2005-2014 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License */ From bb8b9d314815606f92a045d0d0326e805bca4f98 Mon Sep 17 00:00:00 2001 From: "Paul M. Jones" Date: Mon, 24 Feb 2014 17:43:19 -0600 Subject: [PATCH 16/20] use end() instead of convoluted count() --- src/DOMXpath.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/DOMXpath.php b/src/DOMXpath.php index f98fbe3..e67fd34 100644 --- a/src/DOMXpath.php +++ b/src/DOMXpath.php @@ -17,6 +17,7 @@ class DOMXPath extends \DOMXPath { /** * A stack of ErrorExceptions created via addError() + * * @var array */ protected $errors = array(null); @@ -56,7 +57,7 @@ public function queryWithErrorException($expression) */ public function addError($errno, $errstr = '', $errfile = '', $errline = 0) { - $last_error = $this->errors[count($this->errors) - 1]; + $last_error = end($this->errors); $this->errors[] = new ErrorException( $errstr, 0, From d1993555a9a452356376ec11cd1a1dc0fc8d3099 Mon Sep 17 00:00:00 2001 From: Matthew Weier O'Phinney Date: Tue, 25 Feb 2014 11:33:02 -0600 Subject: [PATCH 17/20] [zendframework/zf2#5865] Fix filesystem filename case - s/DOMXpath/DOMXPath/ so that filename and class name match (fixes failure in Zend\Dom\Document\Query test) --- src/{DOMXpath.php => DOMXPath.php} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/{DOMXpath.php => DOMXPath.php} (100%) diff --git a/src/DOMXpath.php b/src/DOMXPath.php similarity index 100% rename from src/DOMXpath.php rename to src/DOMXPath.php From f91ebfeae85d233b81a9128a2cb350f46386f90f Mon Sep 17 00:00:00 2001 From: Marco Pivetta Date: Thu, 13 Mar 2014 12:51:17 +0100 Subject: [PATCH 18/20] Upgrading branch aliases for components: 2.2-dev -> 2.3-dev, 2.3-dev -> 2.4-dev --- composer.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index 106e995..b3b556c 100644 --- a/composer.json +++ b/composer.json @@ -17,8 +17,8 @@ }, "extra": { "branch-alias": { - "dev-master": "2.2-dev", - "dev-develop": "2.3-dev" + "dev-master": "2.3-dev", + "dev-develop": "2.4-dev" } }, "autoload-dev": { From b950bf390997a3f7af2dcb0e1d996db2547de02c Mon Sep 17 00:00:00 2001 From: Abdul Malik Ikhsan Date: Sun, 30 Mar 2014 10:44:23 +0700 Subject: [PATCH 19/20] fixed typo --- src/Document/NodeList.php | 4 ++-- src/NodeList.php | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Document/NodeList.php b/src/Document/NodeList.php index 09977fb..352326f 100644 --- a/src/Document/NodeList.php +++ b/src/Document/NodeList.php @@ -140,7 +140,7 @@ public function offsetGet($key) * * @param mixed $key * @param mixed $value - * @throws Exception\BadMethodCallException when attemptingn to write to a read-only item + * @throws Exception\BadMethodCallException when attempting to write to a read-only item */ public function offsetSet($key, $value) { @@ -151,7 +151,7 @@ public function offsetSet($key, $value) * ArrayAccess: unset offset * * @param mixed $key - * @throws Exception\BadMethodCallException when attemptingn to unset a read-only item + * @throws Exception\BadMethodCallException when attempting to unset a read-only item */ public function offsetUnset($key) { diff --git a/src/NodeList.php b/src/NodeList.php index 0816a64..f9d4a1d 100644 --- a/src/NodeList.php +++ b/src/NodeList.php @@ -195,7 +195,7 @@ public function offsetGet($key) * * @param mixed $key * @param mixed $value - * @throws Exception\BadMethodCallException when attemptingn to write to a read-only item + * @throws Exception\BadMethodCallException when attempting to write to a read-only item */ public function offsetSet($key, $value) { @@ -206,7 +206,7 @@ public function offsetSet($key, $value) * ArrayAccess: unset offset * * @param mixed $key - * @throws Exception\BadMethodCallException when attemptingn to unset a read-only item + * @throws Exception\BadMethodCallException when attempting to unset a read-only item */ public function offsetUnset($key) { From dc76beecb9f9142929715ef1c63065a6a809988c Mon Sep 17 00:00:00 2001 From: Chad Gray Date: Sun, 13 Jul 2014 08:09:07 -0400 Subject: [PATCH 20/20] PHPCS fixes for Zend\Dom --- src/Document.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Document.php b/src/Document.php index 8ece0b4..456e17f 100644 --- a/src/Document.php +++ b/src/Document.php @@ -288,7 +288,6 @@ public function registerXpathNamespaces($xpathNamespaces) $this->xpathNamespaces = $xpathNamespaces; } - /** * Get Document's registered XPath PHP Functions *