|
|
@@ -12,7 +12,7 @@ class Translator {
|
|
|
. '|(#(?P<id>[\w-]*))'
|
|
|
. '|(\.(?P<class>[\w-]*))'
|
|
|
. '|(?P<sibling>\s*\+\s*)'
|
|
|
- . "|(\[(?P<attribute>[\w-]*)((?P<attribute_equals>[=~$*]+)(?P<attribute_value>(.+\[\]'?)|[^\]]+))*\])+"
|
|
|
+ . "|(\[(?P<attribute>[\w-]*)((?P<attribute_equals>[=~$|^*]+)(?P<attribute_value>(.+\[\]'?)|[^\]]+))*\])+"
|
|
|
. '|(?P<descendant>\s+)'
|
|
|
. '/';
|
|
|
|
|
|
@@ -20,17 +20,14 @@ class Translator {
|
|
|
const EQUALS_CONTAINS_WORD = "~=";
|
|
|
const EQUALS_ENDS_WITH = "$=";
|
|
|
const EQUALS_CONTAINS = "*=";
|
|
|
- const EQUALS_STARTS_WITH_OR_STARTS_WITH_HYPHENATED = "|=";
|
|
|
+ const EQUALS_OR_STARTS_WITH_HYPHENATED = "|=";
|
|
|
const EQUALS_STARTS_WITH = "^=";
|
|
|
|
|
|
- /** @var string */
|
|
|
- protected $cssSelector;
|
|
|
- /** @var string */
|
|
|
- protected $prefix;
|
|
|
-
|
|
|
- public function __construct(string $cssSelector, string $prefix = ".//") {
|
|
|
- $this->cssSelector = $cssSelector;
|
|
|
- $this->prefix = $prefix;
|
|
|
+ public function __construct(
|
|
|
+ protected string $cssSelector,
|
|
|
+ protected string $prefix = ".//",
|
|
|
+ protected bool $htmlMode = true
|
|
|
+ ) {
|
|
|
}
|
|
|
|
|
|
public function __toString():string {
|
|
|
@@ -70,7 +67,11 @@ class Translator {
|
|
|
switch ($currentThreadItem["type"]) {
|
|
|
case "star":
|
|
|
case "element":
|
|
|
- $xpath []= $currentThreadItem['content'];
|
|
|
+ if($this->htmlMode) {
|
|
|
+ $xpath []= strtolower($currentThreadItem['content']);
|
|
|
+ } else {
|
|
|
+ $xpath []= $currentThreadItem['content'];
|
|
|
+ }
|
|
|
$hasElement = true;
|
|
|
break;
|
|
|
|
|
|
@@ -135,6 +136,30 @@ class Translator {
|
|
|
);
|
|
|
}
|
|
|
break;
|
|
|
+
|
|
|
+ case "last-child":
|
|
|
+ $prev = count($xpath) - 1;
|
|
|
+ $xpath[$prev] = '*[last()]/self::' . $xpath[$prev];
|
|
|
+ break;
|
|
|
+
|
|
|
+ case 'first-of-type':
|
|
|
+ $prev = count($xpath) - 1;
|
|
|
+ $previous = $xpath[$prev];
|
|
|
+
|
|
|
+ if(substr($previous, -1, 1) === "]") {
|
|
|
+ array_push(
|
|
|
+ $xpath,
|
|
|
+ "[1]"
|
|
|
+ );
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ array_push(
|
|
|
+ $xpath,
|
|
|
+ "[1]"
|
|
|
+ );
|
|
|
+ }
|
|
|
+ break;
|
|
|
+
|
|
|
case "nth-of-type":
|
|
|
if (empty($specifier)) {
|
|
|
continue 3;
|
|
|
@@ -156,6 +181,25 @@ class Translator {
|
|
|
);
|
|
|
}
|
|
|
break;
|
|
|
+
|
|
|
+ case "last-of-type":
|
|
|
+ $prev = count($xpath) - 1;
|
|
|
+ $previous = $xpath[$prev];
|
|
|
+
|
|
|
+ if(substr($previous, -1, 1) === "]") {
|
|
|
+ array_push(
|
|
|
+ $xpath,
|
|
|
+ "[last()]"
|
|
|
+ );
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ array_push(
|
|
|
+ $xpath,
|
|
|
+ "[last()]"
|
|
|
+ );
|
|
|
+ }
|
|
|
+ break;
|
|
|
+
|
|
|
}
|
|
|
break;
|
|
|
|
|
|
@@ -197,6 +241,10 @@ class Translator {
|
|
|
$hasElement = true;
|
|
|
}
|
|
|
|
|
|
+ if($this->htmlMode) {
|
|
|
+ $currentThreadItem['content'] = strtolower($currentThreadItem['content']);
|
|
|
+ }
|
|
|
+
|
|
|
/** @var null|array<int, array<string, string>> $detail */
|
|
|
$detail = $currentThreadItem["detail"] ?? null;
|
|
|
$detailType = $detail[0] ?? null;
|
|
|
@@ -244,11 +292,24 @@ class Translator {
|
|
|
);
|
|
|
break;
|
|
|
|
|
|
- case self::EQUALS_STARTS_WITH_OR_STARTS_WITH_HYPHENATED:
|
|
|
- throw new NotYetImplementedException();
|
|
|
+ case self::EQUALS_OR_STARTS_WITH_HYPHENATED:
|
|
|
+ array_push(
|
|
|
+ $xpath,
|
|
|
+ "["
|
|
|
+ . "@{$currentThreadItem['content']}=\"{$valueString}\" or "
|
|
|
+ . "starts-with(@{$currentThreadItem['content']}, \"{$valueString}-\")"
|
|
|
+ . "]"
|
|
|
+ );
|
|
|
+ break;
|
|
|
|
|
|
case self::EQUALS_STARTS_WITH:
|
|
|
- throw new NotYetImplementedException();
|
|
|
+ array_push(
|
|
|
+ $xpath,
|
|
|
+ "[starts-with("
|
|
|
+ . "@{$currentThreadItem['content']}, \"{$valueString}\""
|
|
|
+ . ")]"
|
|
|
+ );
|
|
|
+ break;
|
|
|
|
|
|
case self::EQUALS_ENDS_WITH:
|
|
|
array_push(
|
|
|
@@ -279,7 +340,7 @@ class Translator {
|
|
|
protected function preg_match_collated(
|
|
|
string $regex,
|
|
|
string $string,
|
|
|
- callable $transform = null
|
|
|
+ ?callable $transform = null
|
|
|
):array {
|
|
|
preg_match_all(
|
|
|
$regex,
|