diff options
author | Alexandre Alapetite <alexandre@alapetite.fr> | 2025-03-13 22:40:41 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2025-03-13 22:40:41 +0100 |
commit | a7361a3e7cd335c8932deba88fe60e8f673c2d40 (patch) | |
tree | bb4c007188d54897210f2a0539c2df0f438fb069 | |
parent | df545b513b1c43e54da5b023bf3fe01bf36ad013 (diff) | |
download | freshrss-a7361a3e7cd335c8932deba88fe60e8f673c2d40.tar.gz freshrss-a7361a3e7cd335c8932deba88fe60e8f673c2d40.zip |
Implement JSON string concatenation with & operator (#7414)
Inspired by [JSONata syntax](https://docs.jsonata.org/expressions).
fix https://github.com/FreshRSS/FreshRSS/issues/6565
-rw-r--r-- | app/Utils/dotNotationUtil.php | 32 | ||||
-rw-r--r-- | docs/en/users/11_website_scraping.md | 2 | ||||
-rw-r--r-- | tests/app/Utils/dotNotationUtilTest.php | 3 |
3 files changed, 36 insertions, 1 deletions
diff --git a/app/Utils/dotNotationUtil.php b/app/Utils/dotNotationUtil.php index 77ae96c30..89b91bc5b 100644 --- a/app/Utils/dotNotationUtil.php +++ b/app/Utils/dotNotationUtil.php @@ -18,9 +18,39 @@ final class FreshRSS_dotNotation_Util return static::value($default); } /** @var \ArrayAccess<string,mixed>|array<string,mixed> $array */ - if (in_array($key, [null, '', '.', '$'], true)) { + if ($key === null) { return $array; } + $key = trim($key); + + if (in_array($key, ['', '.', '$'], true)) { + return $array; + } + + // If the key is a simple string, return the text + if (preg_match('/^(?P<delim>[\'"])(?P<text>[^&]*)(?P=delim)$/', $key, $matches)) { + $text = $matches['text']; + $text = str_replace('&', '&', $text); // Unescape `&` + return $text; + } + + // Escape `&` operator + $key = preg_replace_callback('/(?P<delim>[\'"])(?P<text>.*?)(?P=delim)/', + fn(array $matches): string => str_replace('&', '&', $matches[0]), + $key) ?? $key; + + // If the key contains string concatenations with `&`, process them + $concats = explode('&', $key); + if (count($concats) > 1) { + $text = ''; + foreach ($concats as $concat) { + $result = static::get($array, $concat, $default); + if (is_scalar($result)) { + $text .= (string)$result; + } + } + return $text; + } // Compatibility with brackets path such as `items[0].value` $key = preg_replace('/\[(\d+)\]/', '.$1', $key); diff --git a/docs/en/users/11_website_scraping.md b/docs/en/users/11_website_scraping.md index f725280ea..a5704b81b 100644 --- a/docs/en/users/11_website_scraping.md +++ b/docs/en/users/11_website_scraping.md @@ -50,6 +50,8 @@ and the link would be `links[1]`. It is a similar syntax to the JavaScript way to access JSON: `object.object.array[2].property`. +Support string concatenation with a syntax like: `meta.title & " some text"` using single-quotes or double-quotes. + ## Tips & tricks - [Timezone of date](https://github.com/FreshRSS/FreshRSS/discussions/5483) diff --git a/tests/app/Utils/dotNotationUtilTest.php b/tests/app/Utils/dotNotationUtilTest.php index 20d4726af..787d3ddf3 100644 --- a/tests/app/Utils/dotNotationUtilTest.php +++ b/tests/app/Utils/dotNotationUtilTest.php @@ -33,6 +33,9 @@ class dotNotationUtilTest extends PHPUnit\Framework\TestCase { yield [$array, 'items[0].meta.title', 'first']; yield [$array, 'items.1.meta.title', 'second']; yield [$array, 'items[1].meta.title', 'second']; + yield [$array, '"Hello " & hello & \'!\'', 'Hello world!']; + yield [$array, '"Hello & goodbye " & hello & \'!\'', 'Hello & goodbye world!']; + yield [$array, '"Hello " & hello & deeper.hello & "!"', 'Hello worldagain!']; } /** |