diff --git a/composer.lock b/composer.lock index b9b12f7..c29dbfc 100644 --- a/composer.lock +++ b/composer.lock @@ -65,16 +65,16 @@ }, { "name": "myclabs/deep-copy", - "version": "1.9.1", + "version": "1.9.3", "source": { "type": "git", "url": "https://github.com/myclabs/DeepCopy.git", - "reference": "e6828efaba2c9b79f4499dae1d66ef8bfa7b2b72" + "reference": "007c053ae6f31bba39dfa19a7726f56e9763bbea" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/e6828efaba2c9b79f4499dae1d66ef8bfa7b2b72", - "reference": "e6828efaba2c9b79f4499dae1d66ef8bfa7b2b72", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/007c053ae6f31bba39dfa19a7726f56e9763bbea", + "reference": "007c053ae6f31bba39dfa19a7726f56e9763bbea", "shasum": "" }, "require": { @@ -109,7 +109,7 @@ "object", "object graph" ], - "time": "2019-04-07T13:18:21+00:00" + "time": "2019-08-09T12:45:53+00:00" }, { "name": "phar-io/manifest", @@ -196,18 +196,18 @@ "authors": [ { "name": "Arne Blankerts", - "role": "Developer", - "email": "arne@blankerts.de" + "email": "arne@blankerts.de", + "role": "Developer" }, { "name": "Sebastian Heuer", - "role": "Developer", - "email": "sebastian@phpeople.de" + "email": "sebastian@phpeople.de", + "role": "Developer" }, { "name": "Sebastian Bergmann", - "role": "Developer", - "email": "sebastian@phpunit.de" + "email": "sebastian@phpunit.de", + "role": "Developer" } ], "description": "Library for handling version information and constraints", @@ -367,16 +367,16 @@ }, { "name": "phpgt/dom", - "version": "v2.0.3", + "version": "v2.1.2", "source": { "type": "git", "url": "https://github.com/PhpGt/Dom.git", - "reference": "ad48666c58910e266bb381c7ff54fc96718d3a96" + "reference": "4df60cd75b6f86a5333cfb8a3c2d8ba0c61c2615" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PhpGt/Dom/zipball/ad48666c58910e266bb381c7ff54fc96718d3a96", - "reference": "ad48666c58910e266bb381c7ff54fc96718d3a96", + "url": "https://api.github.com/repos/PhpGt/Dom/zipball/4df60cd75b6f86a5333cfb8a3c2d8ba0c61c2615", + "reference": "4df60cd75b6f86a5333cfb8a3c2d8ba0c61c2615", "shasum": "" }, "require": { @@ -384,7 +384,8 @@ "ext-libxml": "*", "ext-mbstring": "*", "php": ">=7.2", - "phpgt/cssxpath": "*" + "phpgt/cssxpath": "*", + "psr/http-message": "1.*" }, "require-dev": { "phpunit/phpunit": "8.*" @@ -443,7 +444,7 @@ } ], "description": "The modern DOM API for PHP 7 projects.", - "time": "2019-07-31T15:30:50+00:00" + "time": "2019-08-15T09:40:43+00:00" }, { "name": "phpspec/prophecy", @@ -510,16 +511,16 @@ }, { "name": "phpunit/php-code-coverage", - "version": "7.0.6", + "version": "7.0.7", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "d471d0d2b529a67c6a722dd446c4ec90881ac315" + "reference": "7743bbcfff2a907e9ee4a25be13d0f8ec5e73800" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/d471d0d2b529a67c6a722dd446c4ec90881ac315", - "reference": "d471d0d2b529a67c6a722dd446c4ec90881ac315", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/7743bbcfff2a907e9ee4a25be13d0f8ec5e73800", + "reference": "7743bbcfff2a907e9ee4a25be13d0f8ec5e73800", "shasum": "" }, "require": { @@ -528,7 +529,7 @@ "php": "^7.2", "phpunit/php-file-iterator": "^2.0.2", "phpunit/php-text-template": "^1.2.1", - "phpunit/php-token-stream": "^3.0.2", + "phpunit/php-token-stream": "^3.1.0", "sebastian/code-unit-reverse-lookup": "^1.0.1", "sebastian/environment": "^4.2.2", "sebastian/version": "^2.0.1", @@ -569,7 +570,7 @@ "testing", "xunit" ], - "time": "2019-07-08T05:29:42+00:00" + "time": "2019-07-25T05:31:54+00:00" }, { "name": "phpunit/php-file-iterator", @@ -713,16 +714,16 @@ }, { "name": "phpunit/php-token-stream", - "version": "3.0.2", + "version": "3.1.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-token-stream.git", - "reference": "c4a66b97f040e3e20b3aa2a243230a1c3a9f7c8c" + "reference": "e899757bb3df5ff6e95089132f32cd59aac2220a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/c4a66b97f040e3e20b3aa2a243230a1c3a9f7c8c", - "reference": "c4a66b97f040e3e20b3aa2a243230a1c3a9f7c8c", + "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/e899757bb3df5ff6e95089132f32cd59aac2220a", + "reference": "e899757bb3df5ff6e95089132f32cd59aac2220a", "shasum": "" }, "require": { @@ -735,7 +736,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "3.0-dev" + "dev-master": "3.1-dev" } }, "autoload": { @@ -758,20 +759,20 @@ "keywords": [ "tokenizer" ], - "time": "2019-07-08T05:24:54+00:00" + "time": "2019-07-25T05:29:42+00:00" }, { "name": "phpunit/phpunit", - "version": "8.2.5", + "version": "8.3.4", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "c1b8534b3730f20f58600124129197bf1183dc92" + "reference": "e31cce0cf4499c0ccdbbb211a3280d36ab341e36" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/c1b8534b3730f20f58600124129197bf1183dc92", - "reference": "c1b8534b3730f20f58600124129197bf1183dc92", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/e31cce0cf4499c0ccdbbb211a3280d36ab341e36", + "reference": "e31cce0cf4499c0ccdbbb211a3280d36ab341e36", "shasum": "" }, "require": { @@ -787,7 +788,7 @@ "phar-io/version": "^2.0.1", "php": "^7.2", "phpspec/prophecy": "^1.8.1", - "phpunit/php-code-coverage": "^7.0.5", + "phpunit/php-code-coverage": "^7.0.7", "phpunit/php-file-iterator": "^2.0.2", "phpunit/php-text-template": "^1.2.1", "phpunit/php-timer": "^2.1.2", @@ -815,7 +816,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "8.2-dev" + "dev-master": "8.3-dev" } }, "autoload": { @@ -841,7 +842,57 @@ "testing", "xunit" ], - "time": "2019-07-15T06:26:24+00:00" + "time": "2019-08-11T06:56:55+00:00" + }, + { + "name": "psr/http-message", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-message.git", + "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-message/zipball/f6561bf28d520154e4b0ec72be95418abe6d9363", + "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP messages", + "homepage": "https://github.com/php-fig/http-message", + "keywords": [ + "http", + "http-message", + "psr", + "psr-7", + "request", + "response" + ], + "time": "2016-08-06T14:39:51+00:00" }, { "name": "sebastian/code-unit-reverse-lookup", @@ -1063,16 +1114,16 @@ }, { "name": "sebastian/exporter", - "version": "3.1.0", + "version": "3.1.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/exporter.git", - "reference": "234199f4528de6d12aaa58b612e98f7d36adb937" + "reference": "06a9a5947f47b3029d76118eb5c22802e5869687" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/234199f4528de6d12aaa58b612e98f7d36adb937", - "reference": "234199f4528de6d12aaa58b612e98f7d36adb937", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/06a9a5947f47b3029d76118eb5c22802e5869687", + "reference": "06a9a5947f47b3029d76118eb5c22802e5869687", "shasum": "" }, "require": { @@ -1099,6 +1150,10 @@ "BSD-3-Clause" ], "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, { "name": "Jeff Welch", "email": "whatthejeff@gmail.com" @@ -1107,17 +1162,13 @@ "name": "Volker Dusch", "email": "github@wallbash.com" }, - { - "name": "Bernhard Schussek", - "email": "bschussek@2bepublished.at" - }, - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - }, { "name": "Adam Harvey", "email": "aharvey@php.net" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" } ], "description": "Provides the functionality to export PHP variables for visualization", @@ -1126,7 +1177,7 @@ "export", "exporter" ], - "time": "2017-04-03T13:19:02+00:00" + "time": "2019-08-11T12:43:14+00:00" }, { "name": "sebastian/global-state", @@ -1407,8 +1458,8 @@ "authors": [ { "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" + "role": "lead", + "email": "sebastian@phpunit.de" } ], "description": "Collection of value objects that represent the types of the PHP type system", @@ -1460,16 +1511,16 @@ }, { "name": "symfony/polyfill-ctype", - "version": "v1.11.0", + "version": "v1.12.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-ctype.git", - "reference": "82ebae02209c21113908c229e9883c419720738a" + "reference": "550ebaac289296ce228a706d0867afc34687e3f4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/82ebae02209c21113908c229e9883c419720738a", - "reference": "82ebae02209c21113908c229e9883c419720738a", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/550ebaac289296ce228a706d0867afc34687e3f4", + "reference": "550ebaac289296ce228a706d0867afc34687e3f4", "shasum": "" }, "require": { @@ -1481,7 +1532,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.11-dev" + "dev-master": "1.12-dev" } }, "autoload": { @@ -1497,13 +1548,13 @@ "MIT" ], "authors": [ - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - }, { "name": "Gert de Pagter", "email": "BackEndTea@gmail.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" } ], "description": "Symfony polyfill for ctype functions", @@ -1514,7 +1565,7 @@ "polyfill", "portable" ], - "time": "2019-02-06T07:57:58+00:00" + "time": "2019-08-06T08:03:45+00:00" }, { "name": "theseer/tokenizer", diff --git a/src/Translator.php b/src/Translator.php index aa3c35e..80b9b58 100644 --- a/src/Translator.php +++ b/src/Translator.php @@ -16,6 +16,13 @@ class Translator { . '|(?P\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_STARTS_WITH = "^="; + protected $cssSelector; protected $prefix; @@ -53,15 +60,15 @@ protected function convertSingleSelector(string $css):string { $xpath = [$this->prefix]; $prevType = ""; - foreach($thread as $k => $item) { - $next = isset($thread[$k + 1]) - ? $thread[$k + 1] + foreach($thread as $threadKey => $currentThreadItem) { + $next = isset($thread[$threadKey + 1]) + ? $thread[$threadKey + 1] : false; - switch ($item['type']) { + switch ($currentThreadItem['type']) { case 'star': case 'element': - $xpath []= $item['content']; + $xpath []= $currentThreadItem['content']; break; case 'pseudo': @@ -70,11 +77,11 @@ protected function convertSingleSelector(string $css):string { $specifier = "{$next['content']}"; } - switch ($item['content']) { + switch ($currentThreadItem['content']) { case 'disabled': case 'checked': case 'selected': - $xpath []= "[@{$item['content']}]"; + $xpath []= "[@{$currentThreadItem['content']}]"; break; case 'text': @@ -131,13 +138,13 @@ protected function convertSingleSelector(string $css):string { break; case 'id': - $xpath []= ($prevType != 'element' ? '*' : '') . "[@id='{$item['content']}']"; + $xpath []= ($prevType != 'element' ? '*' : '') . "[@id='{$currentThreadItem['content']}']"; break; case 'class': // https://devhints.io/xpath#class-check $xpath []= (($prevType != 'element' && $prevType != 'class') ? '*' : '') - . "[contains(concat(' ',normalize-space(@class),' '),' {$item['content']} ')]"; + . "[contains(concat(' ',normalize-space(@class),' '),' {$currentThreadItem['content']} ')]"; break; case 'sibling': @@ -149,37 +156,53 @@ protected function convertSingleSelector(string $css):string { $xpath []= "*"; } - if (!$next || $next['type'] != 'attribute_equals') { - $xpath []= "[@{$item['content']}]"; + $detail = $currentThreadItem["detail"] ?? null; + $detailType = $detail[0] ?? null; + $detailValue = $detail[1] ?? null; + + if(!$detailType + || $detailType["type"] !== "attribute_equals") { + $xpath []= "[@{$currentThreadItem['content']}]"; continue; } - $value = $thread[$k+2]; $valueString = trim( - $value['content'], + $detailValue["content"], " '\"" ); - $equalsType = $next['content']; + $equalsType = $detailType["content"]; switch ($equalsType) { - case '=': - $xpath []= "[@{$item['content']}=\"{$valueString}\"]"; + case self::EQUALS_EXACT: + $xpath []= "[@{$currentThreadItem['content']}=\"{$valueString}\"]"; break; - case '~=': + case self::EQUALS_CONTAINS: + // TODO. + break; + + case self::EQUALS_CONTAINS_WORD: $xpath []= "[" . "contains(" - . "concat(\" \",@{$item['content']},\" \")," + . "concat(\" \",@{$currentThreadItem['content']},\" \")," . "concat(\" \",\"{$valueString}\",\" \")" . ")" . "]"; break; - case '$=': + case self::EQUALS_STARTS_WITH_OR_STARTS_WITH_HYPHENATED: + // TODO. + break; + + case self::EQUALS_STARTS_WITH: + // TODO. + break; + + case self::EQUALS_ENDS_WITH: $xpath []= "[" . "substring(" - . "@{$item['content']}," - . "string-length(@{$item['content']}) - " + . "@{$currentThreadItem['content']}," + . "string-length(@{$currentThreadItem['content']}) - " . "string-length(\"{$valueString}\") + 1)" . "=\"{$valueString}\"" . "]"; @@ -192,7 +215,7 @@ protected function convertSingleSelector(string $css):string { break; } - $prevType = $item['type']; + $prevType = $currentThreadItem['type']; } return implode("", $xpath); @@ -240,7 +263,11 @@ protected function preg_match_collated( $set [$i]= $toSet; } else { - $set []= $toSet; + if(!isset($set[$i]["detail"])) { + $set[$i]["detail"] = []; + } + + $set[$i]["detail"] []= $toSet; } } } diff --git a/test/unit/Helper/Helper.php b/test/unit/Helper/Helper.php index e1d119f..129a048 100644 --- a/test/unit/Helper/Helper.php +++ b/test/unit/Helper/Helper.php @@ -105,5 +105,34 @@ class Helper { HTML; + const HTML_SELECTS = << +
+ + + +
+HTML; + } \ No newline at end of file diff --git a/test/unit/TranslatorTest.php b/test/unit/TranslatorTest.php index d11ed16..45aef2f 100644 --- a/test/unit/TranslatorTest.php +++ b/test/unit/TranslatorTest.php @@ -324,4 +324,16 @@ public function testCommaInAttributeDoesNotSeparate() { self::assertEquals("INPUT", strtoupper($emailItems[0]->tagName)); self::assertEquals("SPAN", strtoupper($messageItems[0]->tagName)); } + + public function testHierarchyIsRespectedForChildSelectors() { + $document = new HTMLDocument(Helper::HTML_SELECTS); + $fromOptionTranslator = new Translator("[name=from] option"); + $toOptionTranslator = new Translator("[name=to] option"); + + $fromOptions = $document->xPath($fromOptionTranslator); + $toOptions = $document->xPath($toOptionTranslator); + + self::assertEquals(0, $fromOptions[0]->value); + self::assertEquals(5, $toOptions[0]->value); + } } \ No newline at end of file