aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/app
diff options
context:
space:
mode:
authorAlexandre Alapetite <alexandre@alapetite.fr>2025-03-24 14:08:43 +0100
committerGitHub <noreply@github.com>2025-03-24 14:08:43 +0100
commit9114b9a06a6ff668827c4b0fb68fb549d2c50470 (patch)
tree9dd5d20412e325b15fcc4bcb7fe5af442b94a598 /app
parentb0a3ae1e7af2a1485439439463ceed3dc2057f65 (diff)
downloadfreshrss-9114b9a06a6ff668827c4b0fb68fb549d2c50470.tar.gz
freshrss-9114b9a06a6ff668827c4b0fb68fb549d2c50470.zip
Support multiple JSON fragments in HTML+XPath+JSON mode (#7369)
* Support multiple JSON fragments in HTML+XPath+JSON mode fix https://github.com/FreshRSS/FreshRSS/discussions/7352#discussioncomment-12295475 E.g. HTML with one `<script type="application/ld+json">...</script>` per item. * Better help messages
Diffstat (limited to 'app')
-rw-r--r--app/Models/Feed.php21
-rw-r--r--app/i18n/cs/sub.php2
-rw-r--r--app/i18n/de/sub.php2
-rw-r--r--app/i18n/el/sub.php2
-rw-r--r--app/i18n/en-us/sub.php2
-rw-r--r--app/i18n/en/sub.php6
-rw-r--r--app/i18n/es/sub.php2
-rw-r--r--app/i18n/fa/sub.php2
-rw-r--r--app/i18n/fi/sub.php2
-rw-r--r--app/i18n/fr/sub.php2
-rw-r--r--app/i18n/he/sub.php2
-rwxr-xr-xapp/i18n/hu/sub.php2
-rw-r--r--app/i18n/id/sub.php2
-rw-r--r--app/i18n/it/sub.php2
-rw-r--r--app/i18n/ja/sub.php2
-rw-r--r--app/i18n/ko/sub.php2
-rw-r--r--app/i18n/lv/sub.php2
-rw-r--r--app/i18n/nl/sub.php2
-rw-r--r--app/i18n/oc/sub.php2
-rw-r--r--app/i18n/pl/sub.php2
-rw-r--r--app/i18n/pt-br/sub.php2
-rw-r--r--app/i18n/pt-pt/sub.php2
-rw-r--r--app/i18n/ru/sub.php2
-rw-r--r--app/i18n/sk/sub.php2
-rw-r--r--app/i18n/tr/sub.php2
-rw-r--r--app/i18n/zh-cn/sub.php2
-rw-r--r--app/i18n/zh-tw/sub.php2
27 files changed, 47 insertions, 30 deletions
diff --git a/app/Models/Feed.php b/app/Models/Feed.php
index 57bf9d7a4..072948e1b 100644
--- a/app/Models/Feed.php
+++ b/app/Models/Feed.php
@@ -725,8 +725,25 @@ class FreshRSS_Feed extends Minz_Model {
}
$xpath = new DOMXPath($doc);
- $json = @$xpath->evaluate('normalize-space(' . $xPathToJson . ')');
- return is_string($json) ? $json : null;
+ $jsonFragments = @$xpath->evaluate($xPathToJson);
+ if ($jsonFragments === false) {
+ return null;
+ }
+ if (is_string($jsonFragments)) {
+ return $jsonFragments;
+ }
+ if ($jsonFragments instanceof DOMNodeList && $jsonFragments->length > 0) {
+ // If the result is a list, then aggregate as a JSON array
+ $result = [];
+ foreach ($jsonFragments as $node) {
+ $json = json_decode($node->textContent, true);
+ if (json_last_error() === JSON_ERROR_NONE && is_array($json)) {
+ $result[] = $json;
+ }
+ }
+ return json_encode($result, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE) ?: null;
+ }
+ return null;
}
public function loadJson(): ?\SimplePie\SimplePie {
diff --git a/app/i18n/cs/sub.php b/app/i18n/cs/sub.php
index d899aefe7..2ee7e830d 100644
--- a/app/i18n/cs/sub.php
+++ b/app/i18n/cs/sub.php
@@ -88,7 +88,7 @@ return array(
'_' => 'HTML + XPath + JSON dot notation (JSON in HTML)', // TODO
'xpath' => array(
'_' => 'XPath for JSON in HTML', // TODO
- 'help' => 'Example: <code>//script[@type="application/json"]</code>', // TODO
+ 'help' => 'Example: <code>normalize-space(//script[@type="application/json"])</code> (single JSON)<br />or: <code>//script[@type="application/ld+json"]</code> (one JSON object per article)', // TODO
),
),
'html_xpath' => array(
diff --git a/app/i18n/de/sub.php b/app/i18n/de/sub.php
index 3067b5efd..2a9f495c7 100644
--- a/app/i18n/de/sub.php
+++ b/app/i18n/de/sub.php
@@ -88,7 +88,7 @@ return array(
'_' => 'HTML + XPath + JSON Punkt-Notation (JSON in HTML)',
'xpath' => array(
'_' => 'XPath für JSON in HTML',
- 'help' => 'Beispiel: <code>//script[@type="application/json"]</code>',
+ 'help' => 'Beispiel: <code>normalize-space(//script[@type="application/json"])</code> (single JSON)<br />or: <code>//script[@type="application/ld+json"]</code> (one JSON object per article)</code>', // DIRTY
),
),
'html_xpath' => array(
diff --git a/app/i18n/el/sub.php b/app/i18n/el/sub.php
index 79e64bbb5..9147e2357 100644
--- a/app/i18n/el/sub.php
+++ b/app/i18n/el/sub.php
@@ -88,7 +88,7 @@ return array(
'_' => 'HTML + XPath + JSON dot notation (JSON in HTML)', // TODO
'xpath' => array(
'_' => 'XPath for JSON in HTML', // TODO
- 'help' => 'Example: <code>//script[@type="application/json"]</code>', // TODO
+ 'help' => 'Example: <code>normalize-space(//script[@type="application/json"])</code> (single JSON)<br />or: <code>//script[@type="application/ld+json"]</code> (one JSON object per article)', // TODO
),
),
'html_xpath' => array(
diff --git a/app/i18n/en-us/sub.php b/app/i18n/en-us/sub.php
index a6afee939..16cbd6fd2 100644
--- a/app/i18n/en-us/sub.php
+++ b/app/i18n/en-us/sub.php
@@ -88,7 +88,7 @@ return array(
'_' => 'HTML + XPath + JSON dot notation (JSON in HTML)', // IGNORE
'xpath' => array(
'_' => 'XPath for JSON in HTML', // IGNORE
- 'help' => 'Example: <code>//script[@type="application/json"]</code>', // IGNORE
+ 'help' => 'Example: <code>normalize-space(//script[@type="application/json"])</code> (single JSON)<br />or: <code>//script[@type="application/ld+json"]</code> (one JSON object per article)', // IGNORE
),
),
'html_xpath' => array(
diff --git a/app/i18n/en/sub.php b/app/i18n/en/sub.php
index c6e2c24d9..dfb59bfc3 100644
--- a/app/i18n/en/sub.php
+++ b/app/i18n/en/sub.php
@@ -85,10 +85,10 @@ return array(
'kind' => array(
'_' => 'Type of feed source',
'html_json' => array(
- '_' => 'HTML + XPath + JSON dot notation (JSON in HTML)', // TODO
+ '_' => 'HTML + XPath + JSON dot notation (JSON in HTML)',
'xpath' => array(
- '_' => 'XPath for JSON in HTML', // TODO
- 'help' => 'Example: <code>//script[@type="application/json"]</code>', // TODO
+ '_' => 'XPath for JSON in HTML',
+ 'help' => 'Example: <code>normalize-space(//script[@type="application/json"])</code> (single JSON)<br />or: <code>//script[@type="application/ld+json"]</code> (one JSON object per article)',
),
),
'html_xpath' => array(
diff --git a/app/i18n/es/sub.php b/app/i18n/es/sub.php
index b42d1f0e1..0518b6b11 100644
--- a/app/i18n/es/sub.php
+++ b/app/i18n/es/sub.php
@@ -88,7 +88,7 @@ return array(
'_' => 'HTML + XPath + JSON dot notation (JSON en HTML)',
'xpath' => array(
'_' => 'XPath para JSON en HTML',
- 'help' => 'Ejemplo: <code>//script[@type="application/json"]</code>',
+ 'help' => 'Ejemplo: <code>normalize-space(//script[@type="application/json"])</code> (single JSON)<br />or: <code>//script[@type="application/ld+json"]</code> (one JSON object per article)', // DIRTY
),
),
'html_xpath' => array(
diff --git a/app/i18n/fa/sub.php b/app/i18n/fa/sub.php
index e9f220a69..c6dab87d2 100644
--- a/app/i18n/fa/sub.php
+++ b/app/i18n/fa/sub.php
@@ -88,7 +88,7 @@ return array(
'_' => 'HTML + XPath + JSON dot notation (JSON in HTML)', // TODO
'xpath' => array(
'_' => 'XPath for JSON in HTML', // TODO
- 'help' => 'Example: <code>//script[@type="application/json"]</code>', // TODO
+ 'help' => 'Example: <code>normalize-space(//script[@type="application/json"])</code> (single JSON)<br />or: <code>//script[@type="application/ld+json"]</code> (one JSON object per article)', // TODO
),
),
'html_xpath' => array(
diff --git a/app/i18n/fi/sub.php b/app/i18n/fi/sub.php
index 3a6042448..ce7481af9 100644
--- a/app/i18n/fi/sub.php
+++ b/app/i18n/fi/sub.php
@@ -88,7 +88,7 @@ return array(
'_' => 'HTML + XPath + JSON-pistemerkintä (JSON HTML:ssä)',
'xpath' => array(
'_' => 'XPath (JSON HTML:ssä)',
- 'help' => 'Esimerkki: <code>//script[@type="application/json"]</code>',
+ 'help' => 'Esimerkki: <code>normalize-space(//script[@type="application/json"])</code> (single JSON)<br />or: <code>//script[@type="application/ld+json"]</code> (one JSON object per article)', // DIRTY
),
),
'html_xpath' => array(
diff --git a/app/i18n/fr/sub.php b/app/i18n/fr/sub.php
index 0339fa7f9..fc88d9e5c 100644
--- a/app/i18n/fr/sub.php
+++ b/app/i18n/fr/sub.php
@@ -88,7 +88,7 @@ return array(
'_' => 'HTML + XPath + JSON notation point (JSON dans HTML)',
'xpath' => array(
'_' => 'XPath pour JSON dans HTML',
- 'help' => 'Exemple : <code>//script[@type="application/json"]</code>',
+ 'help' => 'Exemple : <code>normalize-space(//script[@type="application/json"])</code> (JSON unique)<br />ou : <code>//script[@type="application/ld+json"]</code> (un objet JSON par article)',
),
),
'html_xpath' => array(
diff --git a/app/i18n/he/sub.php b/app/i18n/he/sub.php
index 64d5f5bbe..fe9779b67 100644
--- a/app/i18n/he/sub.php
+++ b/app/i18n/he/sub.php
@@ -88,7 +88,7 @@ return array(
'_' => 'HTML + XPath + JSON dot notation (JSON in HTML)', // TODO
'xpath' => array(
'_' => 'XPath for JSON in HTML', // TODO
- 'help' => 'Example: <code>//script[@type="application/json"]</code>', // TODO
+ 'help' => 'Example: <code>normalize-space(//script[@type="application/json"])</code> (single JSON)<br />or: <code>//script[@type="application/ld+json"]</code> (one JSON object per article)', // TODO
),
),
'html_xpath' => array(
diff --git a/app/i18n/hu/sub.php b/app/i18n/hu/sub.php
index 3b2d0a4e7..b9595e73d 100755
--- a/app/i18n/hu/sub.php
+++ b/app/i18n/hu/sub.php
@@ -88,7 +88,7 @@ return array(
'_' => 'HTML + XPath + JSON pont jelölés (JSON a HTML-ben)',
'xpath' => array(
'_' => 'XPath JSON-hoz HTML-ben',
- 'help' => 'Példa: <code>//script[@type="application/json"]</code>',
+ 'help' => 'Példa: <code>normalize-space(//script[@type="application/json"])</code> (single JSON)<br />or: <code>//script[@type="application/ld+json"]</code> (one JSON object per article)', // DIRTY
),
),
'html_xpath' => array(
diff --git a/app/i18n/id/sub.php b/app/i18n/id/sub.php
index bcc6a86ab..2ee3c3a4a 100644
--- a/app/i18n/id/sub.php
+++ b/app/i18n/id/sub.php
@@ -88,7 +88,7 @@ return array(
'_' => 'HTML + XPath + JSON dot notation (JSON in HTML)', // TODO
'xpath' => array(
'_' => 'XPath for JSON in HTML', // TODO
- 'help' => 'Example: <code>//script[@type="application/json"]</code>', // TODO
+ 'help' => 'Example: <code>normalize-space(//script[@type="application/json"])</code> (single JSON)<br />or: <code>//script[@type="application/ld+json"]</code> (one JSON object per article)', // TODO
),
),
'html_xpath' => array(
diff --git a/app/i18n/it/sub.php b/app/i18n/it/sub.php
index b817f0c48..fad888ff1 100644
--- a/app/i18n/it/sub.php
+++ b/app/i18n/it/sub.php
@@ -88,7 +88,7 @@ return array(
'_' => 'HTML + XPath + notazione a punti JSON (JSON in HTML)',
'xpath' => array(
'_' => 'XPath per JSON in HTML',
- 'help' => 'Esempio: <code>//script[@type="application/json"]</code>',
+ 'help' => 'Esempio: <code>normalize-space(//script[@type="application/json"])</code> (single JSON)<br />or: <code>//script[@type="application/ld+json"]</code> (one JSON object per article)', // DIRTY
),
),
'html_xpath' => array(
diff --git a/app/i18n/ja/sub.php b/app/i18n/ja/sub.php
index 91b8692cc..d59e0d032 100644
--- a/app/i18n/ja/sub.php
+++ b/app/i18n/ja/sub.php
@@ -88,7 +88,7 @@ return array(
'_' => 'HTML + XPath + JSONドット記法 (HTML内のJSON)',
'xpath' => array(
'_' => 'HTML内のJSONを指すXPath',
- 'help' => '例: <code>//script[@type="application/json"]</code>',
+ 'help' => '例: <code>normalize-space(//script[@type="application/json"])</code> (single JSON)<br />or: <code>//script[@type="application/ld+json"]</code> (one JSON object per article)', // DIRTY
),
),
'html_xpath' => array(
diff --git a/app/i18n/ko/sub.php b/app/i18n/ko/sub.php
index 6e97c63aa..d2f993d38 100644
--- a/app/i18n/ko/sub.php
+++ b/app/i18n/ko/sub.php
@@ -88,7 +88,7 @@ return array(
'_' => 'HTML + XPath + JSON dot notation (JSON in HTML)', // TODO
'xpath' => array(
'_' => 'XPath for JSON in HTML', // TODO
- 'help' => 'Example: <code>//script[@type="application/json"]</code>', // TODO
+ 'help' => 'Example: <code>normalize-space(//script[@type="application/json"])</code> (single JSON)<br />or: <code>//script[@type="application/ld+json"]</code> (one JSON object per article)', // TODO
),
),
'html_xpath' => array(
diff --git a/app/i18n/lv/sub.php b/app/i18n/lv/sub.php
index 0637bbc8c..f22afb5c0 100644
--- a/app/i18n/lv/sub.php
+++ b/app/i18n/lv/sub.php
@@ -88,7 +88,7 @@ return array(
'_' => 'HTML + XPath + JSON dot notation (JSON in HTML)', // TODO
'xpath' => array(
'_' => 'XPath for JSON in HTML', // TODO
- 'help' => 'Example: <code>//script[@type="application/json"]</code>', // TODO
+ 'help' => 'Example: <code>normalize-space(//script[@type="application/json"])</code> (single JSON)<br />or: <code>//script[@type="application/ld+json"]</code> (one JSON object per article)', // TODO
),
),
'html_xpath' => array(
diff --git a/app/i18n/nl/sub.php b/app/i18n/nl/sub.php
index 608c692cc..9a1c6ab50 100644
--- a/app/i18n/nl/sub.php
+++ b/app/i18n/nl/sub.php
@@ -88,7 +88,7 @@ return array(
'_' => 'HTML + XPath + JSON dot notation (JSON in HTML)', // TODO
'xpath' => array(
'_' => 'XPath for JSON in HTML', // TODO
- 'help' => 'Example: <code>//script[@type="application/json"]</code>', // TODO
+ 'help' => 'Example: <code>normalize-space(//script[@type="application/json"])</code> (single JSON)<br />or: <code>//script[@type="application/ld+json"]</code> (one JSON object per article)', // TODO
),
),
'html_xpath' => array(
diff --git a/app/i18n/oc/sub.php b/app/i18n/oc/sub.php
index 7be979f03..2cfe454fe 100644
--- a/app/i18n/oc/sub.php
+++ b/app/i18n/oc/sub.php
@@ -88,7 +88,7 @@ return array(
'_' => 'HTML + XPath + JSON dot notation (JSON in HTML)', // TODO
'xpath' => array(
'_' => 'XPath for JSON in HTML', // TODO
- 'help' => 'Example: <code>//script[@type="application/json"]</code>', // TODO
+ 'help' => 'Example: <code>normalize-space(//script[@type="application/json"])</code> (single JSON)<br />or: <code>//script[@type="application/ld+json"]</code> (one JSON object per article)', // TODO
),
),
'html_xpath' => array(
diff --git a/app/i18n/pl/sub.php b/app/i18n/pl/sub.php
index 80e6e5b4a..cc81def44 100644
--- a/app/i18n/pl/sub.php
+++ b/app/i18n/pl/sub.php
@@ -88,7 +88,7 @@ return array(
'_' => 'HTML + XPath + JSON dot notation (JSON in HTML)', // TODO
'xpath' => array(
'_' => 'XPath for JSON in HTML', // TODO
- 'help' => 'Example: <code>//script[@type="application/json"]</code>', // TODO
+ 'help' => 'Example: <code>normalize-space(//script[@type="application/json"])</code> (single JSON)<br />or: <code>//script[@type="application/ld+json"]</code> (one JSON object per article)', // TODO
),
),
'html_xpath' => array(
diff --git a/app/i18n/pt-br/sub.php b/app/i18n/pt-br/sub.php
index 57750af6a..a54be7569 100644
--- a/app/i18n/pt-br/sub.php
+++ b/app/i18n/pt-br/sub.php
@@ -88,7 +88,7 @@ return array(
'_' => 'HTML + XPath + JSON dot notation (JSON in HTML)', // TODO
'xpath' => array(
'_' => 'XPath for JSON in HTML', // TODO
- 'help' => 'Example: <code>//script[@type="application/json"]</code>', // TODO
+ 'help' => 'Example: <code>normalize-space(//script[@type="application/json"])</code> (single JSON)<br />or: <code>//script[@type="application/ld+json"]</code> (one JSON object per article)', // TODO
),
),
'html_xpath' => array(
diff --git a/app/i18n/pt-pt/sub.php b/app/i18n/pt-pt/sub.php
index d69246719..8d19764c6 100644
--- a/app/i18n/pt-pt/sub.php
+++ b/app/i18n/pt-pt/sub.php
@@ -88,7 +88,7 @@ return array(
'_' => 'HTML + XPath + JSON dot notation (JSON in HTML)', // TODO
'xpath' => array(
'_' => 'XPath for JSON in HTML', // TODO
- 'help' => 'Example: <code>//script[@type="application/json"]</code>', // TODO
+ 'help' => 'Example: <code>normalize-space(//script[@type="application/json"])</code> (single JSON)<br />or: <code>//script[@type="application/ld+json"]</code> (one JSON object per article)', // TODO
),
),
'html_xpath' => array(
diff --git a/app/i18n/ru/sub.php b/app/i18n/ru/sub.php
index bc93c5aac..7a782df47 100644
--- a/app/i18n/ru/sub.php
+++ b/app/i18n/ru/sub.php
@@ -88,7 +88,7 @@ return array(
'_' => 'HTML + XPath + JSON dot notation (JSON in HTML)', // TODO
'xpath' => array(
'_' => 'XPath for JSON in HTML', // TODO
- 'help' => 'Example: <code>//script[@type="application/json"]</code>', // TODO
+ 'help' => 'Example: <code>normalize-space(//script[@type="application/json"])</code> (single JSON)<br />or: <code>//script[@type="application/ld+json"]</code> (one JSON object per article)', // TODO
),
),
'html_xpath' => array(
diff --git a/app/i18n/sk/sub.php b/app/i18n/sk/sub.php
index 20301a319..8ed64adda 100644
--- a/app/i18n/sk/sub.php
+++ b/app/i18n/sk/sub.php
@@ -88,7 +88,7 @@ return array(
'_' => 'HTML + XPath + JSON dot notation (JSON in HTML)', // TODO
'xpath' => array(
'_' => 'XPath for JSON in HTML', // TODO
- 'help' => 'Example: <code>//script[@type="application/json"]</code>', // TODO
+ 'help' => 'Example: <code>normalize-space(//script[@type="application/json"])</code> (single JSON)<br />or: <code>//script[@type="application/ld+json"]</code> (one JSON object per article)', // TODO
),
),
'html_xpath' => array(
diff --git a/app/i18n/tr/sub.php b/app/i18n/tr/sub.php
index 9f7c1bf59..739d8ad77 100644
--- a/app/i18n/tr/sub.php
+++ b/app/i18n/tr/sub.php
@@ -88,7 +88,7 @@ return array(
'_' => 'HTML + XPath + JSON nokta gösterimi (HTML’de JSON)',
'xpath' => array(
'_' => 'HTML’de JSON için XPath',
- 'help' => 'Örnek: <code>//script[@type="application/json"]</code>',
+ 'help' => 'Örnek: <code>normalize-space(//script[@type="application/json"])</code> (single JSON)<br />or: <code>//script[@type="application/ld+json"]</code> (one JSON object per article)', // DIRTY
),
),
'html_xpath' => array(
diff --git a/app/i18n/zh-cn/sub.php b/app/i18n/zh-cn/sub.php
index f781915f7..75f082d08 100644
--- a/app/i18n/zh-cn/sub.php
+++ b/app/i18n/zh-cn/sub.php
@@ -88,7 +88,7 @@ return array(
'_' => 'HTML + XPath + JSON dot notation (JSON in HTML)', // TODO
'xpath' => array(
'_' => 'XPath for JSON in HTML', // TODO
- 'help' => 'Example: <code>//script[@type="application/json"]</code>', // TODO
+ 'help' => 'Example: <code>normalize-space(//script[@type="application/json"])</code> (single JSON)<br />or: <code>//script[@type="application/ld+json"]</code> (one JSON object per article)', // TODO
),
),
'html_xpath' => array(
diff --git a/app/i18n/zh-tw/sub.php b/app/i18n/zh-tw/sub.php
index 7f0413501..d0a8c91a1 100644
--- a/app/i18n/zh-tw/sub.php
+++ b/app/i18n/zh-tw/sub.php
@@ -88,7 +88,7 @@ return array(
'_' => 'HTML + XPath + JSON dot notation (JSON in HTML)', // TODO
'xpath' => array(
'_' => 'XPath for JSON in HTML', // TODO
- 'help' => 'Example: <code>//script[@type="application/json"]</code>', // TODO
+ 'help' => 'Example: <code>normalize-space(//script[@type="application/json"])</code> (single JSON)<br />or: <code>//script[@type="application/ld+json"]</code> (one JSON object per article)', // TODO
),
),
'html_xpath' => array(