From a7361a3e7cd335c8932deba88fe60e8f673c2d40 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Thu, 13 Mar 2025 22:40:41 +0100 Subject: Implement JSON string concatenation with & operator (#7414) Inspired by [JSONata syntax](https://docs.jsonata.org/expressions). fix https://github.com/FreshRSS/FreshRSS/issues/6565 --- app/Utils/dotNotationUtil.php | 32 +++++++++++++++++++++++++++++++- docs/en/users/11_website_scraping.md | 2 ++ tests/app/Utils/dotNotationUtilTest.php | 3 +++ 3 files changed, 36 insertions(+), 1 deletion(-) 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|array $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[\'"])(?P[^&]*)(?P=delim)$/', $key, $matches)) { + $text = $matches['text']; + $text = str_replace('&', '&', $text); // Unescape `&` + return $text; + } + + // Escape `&` operator + $key = preg_replace_callback('/(?P[\'"])(?P.*?)(?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!']; } /** -- cgit v1.2.3