/** @dataProvider getParseSeriesExceptionTestData */ public function testParseSeriesException($series) { $parser = new Parser(); $selectors = $parser->parse(sprintf(':nth-child(%s)', $series)); $this->assertCount(1, $selectors); /** @var FunctionNode $function */ $function = $selectors[0]->getTree(); $this->setExpectedException('Symfony\\Component\\CssSelector\\Exception\\SyntaxErrorException'); Parser::parseSeries($function->getArguments()); }
/** * @param XPathExpr $xpath * @param FunctionNode $function * @param boolean $last * @param boolean $addNameTest * * @return XPathExpr * * @throws ExpressionErrorException */ public function translateNthChild(XPathExpr $xpath, FunctionNode $function, $last = false, $addNameTest = true) { try { list($a, $b) = Parser::parseSeries($function->getArguments()); } catch (SyntaxErrorException $e) { throw new ExpressionErrorException(sprintf('Invalid series: %s', implode(', ', $function->getArguments())), 0, $e); } $xpath->addStarPrefix(); if ($addNameTest) { $xpath->addNameTest(); } if (0 === $a) { return $xpath->addCondition('position() = ' . ($last ? 'last() - ' . $b : $b)); } if ($last) { // todo: verify if this is right $a = -$a; $b = -$b; } $conditions = 1 === $a ? array() : array(sprintf('(position() %s) mod %s = 0', $b > 0 ? (string) -$b : '+' . -$b, $a)); if ($b >= 0) { $conditions[] = 'position() >= ' . $b; } elseif ($last) { $conditions[] = sprintf('position() < (last() %s)', $b); } // todo: handle an+b, odd, even // an+b means every-a, plus b, e.g., 2n+1 means odd // 0n+b means b // n+0 means a=1, i.e., all elements // an means every a elements, i.e., 2n means even // -n means -1n // -1n+6 means elements 6 and previous return empty($conditions) ? $xpath : $xpath->addCondition(implode(' and ', $conditions)); }
/** * @param XPathExpr $xpath * @param FunctionNode $function * @param bool $last * @param bool $addNameTest * * @return XPathExpr * * @throws ExpressionErrorException */ public function translateNthChild(XPathExpr $xpath, FunctionNode $function, $last = false, $addNameTest = true) { try { list($a, $b) = Parser::parseSeries($function->getArguments()); } catch (SyntaxErrorException $e) { throw new ExpressionErrorException(sprintf('Invalid series: %s', implode(', ', $function->getArguments())), 0, $e); } $xpath->addStarPrefix(); if ($addNameTest) { $xpath->addNameTest(); } if (0 === $a) { return $xpath->addCondition('position() = ' . ($last ? 'last() - ' . ($b - 1) : $b)); } if ($a < 0) { if ($b < 1) { return $xpath->addCondition('false()'); } $sign = '<='; } else { $sign = '>='; } $expr = 'position()'; if ($last) { $expr = 'last() - ' . $expr; $b--; } if (0 !== $b) { $expr .= ' - ' . $b; } $conditions = array(sprintf('%s %s 0', $expr, $sign)); if (1 !== $a && -1 !== $a) { $conditions[] = sprintf('(%s) mod %d = 0', $expr, $a); } return $xpath->addCondition(implode(' and ', $conditions)); // todo: handle an+b, odd, even // an+b means every-a, plus b, e.g., 2n+1 means odd // 0n+b means b // n+0 means a=1, i.e., all elements // an means every a elements, i.e., 2n means even // -n means -1n // -1n+6 means elements 6 and previous }