Преглед изворни кода

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
Alexandre Alapetite пре 1 година
родитељ
комит
9114b9a06a

+ 19 - 2
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 {

+ 1 - 1
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(

+ 1 - 1
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(

+ 1 - 1
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(

+ 1 - 1
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(

+ 3 - 3
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(

+ 1 - 1
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(

+ 1 - 1
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(

+ 1 - 1
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(

+ 1 - 1
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(

+ 1 - 1
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(

+ 1 - 1
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(

+ 1 - 1
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(

+ 1 - 1
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(

+ 1 - 1
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(

+ 1 - 1
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(

+ 1 - 1
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(

+ 1 - 1
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(

+ 1 - 1
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(

+ 1 - 1
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(

+ 1 - 1
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(

+ 1 - 1
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(

+ 1 - 1
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(

+ 1 - 1
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(

+ 1 - 1
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(

+ 1 - 1
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(

+ 1 - 1
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(