/** * undocumented function * * @param XPathExpr $xpath * @param mixed $expr * @param Boolean $last * @param Boolean $addNameTest * * @return XPathExpr */ protected function _xpath_nth_child($xpath, $expr, $last = false, $addNameTest = true) { list($a, $b) = $this->parseSeries($expr); if (!$a && !$b && !$last) { // a=0 means nothing is returned... $xpath->addCondition('false() and position() = 0'); return $xpath; } if ($addNameTest) { $xpath->addNameTest(); } $xpath->addStarPrefix(); if ($a == 0) { if ($last) { $b = sprintf('last() - %s', $b - 1); } $xpath->addCondition(sprintf('position() = %s', $b)); return $xpath; } if ($a < 0) { if ($b < 1) { $xpath->addCondition('false()'); return $xpath; } $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); } $xpath->addCondition(implode(' and ', $conditions)); return $xpath; /* FIXME: 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 */ }
/** * undocumented function * * @param XPathExpr $xpath * @param mixed $expr * @param Boolean $last * @param Boolean $addNameTest * * @return XPathExpr */ protected function _xpath_nth_child($xpath, $expr, $last = false, $addNameTest = true) { list($a, $b) = $this->parseSeries($expr); if (!$a && !$b && !$last) { // a=0 means nothing is returned... $xpath->addCondition('false() and position() = 0'); return $xpath; } if ($addNameTest) { $xpath->addNameTest(); } $xpath->addStarPrefix(); if ($a == 0) { if ($last) { $b = sprintf('last() - %s', $b); } $xpath->addCondition(sprintf('position() = %s', $b)); return $xpath; } if ($last) { // FIXME: I'm not sure if this is right $a = -$a; $b = -$b; } if ($b > 0) { $bNeg = -$b; } else { $bNeg = sprintf('+%s', -$b); } if ($a != 1) { $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; /* FIXME: 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 */ }
/** * Sets the XPath expression to be the only child. * * @param XPathExpr $xpath The XPath expression * * @return XPathExpr The modified expression */ protected function xpath_only_child($xpath) { $xpath->addNameTest(); $xpath->addStarPrefix(); $xpath->addCondition('last() = 1'); return $xpath; }