8000 Several selector fixes by Mellthas · Pull Request #3059 · dompdf/dompdf · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

Several selector fixes #3059

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Nov 14, 2022
Merged
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
74 changes: 37 additions & 37 deletions src/Css/Stylesheet.php
Original file line number Diff line number Diff line change
Expand Up @@ -441,9 +441,6 @@ private function _css_selector_to_xpath(string 10000 $selector, bool $first_pass = fal
// Will contain :before and :after
$pseudo_elements = [];

// Will contain :link, etc
$pseudo_classes = [];

// Parse the selector
//$s = preg_split("/([ :>.#+])/", $selector, -1, PREG_SPLIT_DELIM_CAPTURE);

Expand Down Expand Up @@ -525,14 +522,24 @@ private function _css_selector_to_xpath(string $selector, bool $first_pass = fal
$tok = "";
break;

case ".":
case "#":
// All elements matching the current token with a class/id equal to
// the _next_ token.
// https://www.w3.org/TR/selectors-3/#id-selectors
// All elements matching the current token with id equal
// to the _next_ token

$attr = $s === "." ? "class" : "id";
if (mb_substr($query, -1, 1) === "/") {
$query .= "*";
}

$query .= "[@id=\"$tok\"]";
$tok = "";
break;

case ".":
// https://www.w3.org/TR/selectors-3/#class-html
// All elements matching the current token with a class
// equal to the _next_ token

// empty class/id == *
if (mb_substr($query, -1, 1) === "/") {
$query .= "*";
}
Expand All @@ -544,7 +551,7 @@ private function _css_selector_to_xpath(string $selector, bool $first_pass = fal
// This doesn't work because libxml only supports XPath 1.0...
//$query .= "[matches(@$attr,\"^{$tok}\$|^{$tok}[ ]+|[ ]+{$tok}\$|[ ]+{$tok}[ ]+\")]";

$query .= "[contains(concat(' ', normalize-space(@$attr), ' '), concat(' ', '$tok', ' '))]";
$query .= "[contains(concat(' ', normalize-space(@class), ' '), concat(' ', '$tok', ' '))]";
$tok = "";
break;

Expand Down Expand Up @@ -615,7 +622,6 @@ private function _css_selector_to_xpath(string $selector, bool $first_pass = fal
$el = substr($query, $descendant_delimeter+2);
$query = substr($query, 0, strrpos($query, "/")) . ($isChild ? "/" : "//") . $el;

$pseudo_classes[$tok] = true;
$p = $i + 1;
$nth = trim(mb_substr($selector, $p, strpos($selector, ")", $i) - $p));
$position = $last ? "(last()-position()+1)" : "position()";
Expand All @@ -631,26 +637,20 @@ private function _css_selector_to_xpath(string $selector, bool $first_pass = fal
$condition = "($position mod 2) = 0";
} // an+b
else {
$condition = $this->_selector_an_plus_b($nth, $last);
$condition = $this->_selector_an_plus_b($nth, $position);
}

$query .= "[$condition]";
$tok = "";
break;

/** @noinspection PhpMissingBreakStatementInspection */
case "nth-last-child":
$last = true;
case "nth-child":
//FIXME: this fix-up is pretty ugly, would parsing the selector in reverse work better generally?
$descendant_delimeter = strrpos($query, "::");
$isChild = substr($query, $descendant_delimeter-5, 5) === "child";
$el = substr($query, $descendant_delimeter+2);
$query = substr($query, 0, strrpos($query, "/")) . ($isChild ? "/" : "//") . "*";

$pseudo_classes[$tok] = true;
$p = $i + 1;
$nth = trim(mb_substr($selector, $p, strpos($selector, ")", $i) - $p));
$position = $last ? "(last()-position()+1)" : "position()";
$position = $last ? "(count(following-sibling::*) + 1)" : "(count(preceding-sibling::*) + 1)";

// 1
if (preg_match("/^\d+$/", $nth)) {
Expand All @@ -663,19 +663,15 @@ private function _css_selector_to_xpath(string $selector, bool $first_pass = fal
$condition = "($position mod 2) = 0";
} // an+b
else {
$condition = $this->_selector_an_plus_b($nth, $last);
$condition = $this->_selector_an_plus_b($nth, $position);
}

$query .= "[$condition]";
if ($el !== "*") {
$query .= "[name() = '$el']";
}
$tok = "";
break;

//TODO: bit of a hack attempt at matches support, currently only matches against elements
case "matches":
$pseudo_classes[$tok] = true;
$p = $i + 1;
$matchList = trim(mb_substr($selector, $p, strpos($selector, ")", $i) - $p));

Expand Down Expand Up @@ -776,8 +772,8 @@ private function _css_selector_to_xpath(string $selector, bool $first_pass = fal

case "~":
case "|":
case "$":
case "^":
case "$":
case "*":
$op .= $tok[$j++];

Expand Down Expand Up @@ -826,9 +822,9 @@ private function _css_selector_to_xpath(string $selector, bool $first_pass = fal
case "~=":
// FIXME: this will break if $value contains quoted strings
// (e.g. [type~="a b c" "d e f"])
// FIXME: Don't match anything if value contains
// whitespace or is the empty string
$query .= "[contains(concat(' ', normalize-space(@$attr), ' '), concat(' ', '$value', ' '))]";
$query .= $value !== "" && !preg_match("/\s+/", $value)
? "[contains(concat(' ', normalize-space(@$attr), ' '), concat(' ', \"$value\", ' '))]"
: "[false()]";
break;

case "|=":
Expand All @@ -842,16 +838,22 @@ private function _css_selector_to_xpath(string $selector, bool $first_pass = fal
$query = rtrim($query, " or ") . "]";
break;

case "$=":
$query .= "[substring(@$attr, string-length(@$attr)-" . (strlen($value) - 1) . ")=\"$value\"]";
case "^=":
$query .= $value !== ""
? "[starts-with(@$attr,\"$value\")]"
: "[false()]";
break;

case "^=":
$query .= "[starts-with(@$attr,\"$value\")]";
case "$=":
$query .= $value !== ""
? "[substring(@$attr, string-length(@$attr)-" . (strlen($value) - 1) . ")=\"$value\"]"
: "[false()]";
break;

case "*=":
$query .= "[contains(@$attr,\"$value\")]";
$query .= $value !== ""
? "[contains(@$attr,\"$value\")]"
: "[false()]";
break;
}

Expand Down Expand Up @@ -892,11 +894,11 @@ private function _css_selector_to_xpath(string $selector, bool $first_pass = fal
* https://github.com/tenderlove/nokogiri/blob/master/lib/nokogiri/css/xpath_visitor.rb
*
* @param string $expr
* @param bool $last
* @param string $position
*
* @return string
*/
protected function _selector_an_plus_b(string $expr, bool $last = false): string
protected function _selector_an_plus_b(string $expr, string $position): string
{
$expr = preg_replace("/\s/", "", $expr);
if (!preg_match("/^(?P<a>-?[0-9]*)?n(?P<b>[-+]?[0-9]+)?$/", $expr, $matches)) {
Expand All @@ -906,8 +908,6 @@ protected function _selector_an_plus_b(string $expr, bool $last = false): string
$a = (isset($matches["a"]) && $matches["a"] !== "") ? ($matches["a"] !== "-" ? intval($matches["a"]) : -1) : 1;
$b = (isset($matches["b"]) && $matches["b"] !== "") ? intval($matches["b"]) : 0;

$position = $last ? "(last()-position()+1)" : "position()";

if ($b === 0) {
return "($position mod $a) = 0";
} else {
Expand Down
0