Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,6 @@ docs/*
doc/*
test/fakepear
vendor/
composer.lock
composer.lock
.phpunit.result.cache
.idea/
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,16 @@
QueryPath Changelog
===========================

# 4.0.3

- Fix for error while getting parent() on HTML root node
- Fix for error while getting parents() on HTML node

# 4.0.2

- Fix for :nth-child(n+B). It now selects B-th and all the following elements
- Refactored relevant PHPUnit Test Suite to use @dataProvider to remove code repetitions

# 4.0.1

- Only define global functions qp(), htmlqp(), and html5qp() if they haven't been defined already.
Expand Down
6 changes: 5 additions & 1 deletion src/CSS/QueryPathEventHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -736,7 +736,11 @@ protected function parseAnB($rule)

// Each of these is legal: 1, -1, and -. '-' is shorthand for -1.
$aVal = trim($rule[0]);
$aVal = ($aVal == '-') ? -1 : (int) $aVal;
if ($aVal === '') {
$aVal = 1;
} else {
$aVal = ($aVal == '-') ? -1 : (int) $aVal;
}

$bVal = ! empty($rule[1]) ? (int) trim($rule[1]) : 0;

Expand Down
4 changes: 2 additions & 2 deletions src/Helpers/QueryFilters.php
Original file line number Diff line number Diff line change
Expand Up @@ -798,7 +798,7 @@ public function parent($selector = null): Query
{
$found = new SplObjectStorage();
foreach ($this->matches as $m) {
while ($m->parentNode->nodeType !== XML_DOCUMENT_NODE) {
while ($m->parentNode && $m->parentNode->nodeType !== XML_DOCUMENT_NODE) {
$m = $m->parentNode;
// Is there any case where parent node is not an element?
if ($m->nodeType === XML_ELEMENT_NODE) {
Expand Down Expand Up @@ -838,7 +838,7 @@ public function parents($selector = null): Query
{
$found = new SplObjectStorage();
foreach ($this->matches as $m) {
while ($m->parentNode->nodeType !== XML_DOCUMENT_NODE) {
while ($m->parentNode && $m->parentNode->nodeType !== XML_DOCUMENT_NODE) {
$m = $m->parentNode;
// Is there any case where parent node is not an element?
if ($m->nodeType === XML_ELEMENT_NODE) {
Expand Down
121 changes: 33 additions & 88 deletions tests/QueryPath/CSS/QueryPathEventHandlerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -615,7 +615,31 @@ public function testChildAtIndex() {
$this->assertEquals('one', $this->nthMatch($matches, 1)->getAttribute('id'));
}*/

public function testPseudoClassNthChild()
public function nthChildProvider(): array
{
return [
[':root :even', 3, 'four' ], // full list
['i:even', 2, 'four' ], // restricted to specific element
['i:odd', 3, 'three' ], // restricted to specific element, odd this time
['i:nth-child(odd)', 3, 'three' ], // odd
['i:nth-child(2n+1)', 3, 'three' ], // odd, equiv to 2n + 1
['i:nth-child(2n-1)', 3, 'three' ], // odd, equiv to 2n + 1
['i:nth-child(2n)', 2, 'four' ], // even
//['i:nth-child(-2n)', 2, 'four' ], // Not totally sure what should be returned here
['i:nth-child(4n)', 1, 'four', 0], // every fourth row
['i:nth-child(4n+1)', 2, 'five' ], // first of every four rows
['i:nth-child(1)', 1, 'one', 0 ], // first row
['i:nth-child(0n-0)', 0, null ], // empty list
['i:nth-child(n+3)', 3, 'four' ], // third+ lines
//['i:nth-child(0n+3)', 1, 'three' ], // third element in a group of siblings
//['i:nth-child(-n+3)', 3, 'three' ], // first three lines
];
}

/**
* @dataProvider nthChildProvider
*/
public function testPseudoClassNthChild($selector, $matchesCount, $matchId, $matchIndex = 1)
{
$xml = '<?xml version="1.0" ?>
<test>
Expand All @@ -631,95 +655,16 @@ public function testPseudoClassNthChild()

// 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)');
$handler->find($selector);
$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());
$this->assertEquals($matchesCount, $matches->count());
if ($matchesCount) {
$this->assertEquals($matchId, $this->nthMatch($matches, $matchIndex)->getAttribute('id'));
}
}

public function testPseudoClassNthChildNested()
{
$xml = '<?xml version="1.0" ?>
<test>
<i class="odd" id="one"/>
Expand Down
2 changes: 2 additions & 0 deletions tests/QueryPath/DOMQueryTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -1676,6 +1676,8 @@ public function testParent()
$this->assertEquals('root', qp($file, 'unary')->parent()->tag());
$this->assertEquals('root', qp($file, 'li')->parent('root')->tag());
$this->assertEquals(2, qp($file, 'li')->parent()->count());
$this->assertEquals(0, qp(DATA_HTML_FILE, 'html')->parent()->count());
$this->assertEquals(2, qp(DATA_HTML_FILE, 'table')->parents()->count());
}

public function testClosest()
Expand Down