<?php /** @file * CSS Event handling tests */ namespace QueryPath\Tests; require_once __DIR__ . '/../TestCase.php'; use \QueryPath\CSS\Token; use \QueryPath\CSS\QueryPathEventHandler; use \QueryPath\CSS\Parser; use \QueryPath\CSS\EventHandler; /** * Tests for QueryPathEventHandler class. * @ingroup querypath_tests * @group deprecated */ class QueryPathEventHandlerTest extends TestCase { var $xml = '<?xml version="1.0" ?> <html> <head> <title>This is the title</title> </head> <body> <div id="one"> <div id="two" class="class-one"> <div id="three"> Inner text. </div> </div> </div> <span class="class-two">Nada</span> <p><p><p><p><p><p><p class="Odd"><p>8</p></p></p></p></p></p></p></p> <ul> <li class="Odd" id="li-one">Odd</li> <li class="even" id="li-two">Even</li> <li class="Odd" id="li-three">Odd</li> <li class="even" id="li-four">Even</li> <li class="Odd" id="li-five">Odd</li> <li class="even" id="li-six">Even</li> <li class="Odd" id="li-seven">Odd</li> <li class="even" id="li-eight">Even</li> <li class="Odd" id="li-nine">Odd</li> <li class="even" id="li-ten">Even</li> </ul> </body> </html> '; private function firstMatch($matches) { $matches->rewind(); return $matches->current(); } private function nthMatch($matches, $n = 0) { foreach ($matches as $m) { if ($matches->key() == $n) return $m; } } public function testGetMatches() { // Test root element: $xml = '<?xml version="1.0" ?><test><inside/>Text<inside/></test>'; $doc = new \DomDocument(); $doc->loadXML($xml); // Test handing it a DOM Document $handler = new QueryPathEventHandler($doc); $matches = $handler->getMatches(); $this->assertTrue($matches->count() == 1); $match = $this->firstMatch($matches); $this->assertEquals('test', $match->tagName); // Test handling single element $root = $doc->documentElement; $handler = new QueryPathEventHandler($root); $matches = $handler->getMatches(); $this->assertEquals(1, $matches->count()); $match = $this->firstMatch($matches); $this->assertEquals('test', $match->tagName); // Test handling a node list $eles = $doc->getElementsByTagName('inside'); $handler = new QueryPathEventHandler($eles); $matches = $handler->getMatches(); $this->assertEquals(2, $matches->count()); $match = $this->firstMatch($matches); $this->assertEquals('inside', $match->tagName); // Test handling an array of elements $eles = $doc->getElementsByTagName('inside'); $array = array(); foreach ($eles as $ele) $array[] = $ele; $handler = new QueryPathEventHandler($array); $matches = $handler->getMatches(); $this->assertEquals(2, $matches->count()); $match = $this->firstMatch($matches); $this->assertEquals('inside', $match->tagName); } /** * @expectedException \QueryPath\CSS\ParseException */ public function testEmptySelector() { $xml = '<?xml version="1.0" ?><t:test xmlns:t="urn:foo/bar"><t:inside id="first"/>Text<t:inside/><inside/></t:test>'; $doc = new \DomDocument(); $doc->loadXML($xml); // Basic test $handler = new QueryPathEventHandler($doc); $handler->find(''); $matches = $handler->getMatches(); $this->assertEquals(0, $matches->count()); } public function testElementNS() { $xml = '<?xml version="1.0" ?><t:test xmlns:t="urn:foo/bar"><t:inside id="first"/>Text<t:inside/><inside/></t:test>'; $doc = new \DomDocument(); $doc->loadXML($xml); // Basic test $handler = new QueryPathEventHandler($doc); $handler->find('t|inside'); $matches = $handler->getMatches(); $this->assertEquals(2, $matches->count()); $match = $this->firstMatch($matches); $this->assertEquals('t:inside', $match->tagName); // Basic test $handler = new QueryPathEventHandler($doc); $handler->find('t|test'); $matches = $handler->getMatches(); $this->assertEquals(1, $matches->count()); $match = $this->firstMatch($matches); $this->assertEquals('t:test', $match->tagName); } /** * @expectedException \QueryPath\CSS\ParseException */ public function testFailedElementNS() { $xml = '<?xml version="1.0" ?><t:test xmlns:t="urn:foo/bar"><t:inside id="first"/>Text<t:inside/><inside/></t:test>'; $doc = new \DomDocument(); $doc->loadXML($xml); $handler = new QueryPathEventHandler($doc); $handler->find('myns\:mytest'); } public function testElement() { $xml = '<?xml version="1.0" ?><test><inside id="first"/>Text<inside/></test>'; $doc = new \DomDocument(); $doc->loadXML($xml); // Basic test $handler = new QueryPathEventHandler($doc); $handler->find('inside'); $matches = $handler->getMatches(); $this->assertEquals(2, $matches->count()); $match = $this->firstMatch($matches); $this->assertEquals('inside', $match->tagName); $doc = new \DomDocument(); $doc->loadXML($this->xml); // Test getting nested $handler = new QueryPathEventHandler($doc); $handler->find('div'); $matches = $handler->getMatches(); $this->assertEquals(3, $matches->count()); $match = $this->firstMatch($matches); $this->assertEquals('div', $match->tagName); $this->assertEquals('one', $match->getAttribute('id')); // Test getting a list $handler = new QueryPathEventHandler($doc); $handler->find('li'); $matches = $handler->getMatches(); $this->assertEquals(10, $matches->count()); $match = $this->firstMatch($matches); //$this->assertEquals('div', $match->tagName); $this->assertEquals('li-one', $match->getAttribute('id')); // Test getting the root element $handler = new QueryPathEventHandler($doc); $handler->find('html'); $matches = $handler->getMatches(); $this->assertEquals(1, $matches->count()); $match = $this->firstMatch($matches); $this->assertEquals('html', $match->tagName); } public function testElementId() { // Test root element: $xml = '<?xml version="1.0" ?><test><inside id="first"/>Text<inside/></test>'; $doc = new \DomDocument(); $doc->loadXML($xml); $handler = new QueryPathEventHandler($doc); $handler->find('#first'); $matches = $handler->getMatches(); $this->assertEquals(1, $matches->count()); $match = $this->firstMatch($matches); $this->assertEquals('inside', $match->tagName); // Test a search with restricted scope: $handler = new QueryPathEventHandler($doc); $handler->find('inside#first'); $matches = $handler->getMatches(); $this->assertEquals(1, $matches->count()); $match = $this->firstMatch($matches); $this->assertEquals('inside', $match->tagName); } public function testAnyElementInNS() { $xml = '<?xml version="1.0" ?><ns1:test xmlns:ns1="urn:foo/bar"><ns1:inside/>Text<ns1:inside/></ns1:test>'; $doc = new \DomDocument(); $doc->loadXML($xml); // Test handing it a DOM Document $handler = new QueryPathEventHandler($doc); $handler->find('ns1|*'); $matches = $handler->getMatches(); $this->assertEquals(3, $matches->count()); $match = $this->firstMatch($matches); $this->assertEquals('ns1:test', $match->tagName); // Test Issue #30: $xml = '<?xml version="1.0" ?> <ns1:test xmlns:ns1="urn:foo/bar"> <ns1:inside> <ns1:insideInside>Test</ns1:insideInside> </ns1:inside> </ns1:test>'; $doc = new \DomDocument(); $doc->loadXML($xml); $handler = new QueryPathEventHandler($doc); $handler->find('ns1|test>*'); $matches = $handler->getMatches(); $this->assertEquals(1, $matches->count()); $match = $this->firstMatch($matches); $this->assertEquals('ns1:inside', $match->tagName); } public function testAnyElement() { $xml = '<?xml version="1.0" ?><test><inside/>Text<inside/></test>'; $doc = new \DomDocument(); $doc->loadXML($xml); // Test handing it a DOM Document $handler = new QueryPathEventHandler($doc); $handler->find('*'); $matches = $handler->getMatches(); $this->assertEquals(3, $matches->count()); $match = $this->firstMatch($matches); $this->assertEquals('test', $match->tagName); $doc = new \DomDocument(); $doc->loadXML($this->xml); // Test handing it a DOM Document $handler = new QueryPathEventHandler($doc); $handler->find('#two *'); $matches = $handler->getMatches(); $this->assertEquals(1, $matches->count()); $match = $this->firstMatch($matches); $this->assertEquals('three', $match->getAttribute('id')); // Regression for issue #30 $handler = new QueryPathEventHandler($doc); $handler->find('#one>*'); $matches = $handler->getMatches(); $this->assertEquals(1, $matches->count(), 'Should match just top div.'); $match = $this->firstMatch($matches); $this->assertEquals('two', $match->getAttribute('id'), 'Should match ID #two'); } public function testElementClass() { $xml = '<?xml version="1.0" ?><test><inside class="foo" id="one"/>Text<inside/></test>'; $doc = new \DomDocument(); $doc->loadXML($xml); // Test basic class $handler = new QueryPathEventHandler($doc); $handler->find('.foo'); $matches = $handler->getMatches(); $this->assertEquals(1, $matches->count()); $match = $this->firstMatch($matches); $this->assertEquals('one', $match->getAttribute('id')); // Test class in element $doc = new \DomDocument(); $doc->loadXML($this->xml); $handler = new QueryPathEventHandler($doc); $handler->find('li.Odd'); $matches = $handler->getMatches(); $this->assertEquals(5, $matches->count()); $match = $this->nthMatch($matches, 4); $this->assertEquals('li-nine', $match->getAttribute('id')); // Test ID/class combo $handler = new QueryPathEventHandler($doc); $handler->find('.Odd#li-nine'); $matches = $handler->getMatches(); $this->assertEquals(1, $matches->count()); $match = $this->firstMatch($matches); $this->assertEquals('li-nine', $match->getAttribute('id')); } public function testDirectDescendant() { $xml = '<?xml version="1.0" ?> <test> <inside class="foo" id="one"/> Text <inside id="two"> <inside id="inner-one"/> </inside> </test>'; $doc = new \DomDocument(); $doc->loadXML($xml); // Test direct descendent $handler = new QueryPathEventHandler($doc); $handler->find('test > inside'); $matches = $handler->getMatches(); $this->assertEquals(2, $matches->count()); $match = $this->nthMatch($matches, 1); $this->assertEquals('two', $match->getAttribute('id')); } public function testAttribute() { $xml = '<?xml version="1.0" ?><test><inside id="one" name="antidisestablishmentarianism"/>Text<inside/></test>'; $doc = new \DomDocument(); $doc->loadXML($xml); // Test match on attr name $handler = new QueryPathEventHandler($doc); $handler->find('inside[name]'); $matches = $handler->getMatches(); $this->assertEquals(1, $matches->count()); $match = $this->firstMatch($matches); $this->assertEquals('one', $match->getAttribute('id')); // Test broken form $handler = new QueryPathEventHandler($doc); $handler->find('inside[@name]'); $matches = $handler->getMatches(); $this->assertEquals(1, $matches->count()); $match = $this->firstMatch($matches); $this->assertEquals('one', $match->getAttribute('id')); // Test match on attr name and equals value $handler = new QueryPathEventHandler($doc); $handler->find('inside[name="antidisestablishmentarianism"]'); $matches = $handler->getMatches(); $this->assertEquals(1, $matches->count()); $match = $this->firstMatch($matches); $this->assertEquals('one', $match->getAttribute('id')); // Test match on containsInString $handler = new QueryPathEventHandler($doc); $handler->find('inside[name*="disestablish"]'); $matches = $handler->getMatches(); $this->assertEquals(1, $matches->count()); $match = $this->firstMatch($matches); $this->assertEquals('one', $match->getAttribute('id')); // Test match on beginsWith $handler = new QueryPathEventHandler($doc); $handler->find('inside[name^="anti"]'); $matches = $handler->getMatches(); $this->assertEquals(1, $matches->count()); $match = $this->firstMatch($matches); $this->assertEquals('one', $match->getAttribute('id')); // Test match on endsWith $handler = new QueryPathEventHandler($doc); $handler->find('inside[name$="ism"]'); $matches = $handler->getMatches(); $this->assertEquals(1, $matches->count()); $match = $this->firstMatch($matches); $this->assertEquals('one', $match->getAttribute('id')); // Test containsWithSpace $xml = '<?xml version="1.0" ?><test><inside id="one" name="anti dis establishment arian ism"/>Text<inside/></test>'; $doc = new \DomDocument(); $doc->loadXML($xml); $handler = new QueryPathEventHandler($doc); $handler->find('inside[name~="dis"]'); $matches = $handler->getMatches(); $this->assertEquals(1, $matches->count()); $match = $this->firstMatch($matches); $this->assertEquals('one', $match->getAttribute('id')); // Test containsWithHyphen $xml = '<?xml version="1.0" ?><test><inside id="one" name="en-us"/>Text<inside/></test>'; $doc = new \DomDocument(); $doc->loadXML($xml); $handler = new QueryPathEventHandler($doc); $handler->find('inside[name|="us"]'); $matches = $handler->getMatches(); $this->assertEquals(1, $matches->count()); $match = $this->firstMatch($matches); $this->assertEquals('one', $match->getAttribute('id')); } public function testPseudoClassLang() { $xml = '<?xml version="1.0" ?><test><inside lang="en-us" id="one"/>Text<inside/></test>'; $doc = new \DomDocument(); $doc->loadXML($xml); $handler = new QueryPathEventHandler($doc); $handler->find(':lang(en-us)'); $matches = $handler->getMatches(); $this->assertEquals(1, $matches->count()); $match = $this->firstMatch($matches); $this->assertEquals('one', $match->getAttribute('id')); $handler = new QueryPathEventHandler($doc); $handler->find('inside:lang(en)'); $matches = $handler->getMatches(); $this->assertEquals(1, $matches->count()); $match = $this->firstMatch($matches); $this->assertEquals('one', $match->getAttribute('id')); $handler = new QueryPathEventHandler($doc); $handler->find('inside:lang(us)'); $matches = $handler->getMatches(); $this->assertEquals(1, $matches->count()); $match = $this->firstMatch($matches); $this->assertEquals('one', $match->getAttribute('id')); $xml = '<?xml version="1.0" ?><test><inside lang="en-us" id="one"/>Text<inside lang="us" id="two"/></test>'; $doc = new \DomDocument(); $doc->loadXML($xml); $handler = new QueryPathEventHandler($doc); $handler->find(':lang(us)'); $matches = $handler->getMatches(); $this->assertEquals(2, $matches->count()); $match = $this->nthMatch($matches, 1); $this->assertEquals('two', $match->getAttribute('id')); $xml = '<?xml version="1.0" ?> <test xmlns="http://aleph-null.tv/xml" xmlns:xml="http://www.w3.org/XML/1998/namespace"> <inside lang="en-us" id="one"/>Text <inside xml:lang="en-us" id="two"/> </test>'; $doc = new \DomDocument(); $doc->loadXML($xml); $handler = new QueryPathEventHandler($doc); $handler->find(':lang(us)'); $matches = $handler->getMatches(); $this->assertEquals(2, $matches->count()); $match = $this->nthMatch($matches, 1); $this->assertEquals('two', $match->getAttribute('id')); } public function testPseudoClassEnabledDisabledChecked() { $xml = '<?xml version="1.0" ?> <test> <inside enabled="enabled" id="one"/>Text <inside disabled="disabled" id="two"/> <inside checked="FOOOOO" id="three"/> </test>'; $doc = new \DomDocument(); $doc->loadXML($xml); $handler = new QueryPathEventHandler($doc); $handler->find(':enabled'); $matches = $handler->getMatches(); $this->assertEquals(1, $matches->count()); $match = $this->firstMatch($matches); $this->assertEquals('one', $match->getAttribute('id')); $handler = new QueryPathEventHandler($doc); $handler->find(':disabled'); $matches = $handler->getMatches(); $this->assertEquals(1, $matches->count()); $match = $this->firstMatch($matches); $this->assertEquals('two', $match->getAttribute('id')); $handler = new QueryPathEventHandler($doc); $handler->find(':checked()'); $matches = $handler->getMatches(); $this->assertEquals(1, $matches->count()); $match = $this->firstMatch($matches); $this->assertEquals('three', $match->getAttribute('id')); } public function testPseudoClassLink() { $xml = '<?xml version="1.0"?><a><b href="foo"/><c href="foo"/></a>'; $qp = qp($xml, ':link'); $this->assertEquals(2, $qp->size()); } public function testPseudoClassXReset() { $xml = '<?xml version="1.0" ?> <test> <inside enabled="enabled" id="one"/>Text <inside disabled="disabled" id="two"/> <inside checked="FOOOOO" id="three"/> </test>'; $doc = new \DomDocument(); $doc->loadXML($xml); $handler = new QueryPathEventHandler($doc); $handler->find('inside'); $matches = $handler->getMatches(); $this->assertEquals(3, $matches->count()); $handler->find(':x-reset'); $matches = $handler->getMatches(); $this->assertEquals(1, $matches->count()); $this->assertEquals('test', $this->firstMatch($matches)->tagName); } public function testPseudoClassRoot() { $xml = '<?xml version="1.0" ?> <test> <inside enabled="enabled" id="one"/>Text <inside disabled="disabled" id="two"/> <inside checked="FOOOOO" id="three"/> </test>'; $doc = new \DomDocument(); $doc->loadXML($xml); $start = $doc->getElementsByTagName('inside'); // Start "deep in the doc" and traverse backward. $handler = new QueryPathEventHandler($start); $handler->find(':root'); $matches = $handler->getMatches(); $this->assertEquals(1, $matches->count()); $this->assertEquals('test', $this->firstMatch($matches)->tagName); } // Test removed so I can re-declare // listPeerElements as private. public function xtestListPeerElements() { $xml = '<?xml version="1.0" ?> <test> <i class="odd" id="one"/> <i class="even" id="two"/> <i class="odd" id="three"/> <i class="even" id="four"/> <i class="odd" id="five"/> <e class="even" id="six"/> </test>'; $doc = new \DomDocument(); $doc->loadXML($xml); // Test full list $handler = new QueryPathEventHandler($doc); $handler->find('#one'); $matches = $handler->getMatches(); $peers = $handler->listPeerElements($this->firstMatch($matches)); $this->assertEquals(6, count($peers)); } /* public function testChildAtIndex() { $xml = '<?xml version="1.0" ?> <test> <i class="odd" id="one"/> <i class="even" id="two"/> <i class="odd" id="three"/> <i class="even" id="four"/> <i class="odd" id="five"/> <e class="even" id="six"/> </test>'; $doc = new \DomDocument(); $doc->loadXML($xml); // Test full list $handler = new QueryPathEventHandler($doc); $handler->find('test:child-at-index(1)'); $matches = $handler->getMatches(); $this->assertEquals(1, $matches->count()); $this->assertEquals('one', $this->nthMatch($matches, 1)->getAttribute('id')); }*/ public function testPseudoClassNthChild() { $xml = '<?xml version="1.0" ?> <test> <i class="odd" id="one"/> <i class="even" id="two"/> <i class="odd" id="three"/> <i class="even" id="four"/> <i class="odd" id="five"/> <e class="even" id="six"/> </test>'; $doc = new \DomDocument(); $doc->loadXML($xml); // Test full list $handler = new QueryPathEventHandler($doc); $handler->find(':root :even'); $matches = $handler->getMatches(); $this->assertEquals(3, $matches->count()); $this->assertEquals('four', $this->nthMatch($matches, 1)->getAttribute('id')); // Test restricted to specific element $handler = new QueryPathEventHandler($doc); $handler->find('i:even'); $matches = $handler->getMatches(); $this->assertEquals(2, $matches->count()); $this->assertEquals('four', $this->nthMatch($matches, 1)->getAttribute('id')); // Test restricted to specific element, odd this time $handler = new QueryPathEventHandler($doc); $handler->find('i:odd'); $matches = $handler->getMatches(); $this->assertEquals(3, $matches->count()); $this->assertEquals('three', $this->nthMatch($matches, 1)->getAttribute('id')); // Test nth-child(odd) $handler = new QueryPathEventHandler($doc); $handler->find('i:nth-child(odd)'); $matches = $handler->getMatches(); $this->assertEquals(3, $matches->count()); $this->assertEquals('three', $this->nthMatch($matches, 1)->getAttribute('id')); // Test nth-child(2n+1) $handler = new QueryPathEventHandler($doc); $handler->find('i:nth-child(2n+1)'); $matches = $handler->getMatches(); $this->assertEquals(3, $matches->count()); $this->assertEquals('three', $this->nthMatch($matches, 1)->getAttribute('id')); // Test nth-child(2n) (even) $handler = new QueryPathEventHandler($doc); $handler->find('i:nth-child(2n)'); $matches = $handler->getMatches(); $this->assertEquals(2, $matches->count()); $this->assertEquals('four', $this->nthMatch($matches, 1)->getAttribute('id')); // Not totally sure what should be returned here // Test nth-child(-2n) // $handler = new QueryPathEventHandler($doc); // $handler->find('i:nth-child(-2n)'); // $matches = $handler->getMatches(); // $this->assertEquals(2, $matches->count()); // $this->assertEquals('four', $this->nthMatch($matches, 1)->getAttribute('id')); // Test nth-child(2n-1) (odd, equiv to 2n + 1) $handler = new QueryPathEventHandler($doc); $handler->find('i:nth-child(2n-1)'); $matches = $handler->getMatches(); $this->assertEquals(3, $matches->count()); $this->assertEquals('three', $this->nthMatch($matches, 1)->getAttribute('id')); // Test nth-child(4n) (every fourth row) $handler = new QueryPathEventHandler($doc); $handler->find('i:nth-child(4n)'); $matches = $handler->getMatches(); $this->assertEquals(1, $matches->count()); $this->assertEquals('four', $this->nthMatch($matches, 0)->getAttribute('id')); // Test nth-child(4n+1) (first of every four rows) $handler = new QueryPathEventHandler($doc); $handler->find('i:nth-child(4n+1)'); $matches = $handler->getMatches(); // Should match rows one and five $this->assertEquals(2, $matches->count()); $this->assertEquals('five', $this->nthMatch($matches, 1)->getAttribute('id')); // Test nth-child(1) (First row) $handler = new QueryPathEventHandler($doc); $handler->find('i:nth-child(1)'); $matches = $handler->getMatches(); $this->assertEquals(1, $matches->count()); $this->assertEquals('one', $this->firstMatch($matches)->getAttribute('id')); // Test nth-child(0n-0) (Empty list) $handler = new QueryPathEventHandler($doc); $handler->find('i:nth-child(0n-0)'); $matches = $handler->getMatches(); $this->assertEquals(0, $matches->count()); // Test nth-child(-n+3) (First three lines) // $handler = new QueryPathEventHandler($doc); // $handler->find('i:nth-child(-n+3)'); // $matches = $handler->getMatches(); // $this->assertEquals(3, $matches->count()); $xml = '<?xml version="1.0" ?> <test> <i class="odd" id="one"/> <i class="even" id="two"/> <i class="odd" id="three"> <i class="odd" id="inner-one"/> <i class="even" id="inner-two"/> </i> <i class="even" id="four"/> <i class="odd" id="five"/> <e class="even" id="six"/> </test>'; $doc = new \DomDocument(); $doc->loadXML($xml); // Test nested items. $handler = new QueryPathEventHandler($doc); $handler->find('i:nth-child(odd)'); $matches = $handler->getMatches(); $this->assertEquals(4, $matches->count()); $matchIDs = array(); foreach ($matches as $m) { $matchIDs[] = $m->getAttribute('id'); } // $matchIDs = sort($matchIDs); $this->assertEquals(array('one', 'three', 'inner-one', 'five'), $matchIDs); //$this->assertEquals('inner-one', $matches[3]->getAttribute('id')); } public function testPseudoClassOnlyChild() { $xml = '<?xml version="1.0" ?> <test> <i class="odd" id="one"/> </test>'; $doc = new \DomDocument(); $doc->loadXML($xml); // Test single last child. $handler = new QueryPathEventHandler($doc); $handler->find('i:only-child'); $matches = $handler->getMatches(); $this->assertEquals(1, $matches->count()); $this->assertEquals('one', $this->firstMatch($matches)->getAttribute('id')); $xml = '<?xml version="1.0" ?> <test> <i class="odd" id="one"/> <i class="odd" id="two"/> </test>'; $doc = new \DomDocument(); $doc->loadXML($xml); // Test single last child. $handler = new QueryPathEventHandler($doc); $handler->find('i:only-child'); $matches = $handler->getMatches(); $this->assertEquals(0, $matches->count()); //$this->assertEquals('one', $this->firstMatch($matches)->getAttribute('id')); } public function testPseudoClassOnlyOfType() { // TODO: Added this late (it was missing in original test), // and I'm not sure if the assumed behavior is correct. $xml = '<?xml version="1.0" ?> <test> <i class="odd" id="one"/> </test>'; $doc = new \DomDocument(); $doc->loadXML($xml); // Test single last child. $handler = new QueryPathEventHandler($doc); $handler->find('i:only-of-type'); $matches = $handler->getMatches(); $this->assertEquals(1, $matches->count()); $this->assertEquals('one', $this->firstMatch($matches)->getAttribute('id')); $xml = '<?xml version="1.0" ?> <test> <i class="odd" id="one"/> <i class="odd" id="two"/> </test>'; $doc = new \DomDocument(); $doc->loadXML($xml); // Test single last child. $handler = new QueryPathEventHandler($doc); $handler->find('i:only-of-type'); $matches = $handler->getMatches(); $this->assertEquals(0, $matches->count()); } public function testPseudoClassFirstChild() { $xml = '<?xml version="1.0" ?> <test> <i class="odd" id="one"/> <i class="even" id="two"/> <i class="odd" id="three"/> <i class="even" id="four"> <i class="odd" id="inner-one"/> <i class="even" id="inner-two"/> <i class="odd" id="inner-three"/> <i class="even" id="inner-four"/> </i> <i class="odd" id="five"/> <e class="even" id="six"/> </test>'; $doc = new \DomDocument(); $doc->loadXML($xml); // Test single last child. $handler = new QueryPathEventHandler($doc); $handler->find('#four > i:first-child'); $matches = $handler->getMatches(); $this->assertEquals(1, $matches->count()); $this->assertEquals('inner-one', $this->firstMatch($matches)->getAttribute('id')); // Test for two last children $handler = new QueryPathEventHandler($doc); $handler->find('i:first-child'); $matches = $handler->getMatches(); $this->assertEquals(2, $matches->count()); $this->assertEquals('inner-one', $this->nthMatch($matches, 1)->getAttribute('id')); } public function testPseudoClassLastChild() { //print '----' . PHP_EOL; $xml = '<?xml version="1.0" ?> <test> <i class="odd" id="one"/> <i class="even" id="two"/> <i class="odd" id="three"/> <i class="even" id="four"> <i class="odd" id="inner-one"/> <i class="even" id="inner-two"/> <i class="odd" id="inner-three"/> <i class="even" id="inner-four"/> </i> <i class="odd" id="five"/> <e class="even" id="six"/> </test>'; $doc = new \DomDocument(); $doc->loadXML($xml); // Test single last child. $handler = new QueryPathEventHandler($doc); $handler->find('#four > i:last-child'); $matches = $handler->getMatches(); $this->assertEquals(1, $matches->count()); $this->assertEquals('inner-four', $this->nthMatch($matches, 0)->getAttribute('id')); // Test for two last children $handler = new QueryPathEventHandler($doc); $handler->find('i:last-child'); $matches = $handler->getMatches(); $this->assertEquals(2, $matches->count()); $this->assertEquals('inner-four', $this->nthMatch($matches, 0)->getAttribute('id')); $this->assertEquals('five', $this->nthMatch($matches, 1)->getAttribute('id')); } public function testPseudoClassNthLastChild() { $xml = '<?xml version="1.0" ?> <test> <i class="odd" id="one"/> <i class="even" id="two"/> <i class="odd" id="three"/> <i class="even" id="four"> <i class="odd" id="inner-one"/> <i class="even" id="inner-two"/> <i class="odd" id="inner-three"/> <i class="even" id="inner-four"/> </i> <i class="odd" id="five"/> <e class="even" id="six"/> </test>'; $doc = new \DomDocument(); $doc->loadXML($xml); // Test alternate rows from the end. $handler = new QueryPathEventHandler($doc); $handler->find('#four > i:nth-last-child(odd)'); $matches = $handler->getMatches(); $this->assertEquals(2, $matches->count()); $this->assertEquals('inner-two', $this->nthMatch($matches, 0)->getAttribute('id')); $this->assertEquals('inner-four', $this->nthMatch($matches, 1)->getAttribute('id')); // According to spec, this should be last two elements. $handler = new QueryPathEventHandler($doc); $handler->find('#four > i:nth-last-child(-1n+2)'); $matches = $handler->getMatches(); //print $this->firstMatch($matches)->getAttribute('id'); $this->assertEquals(2, $matches->count()); $this->assertEquals('inner-three', $this->nthMatch($matches, 0)->getAttribute('id')); $this->assertEquals('inner-four', $this->nthMatch($matches, 1)->getAttribute('id')); } public function testPseudoClassFirstOfType() { $xml = '<?xml version="1.0" ?> <test> <n class="odd" id="one"/> <i class="even" id="two"/> <i class="odd" id="three"/> </test>'; $doc = new \DomDocument(); $doc->loadXML($xml); // Test alternate rows from the end. $handler = new QueryPathEventHandler($doc); $handler->find('i:first-of-type(odd)'); $matches = $handler->getMatches(); $this->assertEquals(1, $matches->count()); $this->assertEquals('two', $this->firstMatch($matches)->getAttribute('id')); } public function testPseudoClassNthFirstOfType() { $xml = '<?xml version="1.0" ?> <test> <n class="odd" id="one"/> <i class="even" id="two"/> <i class="odd" id="three"/> </test>'; $doc = new \DomDocument(); $doc->loadXML($xml); // Test alternate rows from the end. $handler = new QueryPathEventHandler($doc); $handler->find('i:first-of-type(1)'); $matches = $handler->getMatches(); $this->assertEquals(1, $matches->count()); $this->assertEquals('two', $this->firstMatch($matches)->getAttribute('id')); } public function testPseudoClassLastOfType() { $xml = '<?xml version="1.0" ?> <test> <n class="odd" id="one"/> <i class="even" id="two"/> <i class="odd" id="three"/> </test>'; $doc = new \DomDocument(); $doc->loadXML($xml); // Test alternate rows from the end. $handler = new QueryPathEventHandler($doc); $handler->find('i:last-of-type(odd)'); $matches = $handler->getMatches(); $this->assertEquals(1, $matches->count()); $this->assertEquals('three', $this->firstMatch($matches)->getAttribute('id')); } public function testPseudoNthClassLastOfType() { $xml = '<?xml version="1.0" ?> <test> <n class="odd" id="one"/> <i class="even" id="two"/> <i class="odd" id="three"/> </test>'; $doc = new \DomDocument(); $doc->loadXML($xml); // Test alternate rows from the end. $handler = new QueryPathEventHandler($doc); $handler->find('i:nth-last-of-type(1)'); $matches = $handler->getMatches(); $this->assertEquals(1, $matches->count()); $this->assertEquals('three', $this->firstMatch($matches)->getAttribute('id')); // Issue #56: an+b not working. $xml = '<?xml version="1.0"?> <root> <div>I am the first div.</div> <div>I am the second div.</div> <div>I am the third div.</div> <div>I am the fourth div.</div> <div id="five">I am the fifth div.</div> <div id="six">I am the sixth div.</div> <div id="seven">I am the seventh div.</div> </root>'; $doc = new \DomDocument(); $doc->loadXML($xml); $handler = new QueryPathEventHandler($doc); $handler->find('div:nth-last-of-type(-n+3)'); $matches = $handler->getMatches(); $this->assertEquals(3, $matches->count()); $this->assertEquals('five', $this->firstMatch($matches)->getAttribute('id')); } public function testPseudoClassEmpty() { $xml = '<?xml version="1.0" ?> <test> <n class="odd" id="one"/> <i class="even" id="two"></i> </test>'; $doc = new \DomDocument(); $doc->loadXML($xml); $handler = new QueryPathEventHandler($doc); $handler->find('n:empty'); $matches = $handler->getMatches(); $this->assertEquals(1, $matches->count()); $this->assertEquals('one', $this->firstMatch($matches)->getAttribute('id')); $handler = new QueryPathEventHandler($doc); $handler->find('i:empty'); $matches = $handler->getMatches(); $this->assertEquals(1, $matches->count()); $this->assertEquals('two', $this->firstMatch($matches)->getAttribute('id')); } public function testPseudoClassFirst() { $xml = '<?xml version="1.0" ?> <test> <i class="odd" id="one"/> <i class="even" id="two"/> <i class="odd" id="three"/> </test>'; $doc = new \DomDocument(); $doc->loadXML($xml); // Test alternate rows from the end. $handler = new QueryPathEventHandler($doc); $handler->find('i:first'); $matches = $handler->getMatches(); $this->assertEquals(1, $matches->count()); $this->assertEquals('one', $this->firstMatch($matches)->getAttribute('id')); } public function testPseudoClassLast() { $xml = '<?xml version="1.0" ?> <test> <i class="odd" id="one"/> <i class="even" id="two"/> <i class="odd" id="three"/> </test>'; $doc = new \DomDocument(); $doc->loadXML($xml); // Test alternate rows from the end. $handler = new QueryPathEventHandler($doc); $handler->find('i:last'); $matches = $handler->getMatches(); $this->assertEquals(1, $matches->count()); $this->assertEquals('three', $this->firstMatch($matches)->getAttribute('id')); } public function testPseudoClassGT() { $xml = '<?xml version="1.0" ?> <test> <i class="odd" id="one"/> <i class="even" id="two"/> <i class="odd" id="three"/> </test>'; $doc = new \DomDocument(); $doc->loadXML($xml); // Test alternate rows from the end. $handler = new QueryPathEventHandler($doc); $handler->find('i:gt(1)'); $matches = $handler->getMatches(); $this->assertEquals(2, $matches->count()); $this->assertEquals('two', $this->firstMatch($matches)->getAttribute('id')); } public function testPseudoClassLT() { $xml = '<?xml version="1.0" ?> <test> <i class="odd" id="one"/> <i class="even" id="two"/> <i class="odd" id="three"/> </test>'; $doc = new \DomDocument(); $doc->loadXML($xml); // Test alternate rows from the end. $handler = new QueryPathEventHandler($doc); $handler->find('i:lt(3)'); $matches = $handler->getMatches(); $this->assertEquals(2, $matches->count()); $this->assertEquals('one', $this->nthMatch($matches,0)->getAttribute('id')); $this->assertEquals('two', $this->nthMatch($matches,1)->getAttribute('id')); } public function testPseudoClassNTH() { $xml = '<?xml version="1.0" ?> <test> <i class="odd" id="one"/> <i class="even" id="two"/> <i class="odd" id="three"/> </test>'; $doc = new \DomDocument(); $doc->loadXML($xml); $handler = new QueryPathEventHandler($doc); $handler->find('i:nth(2)'); $matches = $handler->getMatches(); $this->assertEquals(1, $matches->count()); $this->assertEquals('two', $this->firstMatch($matches)->getAttribute('id')); $handler = new QueryPathEventHandler($doc); $handler->find('i:eq(2)'); $matches = $handler->getMatches(); $this->assertEquals(1, $matches->count()); $this->assertEquals('two', $this->firstMatch($matches)->getAttribute('id')); } public function testPseudoClassNthOfType() { $xml = '<?xml version="1.0" ?> <test> <i class="odd" id="one"/> <i class="even" id="two"/> <i class="odd" id="three"/> </test>'; $doc = new \DomDocument(); $doc->loadXML($xml); $handler = new QueryPathEventHandler($doc); $handler->find('i:nth-of-type(2)'); $matches = $handler->getMatches(); $this->assertEquals(1, $matches->count()); $this->assertEquals('two', $this->firstMatch($matches)->getAttribute('id')); } public function testPseudoClassFormElements() { $form = array('text', 'radio', 'checkbox', 'button', 'password'); $xml = '<?xml version="1.0" ?> <test> <input type="%s" class="odd" id="one"/> </test>'; foreach ($form as $item) { $doc = new \DomDocument(); $doc->loadXML(sprintf($xml, $item)); $handler = new QueryPathEventHandler($doc); $handler->find(':' . $item); $matches = $handler->getMatches(); $this->assertEquals(1, $matches->count()); $this->assertEquals('one', $this->firstMatch($matches)->getAttribute('id')); } } public function testPseudoClassHeader() { $xml = '<?xml version="1.0" ?> <test> <h1 class="odd" id="one"/> <h2 class="even" id="two"/> <h6 class="odd" id="three"/> </test>'; $doc = new \DomDocument(); $doc->loadXML($xml); $handler = new QueryPathEventHandler($doc); $handler->find('test :header'); $matches = $handler->getMatches(); $this->assertEquals(3, $matches->count()); $this->assertEquals('three', $this->nthMatch($matches, 2)->getAttribute('id')); } public function testPseudoClassContains() { $xml = '<?xml version="1.0" ?> <test> <p id="one">This is text.</p> <p id="two"><i>More text</i></p> </test>'; $doc = new \DomDocument(); $doc->loadXML($xml); $handler = new QueryPathEventHandler($doc); $handler->find('p:contains(This is text.)'); $matches = $handler->getMatches(); $this->assertEquals(1, $matches->count()); $this->assertEquals('one', $this->firstMatch($matches)->getAttribute('id')); $handler = new QueryPathEventHandler($doc); $handler->find('* :contains(More text)'); $matches = $handler->getMatches(); $this->assertEquals(2, $matches->count(), 'Matches two instance of same text?'); $this->assertEquals('two', $this->firstMatch($matches)->getAttribute('id')); $handler = new QueryPathEventHandler($doc); $handler->find('p:contains("This is text.")'); $matches = $handler->getMatches(); $this->assertEquals(1, $matches->count(), 'Quoted text matches unquoted pcdata'); $this->assertEquals('one', $this->firstMatch($matches)->getAttribute('id')); $handler = new QueryPathEventHandler($doc); $handler->find('p:contains(\\\'This is text.\\\')'); $matches = $handler->getMatches(); $this->assertEquals(1, $matches->count(), 'One match for quoted string.'); $this->assertEquals('one', $this->firstMatch($matches)->getAttribute('id')); // Test for issue #32 $handler = new QueryPathEventHandler($doc); $handler->find('p:contains(text)'); $matches = $handler->getMatches(); $this->assertEquals(2, $matches->count(), 'Two matches for fragment of string.'); $this->assertEquals('one', $this->firstMatch($matches)->getAttribute('id')); } public function testPseudoClassContainsExactly() { $xml = '<?xml version="1.0" ?> <test> <p id="one">This is text.</p> <p id="two"><i>More text</i></p> </test>'; $doc = new \DomDocument(); $doc->loadXML($xml); $handler = new QueryPathEventHandler($doc); $handler->find('p:contains(This is text.)'); $matches = $handler->getMatches(); $this->assertEquals(1, $matches->count()); $this->assertEquals('one', $this->firstMatch($matches)->getAttribute('id')); $handler = new QueryPathEventHandler($doc); $handler->find('* :contains(More text)'); $matches = $handler->getMatches(); $this->assertEquals(2, $matches->count(), 'Matches two instance of same text.'); $this->assertEquals('two', $this->firstMatch($matches)->getAttribute('id')); $handler = new QueryPathEventHandler($doc); $handler->find('p:contains("This is text.")'); $matches = $handler->getMatches(); $this->assertEquals(1, $matches->count(), 'Quoted text matches unquoted pcdata'); $this->assertEquals('one', $this->firstMatch($matches)->getAttribute('id')); $handler = new QueryPathEventHandler($doc); $handler->find('p:contains(\\\'This is text.\\\')'); $matches = $handler->getMatches(); $this->assertEquals(1, $matches->count(), 'One match for quoted string.'); $this->assertEquals('one', $this->firstMatch($matches)->getAttribute('id')); } public function testPseudoClassHas() { $xml = '<?xml version="1.0" ?> <test> <outer id="one"> <inner/> </outer> <outer id="two"/> </test>'; $doc = new \DomDocument(); $doc->loadXML($xml); $handler = new QueryPathEventHandler($doc); $handler->find('outer:has(inner)'); $matches = $handler->getMatches(); $this->assertEquals(1, $matches->count()); $this->assertEquals('one', $this->firstMatch($matches)->getAttribute('id')); } public function testPseudoClassNot() { $xml = '<?xml version="1.0" ?> <test> <outer id="one"> <inner/> </outer> <outer id="two" class="notMe"/> </test>'; $doc = new \DomDocument(); $doc->loadXML($xml); $handler = new QueryPathEventHandler($doc); $handler->find('outer:not(#one)'); $matches = $handler->getMatches(); $this->assertEquals(1, $matches->count()); $this->assertEquals('two', $this->firstMatch($matches)->getAttribute('id')); $handler = new QueryPathEventHandler($doc); $handler->find('outer:not(inner)'); $matches = $handler->getMatches(); $this->assertEquals(1, $matches->count()); $this->assertEquals('two', $this->firstMatch($matches)->getAttribute('id')); $handler = new QueryPathEventHandler($doc); $handler->find('outer:not(.notMe)'); $matches = $handler->getMatches(); $this->assertEquals(1, $matches->count()); $this->assertEquals('one', $this->firstMatch($matches)->getAttribute('id')); } public function testPseudoElement() { $xml = '<?xml version="1.0" ?> <test> <outer id="one">Texts More text</outer> <outer id="two" class="notMe"/> </test>'; $doc = new \DomDocument(); $doc->loadXML($xml); $handler = new QueryPathEventHandler($doc); $handler->find('outer::first-letter'); $matches = $handler->getMatches(); $this->assertEquals(1, $matches->count()); $this->assertEquals('T', $this->firstMatch($matches)->textContent); $handler = new QueryPathEventHandler($doc); $handler->find('outer::first-line'); $matches = $handler->getMatches(); $this->assertEquals(1, $matches->count()); $this->assertEquals('Texts', $this->firstMatch($matches)->textContent); } public function testAdjacent() { $xml = '<?xml version="1.0" ?> <test> <li id="one"/><li id="two"/><li id="three"> <li id="inner-one"> <li id="inner-inner-one"/> <li id="inner-inner-one"/> </li> <li id="inner-two"/> </li> <li id="four"/> <li id="five"/> </test>'; $doc = new \DomDocument(); $doc->loadXML($xml); $handler = new QueryPathEventHandler($doc); $handler->find('#one + li'); $matches = $handler->getMatches(); $this->assertEquals(1, $matches->count()); $this->assertEquals('two', $this->firstMatch($matches)->getAttribute('id')); // Tell it to ignore whitespace nodes. $doc->loadXML($xml, LIBXML_NOBLANKS); // Test with whitespace sensitivity weakened. $handler = new QueryPathEventHandler($doc); $handler->find('#four + li'); $matches = $handler->getMatches(); $this->assertEquals(1, $matches->count()); $this->assertEquals('five', $this->firstMatch($matches)->getAttribute('id')); } public function testAnotherSelector() { $xml = '<?xml version="1.0" ?> <test> <li id="one"/><li id="two"/><li id="three"> <li id="inner-one"> <li id="inner-inner-one"/> <li id="inner-inner-one"/> </li> <li id="inner-two"/> </li> <li id="four"/> <li id="five"/> </test>'; $doc = new \DomDocument(); $doc->loadXML($xml); $handler = new QueryPathEventHandler($doc); $handler->find('#one, #two'); $matches = $handler->getMatches(); //print $this->firstMatch($matches)->getAttribute('id') . PHP_EOL; $this->assertEquals(2, $matches->count()); $this->assertEquals('two', $this->nthMatch($matches, 1)->getAttribute('id')); } public function testSibling() { $xml = '<?xml version="1.0" ?> <test> <li id="one"/><li id="two"/><li id="three"> <li id="inner-one"> <li id="inner-inner-one"/> <il id="inner-inner-two"/> <li id="dont-match-me"/> </li> <li id="inner-two"/> </li> <li id="four"/> <li id="five"/> </test>'; $doc = new \DomDocument(); $doc->loadXML($xml); $handler = new QueryPathEventHandler($doc); $handler->find('#one ~ li'); $matches = $handler->getMatches(); //print $this->firstMatch($matches)->getAttribute('id') . PHP_EOL; $this->assertEquals(4, $matches->count()); $this->assertEquals('three', $this->nthMatch($matches, 1)->getAttribute('id')); $handler = new QueryPathEventHandler($doc); $handler->find('#two ~ li'); $matches = $handler->getMatches(); //print $this->firstMatch($matches)->getAttribute('id') . PHP_EOL; $this->assertEquals(3, $matches->count()); //$this->assertEquals('three', $this->nthMatch($matches, 1)->getAttribute('id')); $handler = new QueryPathEventHandler($doc); $handler->find('#inner-one > li ~ il'); $matches = $handler->getMatches(); //print $this->firstMatch($matches)->getAttribute('id') . PHP_EOL; $this->assertEquals(1, $matches->count()); $this->assertEquals('inner-inner-two', $this->firstMatch($matches)->getAttribute('id')); } public function testAnyDescendant() { $xml = '<?xml version="1.0" ?> <test> <li id="one"/><li id="two"/><li id="three"> <li id="inner-one" class="foo"> <li id="inner-inner-one" class="foo"/> <il id="inner-inner-two"/> <li id="dont-match-me"/> </li> <li id="inner-two"/> </li> <li id="four"/> <li id="five"/> </test>'; $doc = new \DomDocument(); $doc->loadXML($xml); $handler = new QueryPathEventHandler($doc); $handler->find('*'); $matches = $handler->getMatches(); $this->assertEquals(11, $matches->count()); $handler = new QueryPathEventHandler($doc); $handler->find('*.foo'); $matches = $handler->getMatches(); $this->assertEquals(2, $matches->count()); $this->assertEquals('inner-inner-one', $this->nthMatch($matches, 1)->getAttribute('id')); $handler = new QueryPathEventHandler($doc); $handler->find('test > li *.foo'); $matches = $handler->getMatches(); $this->assertEquals(2, $matches->count()); $this->assertEquals('inner-inner-one', $this->nthMatch($matches, 1)->getAttribute('id')); } }