Skip to content

Commit b8accfe

Browse files
committed
added DomQuery::matches()
1 parent 8c33846 commit b8accfe

File tree

3 files changed

+78
-33
lines changed

3 files changed

+78
-33
lines changed

src/Framework/DomQuery.php

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,8 @@ public static function fromXml(string $xml): self
6666
*/
6767
public function find(string $selector): array
6868
{
69-
return $this->xpath(self::css2xpath($selector));
69+
$base = str_starts_with($selector, '>') ? 'self' : 'descendant';
70+
return $this->xpath($base . '::' . self::css2xpath($selector));
7071
}
7172

7273

@@ -79,12 +80,21 @@ public function has(string $selector): bool
7980
}
8081

8182

83+
/**
84+
* Determines if the current element matches the specified CSS selector.
85+
*/
86+
public function matches(string $selector): bool
87+
{
88+
return (bool) $this->xpath('self::' . self::css2xpath($selector));
89+
}
90+
91+
8292
/**
8393
* Converts a CSS selector into an XPath expression.
8494
*/
8595
public static function css2xpath(string $css): string
8696
{
87-
$xpath = './/*';
97+
$xpath = '*';
8898
preg_match_all(<<<'XX'
8999
/
90100
([#.:]?)([a-z][a-z0-9_-]*)| # id, class, pseudoclass (1,2)

tests/Framework/DomQuery.css2Xpath.phpt

Lines changed: 28 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -8,73 +8,73 @@ use Tester\DomQuery;
88
require __DIR__ . '/../bootstrap.php';
99

1010
test('type selectors', function () {
11-
Assert::same('.//*', DomQuery::css2xpath('*'));
12-
Assert::same('.//foo', DomQuery::css2xpath('foo'));
11+
Assert::same('*', DomQuery::css2xpath('*'));
12+
Assert::same('foo', DomQuery::css2xpath('foo'));
1313
});
1414

1515

1616
test('#ID', function () {
17-
Assert::same(".//*[@id='foo']", DomQuery::css2xpath('#foo'));
18-
Assert::same(".//*[@id='id']", DomQuery::css2xpath('*#id'));
17+
Assert::same("*[@id='foo']", DomQuery::css2xpath('#foo'));
18+
Assert::same("*[@id='id']", DomQuery::css2xpath('*#id'));
1919
});
2020

2121

2222
test('class', function () {
23-
Assert::same(".//*[contains(concat(' ', normalize-space(@class), ' '), ' foo ')]", DomQuery::css2xpath('.foo'));
24-
Assert::same(".//*[contains(concat(' ', normalize-space(@class), ' '), ' foo ')]", DomQuery::css2xpath('*.foo'));
25-
Assert::same(".//*[contains(concat(' ', normalize-space(@class), ' '), ' foo ')][contains(concat(' ', normalize-space(@class), ' '), ' bar ')]", DomQuery::css2xpath('.foo.bar'));
23+
Assert::same("*[contains(concat(' ', normalize-space(@class), ' '), ' foo ')]", DomQuery::css2xpath('.foo'));
24+
Assert::same("*[contains(concat(' ', normalize-space(@class), ' '), ' foo ')]", DomQuery::css2xpath('*.foo'));
25+
Assert::same("*[contains(concat(' ', normalize-space(@class), ' '), ' foo ')][contains(concat(' ', normalize-space(@class), ' '), ' bar ')]", DomQuery::css2xpath('.foo.bar'));
2626
});
2727

2828

2929
test('attribute selectors', function () {
30-
Assert::same('.//div[@foo]', DomQuery::css2xpath('div[foo]'));
31-
Assert::same(".//div[@foo='bar']", DomQuery::css2xpath('div[foo=bar]'));
32-
Assert::same(".//*[@foo='bar']", DomQuery::css2xpath('[foo="bar"]'));
33-
Assert::same(".//div[@foo='bar']", DomQuery::css2xpath('div[foo="bar"]'));
34-
Assert::same(".//div[@foo='bar']", DomQuery::css2xpath("div[foo='bar']"));
35-
Assert::same(".//div[@foo='bar']", DomQuery::css2xpath('div[Foo="bar"]'));
36-
Assert::same(".//div[contains(concat(' ', normalize-space(@foo), ' '), ' bar ')]", DomQuery::css2xpath('div[foo~="bar"]'));
37-
Assert::same(".//div[contains(@foo, 'bar')]", DomQuery::css2xpath('div[foo*="bar"]'));
38-
Assert::same(".//div[starts-with(@foo, 'bar')]", DomQuery::css2xpath('div[foo^="bar"]'));
39-
Assert::same(".//div[substring(@foo, string-length(@foo)-0)='bar']", DomQuery::css2xpath('div[foo$="bar"]'));
40-
Assert::same(".//div[@foo='bar[]']", DomQuery::css2xpath("div[foo='bar[]']"));
41-
Assert::same(".//div[@foo='bar[]']", DomQuery::css2xpath('div[foo="bar[]"]'));
30+
Assert::same('div[@foo]', DomQuery::css2xpath('div[foo]'));
31+
Assert::same("div[@foo='bar']", DomQuery::css2xpath('div[foo=bar]'));
32+
Assert::same("*[@foo='bar']", DomQuery::css2xpath('[foo="bar"]'));
33+
Assert::same("div[@foo='bar']", DomQuery::css2xpath('div[foo="bar"]'));
34+
Assert::same("div[@foo='bar']", DomQuery::css2xpath("div[foo='bar']"));
35+
Assert::same("div[@foo='bar']", DomQuery::css2xpath('div[Foo="bar"]'));
36+
Assert::same("div[contains(concat(' ', normalize-space(@foo), ' '), ' bar ')]", DomQuery::css2xpath('div[foo~="bar"]'));
37+
Assert::same("div[contains(@foo, 'bar')]", DomQuery::css2xpath('div[foo*="bar"]'));
38+
Assert::same("div[starts-with(@foo, 'bar')]", DomQuery::css2xpath('div[foo^="bar"]'));
39+
Assert::same("div[substring(@foo, string-length(@foo)-0)='bar']", DomQuery::css2xpath('div[foo$="bar"]'));
40+
Assert::same("div[@foo='bar[]']", DomQuery::css2xpath("div[foo='bar[]']"));
41+
Assert::same("div[@foo='bar[]']", DomQuery::css2xpath('div[foo="bar[]"]'));
4242
});
4343

4444

4545
test('variants', function () {
46-
Assert::same(".//*[@id='foo']|//*[@id='bar']", DomQuery::css2xpath('#foo, #bar'));
47-
Assert::same(".//*[@id='foo']|//*[@id='bar']", DomQuery::css2xpath('#foo,#bar'));
48-
Assert::same(".//*[@id='foo']|//*[@id='bar']", DomQuery::css2xpath('#foo ,#bar'));
46+
Assert::same("*[@id='foo']|//*[@id='bar']", DomQuery::css2xpath('#foo, #bar'));
47+
Assert::same("*[@id='foo']|//*[@id='bar']", DomQuery::css2xpath('#foo,#bar'));
48+
Assert::same("*[@id='foo']|//*[@id='bar']", DomQuery::css2xpath('#foo ,#bar'));
4949
});
5050

5151

5252
test('descendant combinator', function () {
5353
Assert::same(
54-
".//div[@id='foo']//*[contains(concat(' ', normalize-space(@class), ' '), ' bar ')]",
54+
"div[@id='foo']//*[contains(concat(' ', normalize-space(@class), ' '), ' bar ')]",
5555
DomQuery::css2xpath('div#foo .bar'),
5656
);
5757
Assert::same(
58-
'.//div//*//p',
58+
'div//*//p',
5959
DomQuery::css2xpath('div * p'),
6060
);
6161
});
6262

6363

6464
test('child combinator', function () {
65-
Assert::same(".//div[@id='foo']/span", DomQuery::css2xpath('div#foo>span'));
66-
Assert::same(".//div[@id='foo']/span", DomQuery::css2xpath('div#foo > span'));
65+
Assert::same("div[@id='foo']/span", DomQuery::css2xpath('div#foo>span'));
66+
Assert::same("div[@id='foo']/span", DomQuery::css2xpath('div#foo > span'));
6767
});
6868

6969

7070
test('general sibling combinator', function () {
71-
Assert::same('.//div/following-sibling::span', DomQuery::css2xpath('div ~ span'));
71+
Assert::same('div/following-sibling::span', DomQuery::css2xpath('div ~ span'));
7272
});
7373

7474

7575
test('complex', function () {
7676
Assert::same(
77-
".//div[@id='foo']//span[contains(concat(' ', normalize-space(@class), ' '), ' bar ')]"
77+
"div[@id='foo']//span[contains(concat(' ', normalize-space(@class), ' '), ' bar ')]"
7878
. "|//*[@id='bar']//li[contains(concat(' ', normalize-space(@class), ' '), ' baz ')]//a",
7979
DomQuery::css2xpath('div#foo span.bar, #bar li.baz a'),
8080
);

tests/Framework/DomQuery.fromXml.phpt

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,41 @@ use Tester\DomQuery;
77

88
require __DIR__ . '/../bootstrap.php';
99

10-
$q = DomQuery::fromXml('<xml><body>hello</body></xml>');
11-
Assert::true($q->has('body'));
12-
Assert::false($q->has('p'));
10+
11+
$xml = <<<'XML'
12+
<root>
13+
<item id="test1" class="foo">Item 1</item>
14+
<item id="test2" class="bar">Item 2</item>
15+
<container>
16+
<item id="test3" class="foo">Item 3</item>
17+
</container>
18+
</root>
19+
XML;
20+
21+
$dom = DomQuery::fromXml($xml);
22+
Assert::type(DomQuery::class, $dom);
23+
24+
// root
25+
Assert::true($dom->matches('root'));
26+
Assert::false($dom->has('root'));
27+
28+
// find
29+
$results = $dom->find('.foo');
30+
Assert::count(2, $results);
31+
Assert::type(DomQuery::class, $results[0]);
32+
Assert::type(DomQuery::class, $results[1]);
33+
34+
// children
35+
$results = $dom->find('> item');
36+
Assert::count(2, $results);
37+
38+
// has
39+
Assert::true($dom->has('#test1'));
40+
Assert::false($dom->has('#nonexistent'));
41+
Assert::false($dom->find('container')[0]->has('#test1'));
42+
Assert::true($dom->find('container')[0]->has('#test3'));
43+
44+
// matches
45+
$subItem = $dom->find('#test1')[0];
46+
Assert::true($subItem->matches('.foo'));
47+
Assert::false($subItem->matches('.bar'));

0 commit comments

Comments
 (0)