Merge branch '2.1' into 2.2
* 2.1: [CssSelector] Fix :nth-last-child() translation Fix Crawler::children() to not trigger a notice for childless node
This commit is contained in:
commit
7b5e68053f
@ -100,43 +100,46 @@ class FunctionNode implements NodeInterface
|
|||||||
$xpath->addStarPrefix();
|
$xpath->addStarPrefix();
|
||||||
if ($a == 0) {
|
if ($a == 0) {
|
||||||
if ($last) {
|
if ($last) {
|
||||||
$b = sprintf('last() - %s', $b);
|
$b = sprintf('last() - %s', $b - 1);
|
||||||
}
|
}
|
||||||
$xpath->addCondition(sprintf('position() = %s', $b));
|
$xpath->addCondition(sprintf('position() = %s', $b));
|
||||||
|
|
||||||
return $xpath;
|
return $xpath;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($a < 0) {
|
||||||
|
if ($b < 1) {
|
||||||
|
$xpath->addCondition('false()');
|
||||||
|
|
||||||
|
return $xpath;
|
||||||
|
}
|
||||||
|
|
||||||
|
$sign = '<=';
|
||||||
|
} else {
|
||||||
|
$sign = '>=';
|
||||||
|
}
|
||||||
|
|
||||||
|
$expr = 'position()';
|
||||||
|
|
||||||
if ($last) {
|
if ($last) {
|
||||||
// FIXME: I'm not sure if this is right
|
$expr = 'last() - '.$expr;
|
||||||
$a = -$a;
|
$b--;
|
||||||
$b = -$b;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($b > 0) {
|
if (0 !== $b) {
|
||||||
$bNeg = -$b;
|
$expr .= ' - '.$b;
|
||||||
} else {
|
}
|
||||||
$bNeg = sprintf('+%s', -$b);
|
|
||||||
|
$conditions = array(sprintf('%s %s 0', $expr, $sign));
|
||||||
|
|
||||||
|
if (1 !== $a && -1 !== $a) {
|
||||||
|
$conditions[] = sprintf('(%s) mod %d = 0', $expr, $a);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($a != 1) {
|
$xpath->addCondition(implode(' and ', $conditions));
|
||||||
$expr = array(sprintf('(position() %s) mod %s = 0', $bNeg, $a));
|
|
||||||
} else {
|
|
||||||
$expr = array();
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($b >= 0) {
|
|
||||||
$expr[] = sprintf('position() >= %s', $b);
|
|
||||||
} elseif ($b < 0 && $last) {
|
|
||||||
$expr[] = sprintf('position() < (last() %s)', $b);
|
|
||||||
}
|
|
||||||
$expr = implode($expr, ' and ');
|
|
||||||
|
|
||||||
if ($expr) {
|
|
||||||
$xpath->addCondition($expr);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $xpath;
|
return $xpath;
|
||||||
|
|
||||||
/* FIXME: handle an+b, odd, even
|
/* FIXME: handle an+b, odd, even
|
||||||
an+b means every-a, plus b, e.g., 2n+1 means odd
|
an+b means every-a, plus b, e.g., 2n+1 means odd
|
||||||
0n+b means b
|
0n+b means b
|
||||||
|
@ -54,7 +54,7 @@ class CssSelectorTest extends \PHPUnit_Framework_TestCase
|
|||||||
array('h1', "h1"),
|
array('h1', "h1"),
|
||||||
array('foo|h1', "foo:h1"),
|
array('foo|h1', "foo:h1"),
|
||||||
array('h1, h2, h3', "h1 | h2 | h3"),
|
array('h1, h2, h3', "h1 | h2 | h3"),
|
||||||
array('h1:nth-child(3n+1)', "*/*[name() = 'h1' and ((position() -1) mod 3 = 0 and position() >= 1)]"),
|
array('h1:nth-child(3n+1)', "*/*[name() = 'h1' and (position() - 1 >= 0 and (position() - 1) mod 3 = 0)]"),
|
||||||
array('h1 > p', "h1/p"),
|
array('h1 > p', "h1/p"),
|
||||||
array('h1#foo', "h1[@id = 'foo']"),
|
array('h1#foo', "h1[@id = 'foo']"),
|
||||||
array('h1.foo', "h1[contains(concat(' ', normalize-space(@class), ' '), ' foo ')]"),
|
array('h1.foo', "h1[contains(concat(' ', normalize-space(@class), ' '), ' foo ')]"),
|
||||||
|
@ -36,12 +36,12 @@ class FunctionNodeTest extends \PHPUnit_Framework_TestCase
|
|||||||
// h1:nth-child(odd)
|
// h1:nth-child(odd)
|
||||||
$element2 = new ElementNode('*', new Token('Symbol', 'odd', -1));
|
$element2 = new ElementNode('*', new Token('Symbol', 'odd', -1));
|
||||||
$function = new FunctionNode($element, ':', 'nth-child', $element2);
|
$function = new FunctionNode($element, ':', 'nth-child', $element2);
|
||||||
$this->assertEquals("*/*[name() = 'h1' and ((position() -1) mod 2 = 0 and position() >= 1)]", (string) $function->toXpath(), '->toXpath() returns the xpath representation of the node');
|
$this->assertEquals("*/*[name() = 'h1' and (position() - 1 >= 0 and (position() - 1) mod 2 = 0)]", (string) $function->toXpath(), '->toXpath() returns the xpath representation of the node');
|
||||||
|
|
||||||
// h1:nth-child(even)
|
// h1:nth-child(even)
|
||||||
$element2 = new ElementNode('*', new Token('Symbol', 'even', -1));
|
$element2 = new ElementNode('*', new Token('Symbol', 'even', -1));
|
||||||
$function = new FunctionNode($element, ':', 'nth-child', $element2);
|
$function = new FunctionNode($element, ':', 'nth-child', $element2);
|
||||||
$this->assertEquals("*/*[name() = 'h1' and ((position() +0) mod 2 = 0 and position() >= 0)]", (string) $function->toXpath(), '->toXpath() returns the xpath representation of the node');
|
$this->assertEquals("*/*[name() = 'h1' and (position() >= 0 and (position()) mod 2 = 0)]", (string) $function->toXpath(), '->toXpath() returns the xpath representation of the node');
|
||||||
|
|
||||||
// h1:nth-child(n)
|
// h1:nth-child(n)
|
||||||
$element2 = new ElementNode('*', new Token('Symbol', 'n', -1));
|
$element2 = new ElementNode('*', new Token('Symbol', 'n', -1));
|
||||||
@ -51,12 +51,12 @@ class FunctionNodeTest extends \PHPUnit_Framework_TestCase
|
|||||||
// h1:nth-child(3n+1)
|
// h1:nth-child(3n+1)
|
||||||
$element2 = new ElementNode('*', new Token('Symbol', '3n+1', -1));
|
$element2 = new ElementNode('*', new Token('Symbol', '3n+1', -1));
|
||||||
$function = new FunctionNode($element, ':', 'nth-child', $element2);
|
$function = new FunctionNode($element, ':', 'nth-child', $element2);
|
||||||
$this->assertEquals("*/*[name() = 'h1' and ((position() -1) mod 3 = 0 and position() >= 1)]", (string) $function->toXpath(), '->toXpath() returns the xpath representation of the node');
|
$this->assertEquals("*/*[name() = 'h1' and (position() - 1 >= 0 and (position() - 1) mod 3 = 0)]", (string) $function->toXpath(), '->toXpath() returns the xpath representation of the node');
|
||||||
|
|
||||||
// h1:nth-child(n+1)
|
// h1:nth-child(n+1)
|
||||||
$element2 = new ElementNode('*', new Token('Symbol', 'n+1', -1));
|
$element2 = new ElementNode('*', new Token('Symbol', 'n+1', -1));
|
||||||
$function = new FunctionNode($element, ':', 'nth-child', $element2);
|
$function = new FunctionNode($element, ':', 'nth-child', $element2);
|
||||||
$this->assertEquals("*/*[name() = 'h1' and (position() >= 1)]", (string) $function->toXpath(), '->toXpath() returns the xpath representation of the node');
|
$this->assertEquals("*/*[name() = 'h1' and (position() - 1 >= 0)]", (string) $function->toXpath(), '->toXpath() returns the xpath representation of the node');
|
||||||
|
|
||||||
// h1:nth-child(1)
|
// h1:nth-child(1)
|
||||||
$element2 = new ElementNode('*', new Token('Symbol', '2', -1));
|
$element2 = new ElementNode('*', new Token('Symbol', '2', -1));
|
||||||
@ -66,16 +66,16 @@ class FunctionNodeTest extends \PHPUnit_Framework_TestCase
|
|||||||
// h1:nth-child(2n)
|
// h1:nth-child(2n)
|
||||||
$element2 = new ElementNode('*', new Token('Symbol', '2n', -1));
|
$element2 = new ElementNode('*', new Token('Symbol', '2n', -1));
|
||||||
$function = new FunctionNode($element, ':', 'nth-child', $element2);
|
$function = new FunctionNode($element, ':', 'nth-child', $element2);
|
||||||
$this->assertEquals("*/*[name() = 'h1' and ((position() +0) mod 2 = 0 and position() >= 0)]", (string) $function->toXpath(), '->toXpath() returns the xpath representation of the node');
|
$this->assertEquals("*/*[name() = 'h1' and (position() >= 0 and (position()) mod 2 = 0)]", (string) $function->toXpath(), '->toXpath() returns the xpath representation of the node');
|
||||||
|
|
||||||
// h1:nth-child(-n)
|
// h1:nth-child(-n)
|
||||||
$element2 = new ElementNode('*', new Token('Symbol', '-n', -1));
|
$element2 = new ElementNode('*', new Token('Symbol', '-n', -1));
|
||||||
$function = new FunctionNode($element, ':', 'nth-child', $element2);
|
$function = new FunctionNode($element, ':', 'nth-child', $element2);
|
||||||
$this->assertEquals("*/*[name() = 'h1' and ((position() +0) mod -1 = 0 and position() >= 0)]", (string) $function->toXpath(), '->toXpath() returns the xpath representation of the node');
|
$this->assertEquals("*/*[name() = 'h1' and (false())]", (string) $function->toXpath(), '->toXpath() returns the xpath representation of the node');
|
||||||
|
|
||||||
// h1:nth-last-child(2)
|
// h1:nth-last-child(2)
|
||||||
$function = new FunctionNode($element, ':', 'nth-last-child', 2);
|
$function = new FunctionNode($element, ':', 'nth-last-child', 2);
|
||||||
$this->assertEquals("*/*[name() = 'h1' and (position() = last() - 2)]", (string) $function->toXpath(), '->toXpath() returns the xpath representation of the node');
|
$this->assertEquals("*/*[name() = 'h1' and (position() = last() - 1)]", (string) $function->toXpath(), '->toXpath() returns the xpath representation of the node');
|
||||||
|
|
||||||
// h1:nth-of-type(2)
|
// h1:nth-of-type(2)
|
||||||
$function = new FunctionNode($element, ':', 'nth-of-type', 2);
|
$function = new FunctionNode($element, ':', 'nth-of-type', 2);
|
||||||
@ -83,7 +83,7 @@ class FunctionNodeTest extends \PHPUnit_Framework_TestCase
|
|||||||
|
|
||||||
// h1:nth-last-of-type(2)
|
// h1:nth-last-of-type(2)
|
||||||
$function = new FunctionNode($element, ':', 'nth-last-of-type', 2);
|
$function = new FunctionNode($element, ':', 'nth-last-of-type', 2);
|
||||||
$this->assertEquals("*/h1[position() = last() - 2]", (string) $function->toXpath(), '->toXpath() returns the xpath representation of the node');
|
$this->assertEquals("*/h1[position() = last() - 1]", (string) $function->toXpath(), '->toXpath() returns the xpath representation of the node');
|
||||||
|
|
||||||
/*
|
/*
|
||||||
// h1:not(p)
|
// h1:not(p)
|
||||||
|
@ -432,7 +432,9 @@ class Crawler extends \SplObjectStorage
|
|||||||
throw new \InvalidArgumentException('The current node list is empty.');
|
throw new \InvalidArgumentException('The current node list is empty.');
|
||||||
}
|
}
|
||||||
|
|
||||||
return new static($this->sibling($this->getNode(0)->firstChild), $this->uri);
|
$node = $this->getNode(0)->firstChild;
|
||||||
|
|
||||||
|
return new static($node ? $this->sibling($node) : array(), $this->uri);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -536,6 +536,14 @@ EOF
|
|||||||
} catch (\InvalidArgumentException $e) {
|
} catch (\InvalidArgumentException $e) {
|
||||||
$this->assertTrue(true, '->children() throws an \InvalidArgumentException if the node list is empty');
|
$this->assertTrue(true, '->children() throws an \InvalidArgumentException if the node list is empty');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$crawler = new Crawler('<p></p>');
|
||||||
|
$crawler->filter('p')->children();
|
||||||
|
$this->assertTrue(true, '->children() does not trigger a notice if the node has no children');
|
||||||
|
} catch (\PHPUnit_Framework_Error_Notice $e) {
|
||||||
|
$this->fail('->children() does not trigger a notice if the node has no children');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testParents()
|
public function testParents()
|
||||||
|
Reference in New Issue
Block a user