Skip to content

Commit

Permalink
Bump phpgt/cssxpath
Browse files Browse the repository at this point in the history
Includes PhpGt/CssXPath#227
Follow-up of PhpGt/CssXPath#227 for PHP 8.4
Requires PHP 8.0+
Full diff PhpGt/CssXPath@d99d35f...45f3ac1
  • Loading branch information
Alkarex committed Jul 12, 2024
1 parent b92b80d commit 004b004
Show file tree
Hide file tree
Showing 3 changed files with 89 additions and 18 deletions.
2 changes: 1 addition & 1 deletion lib/composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
],
"require": {
"marienfressinaud/lib_opml": "0.5.1",
"phpgt/cssxpath": "dev-master#d99d35f7194bac19fb3f8726b70c1bc83de3e931",
"phpgt/cssxpath": "dev-master#45f3ac151fc21d459e2515c3aff97cd4bf877bf8",
"phpmailer/phpmailer": "6.9.1"
},
"config": {
Expand Down
14 changes: 12 additions & 2 deletions lib/phpgt/cssxpath/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@ A lightweight and dependency free CSS to XPath translator. This repository is us
<a href="https://github.com/PhpGt/CssXPath/actions" target="_blank">
<img src="https://badge.status.php.gt/cssxpath-build.svg" alt="Build status" />
</a>
<a href="https://scrutinizer-ci.com/g/PhpGt/CssXPath" target="_blank">
<a href="https://app.codacy.com/gh/PhpGt/CssXPath" target="_blank">
<img src="https://badge.status.php.gt/cssxpath-quality.svg" alt="Code quality" />
</a>
<a href="https://scrutinizer-ci.com/g/PhpGt/CssXPath" target="_blank">
<a href="https://app.codecov.io/gh/PhpGt/CssXPath" target="_blank">
<img src="https://badge.status.php.gt/cssxpath-coverage.svg" alt="Code coverage" />
</a>
<a href="https://packagist.org/packages/PhpGt/CssXPath" target="_blank">
Expand Down Expand Up @@ -49,5 +49,15 @@ $xpath = new DOMXPath($document);
$inputElementList = $xpath->query(new Translator("form>label>input");
```

## Using this library with XML Documents

To correctly work with XML documents, where the attributes are case-sensitive, pass `false` to the `htmlMode` property of the constructor.

```php
$translator = new Translator("[data-FOO='bar']", htmlMode: false);
```

It's perhaps worth noting that for XML-style matching to work, you must load the document content with DOMDocument->load/DOMDocument->loadXML instead of DOMDocument->loadHTMLFile/DOMDocument->loadHTML, as the HTML loading methods automatically convert the tags and attribute names to lowercase. This is handled automatically when using [PHP.Gt/Dom][gt-dom].

[qsa]: https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelectorAll
[gt-dom]: https://www.php.gt/dom
91 changes: 76 additions & 15 deletions lib/phpgt/cssxpath/src/Translator.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,25 +12,22 @@ 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+)'
. '/';

const EQUALS_EXACT = "=";
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 {
Expand Down Expand Up @@ -70,7 +67,11 @@ protected function convertSingleSelector(string $css):string {
switch ($currentThreadItem["type"]) {
case "star":
case "element":
$xpath []= $currentThreadItem['content'];
if($this->htmlMode) {
$xpath []= strtolower($currentThreadItem['content']);
} else {
$xpath []= $currentThreadItem['content'];
}
$hasElement = true;
break;

Expand Down Expand Up @@ -135,6 +136,30 @@ protected function convertSingleSelector(string $css):string {
);
}
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;
Expand All @@ -156,6 +181,25 @@ protected function convertSingleSelector(string $css):string {
);
}
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;

Expand Down Expand Up @@ -197,6 +241,10 @@ protected function convertSingleSelector(string $css):string {
$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;
Expand Down Expand Up @@ -244,11 +292,24 @@ protected function convertSingleSelector(string $css):string {
);
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(
Expand Down Expand Up @@ -279,7 +340,7 @@ protected function convertSingleSelector(string $css):string {
protected function preg_match_collated(
string $regex,
string $string,
callable $transform = null
?callable $transform = null
):array {
preg_match_all(
$regex,
Expand Down

0 comments on commit 004b004

Please sign in to comment.