CssXPath-StarSelector (#4506)

* CssXPath-StarSelector
Add support for selectors such as `a[href*="example"]`
https://developer.mozilla.org/docs/Web/CSS/Attribute_selectors
Translated to `.//a[contains(@href,"example")]`

Upstream PR: https://github.com/PhpGt/CssXPath/pull/181

* Upstream merged
This commit is contained in:
Alexandre Alapetite 2022-08-18 11:14:40 +02:00 committed by GitHub
parent ea0d924985
commit 2acf3a4dd8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 29 additions and 16 deletions

4
lib/.gitignore vendored
View File

@ -1,9 +1,7 @@
autoload.php
composer.lock
composer/
phpgt/cssxpath/.github/
phpgt/cssxpath/.gitignore
phpgt/cssxpath/.scrutinizer.yml
phpgt/cssxpath/.*
phpgt/cssxpath/composer.json
phpgt/cssxpath/CONTRIBUTING.md
phpgt/cssxpath/test/

View File

@ -4,9 +4,15 @@
"type": "project",
"homepage": "https://freshrss.org/",
"license": "AGPL-3.0",
"repositories": [
{
"type": "git",
"url": "https://github.com/PhpGt/CssXPath.git"
}
],
"require": {
"php": ">=7.0.0",
"phpgt/cssxpath": "v1.1.4",
"phpgt/cssxpath": "dev-master#4fbe420aba3d9e729940107ded4236a835a1a132",
"phpmailer/phpmailer": "6.6.0"
},
"config": {

View File

@ -1,5 +1,5 @@
Translate CSS selectors to XPath queries.
=========================================
Translate CSS selectors to XPath queries
========================================
A lightweight and dependency free CSS to XPath translator. This repository is used to bring modern DOM functionality like [`querySelectorAll()`][qsa] to PHP in the [PHP.Gt/Dom][gt-dom] project.

View File

@ -3,4 +3,4 @@ namespace Gt\CssXPath;
use RuntimeException;
class CssXPathException extends RuntimeException {}
class CssXPathException extends RuntimeException {}

View File

@ -1,4 +1,4 @@
<?php
namespace Gt\CssXPath;
class NotYetImplementedException extends CssXPathException {}
class NotYetImplementedException extends CssXPathException {}

View File

@ -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+)'
. '/';
@ -61,7 +61,7 @@ class Translator {
$thread = array_values($thread);
$xpath = [$this->prefix];
$prevType = "";
$hasElement = false;
foreach($thread as $threadKey => $currentThreadItem) {
$next = isset($thread[$threadKey + 1])
? $thread[$threadKey + 1]
@ -71,6 +71,7 @@ class Translator {
case "star":
case "element":
$xpath []= $currentThreadItem['content'];
$hasElement = true;
break;
case "pseudo":
@ -160,23 +161,26 @@ class Translator {
case "child":
array_push($xpath, "/");
$hasElement = false;
break;
case "id":
array_push(
$xpath,
($prevType != "element" ? '*' : '')
($hasElement ? '' : '*')
. "[@id='{$currentThreadItem['content']}']"
);
$hasElement = true;
break;
case "class":
// https://devhints.io/xpath#class-check
array_push(
$xpath,
(($prevType != "element" && $prevType != "class") ? '*' : '')
($hasElement ? '' : '*')
. "[contains(concat(' ',normalize-space(@class),' '),' {$currentThreadItem['content']} ')]"
);
$hasElement = true;
break;
case "sibling":
@ -184,11 +188,13 @@ class Translator {
$xpath,
"/following-sibling::*[1]/self::"
);
$hasElement = false;
break;
case "attribute":
if(!$prevType) {
if(!$hasElement) {
array_push($xpath, "*");
$hasElement = true;
}
/** @var null|array<int, array<string, string>> $detail */
@ -220,7 +226,11 @@ class Translator {
break;
case self::EQUALS_CONTAINS:
throw new NotYetImplementedException();
array_push(
$xpath,
"[contains(@{$currentThreadItem['content']},\"{$valueString}\")]"
);
break;
case self::EQUALS_CONTAINS_WORD:
array_push(
@ -257,10 +267,9 @@ class Translator {
case "descendant":
array_push($xpath, "//");
$hasElement = false;
break;
}
$prevType = $currentThreadItem["type"];
}
return implode("", $xpath);