Jelajahi Sumber

Implement JSON string concatenation with & operator (#7414)

Inspired by [JSONata syntax](https://docs.jsonata.org/expressions).
fix https://github.com/FreshRSS/FreshRSS/issues/6565
Alexandre Alapetite 1 tahun lalu
induk
melakukan
a7361a3e7c

+ 31 - 1
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);

+ 2 - 0
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)

+ 3 - 0
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!'];
 	}
 
 	/**