Еквівалент XSLT для JSON


15

Мені було цікаво знайти (або за потреби розробити) еквівалент XSLT для JSON.

Оскільки я не знайшов жодного, я розглядав можливу мову запитів, щоб використовувати для узгодження шляхів до JSON, щоб застосувати шаблони (з JavaScript), коли була відповідність (ймовірно, просто перевіряла масив відповідних шаблонів за порядком і зупинялась на перший шаблон, який відповідає, хоча дозволяє використовувати еквівалент xsl: apply-templates, щоб тримати шаблони для дітей).

Мені відомі JSONPath, JSONQuery і RQL як мови запитів JSON (хоча мені було не зовсім зрозуміло, чи підтримує RQL абсолютні та відносні шляхи). Будь-які пропозиції щодо факторів, які слід враховувати, та відносні переваги кожного щодо такого використання.


Просто випадкова думка, можливо, JavaScript і вуса / ручки, можливо? :)
Кнерд

Дякую, але я більше прагну використовувати стандартний підхід (наприклад, принаймні один із потенціалом, враховуючи, що загальні вирази шляху JSON були б загальновизнаним засобом посилання на JSON на відміну від синтаксису, характерного для бібліотеки).
Бретт Замір


1
Також мені це було цікаво: json-template.googlecode.com/svn/trunk/doc/…
Роберт Харві

Я робив Json -> XML -> XSLT -> Json раніше - він працює чудово, навіть якщо це не найефективніше рішення,
user2813274

Відповіді:


27

XML: XSLT :: JSON: x . Що таке х ?

Найдоцільнішою відповіддю буде x = JavaScript. Хоча ви могли б зробити справу для цього, це відчуває себе незадовільно. Навіть незважаючи на те, що XSLT технічно є Тюрінгом завершеним , між декларативом є погана відповідність стилем XSLT та більш імперативними чи функціональними стилями, що спостерігаються в JavaScript.

Є кілька самостійних мов запитів JSON, таких як JSONPath , JSONiq та RQL, які можуть стояти серед середнього рівня XML: XPath :: JSON: y (або, можливо, XQuery, а не XPath). І кожна база даних, орієнтована на JSON, має мову запитів, пов’язану з JSON .

Але реальність така, незважаючи на те, що є кілька претендентів на повну позицію XSLT, наприклад SpahQL , немає загальновизнаних, широко підтримуваних JSON еквівалентів XSLT.

Чому?

З усього JSON у світі, чому не існує (більш прямого) аналога XSLT? Оскільки багато розробників розглядають XSLT як невдалий експеримент. Будь-яка пошукова система призведе до цитат на кшталт "XSLT - це невдача, загорнута болем". Інші стверджували, що якби це було просто краще відформатовано, воно було б більш популярним. Але інтерес до XSLT з часом зменшувався . Багато інструментів, які підтримують його, підтримують лише версію 1.0 , що є специфікацією 1999 року. П'ятнадцятирічні специфікації? Є набагато новіша специфікація 2.0, і якби люди були захоплені XSLT, це було б підтримано. Це не так.

За великим рахунком розробники вирішили обробляти та перетворювати XML документи з кодом, а не шаблонами перетворення. Тому не дивно, що, працюючи з JSON, вони також за великим рахунком вирішать робити це рідною мовою, а не додавати додаткову систему "іноземної" трансформації.


2
+1, оскільки це продумана відповідь, але я все ще вважаю, що чистіше мати купу лінійно розташованих шаблонів, коли бібліотека виконує перегляд, і, хоча я думаю, ви, мабуть, праві щодо ставлення до XSL (я б схиляюся до табору, думаючи, що це питання форматування, хоча рекурсивний стиль, правда, потребує певного привчання), я б ставлю на облік, що частина проблеми може бути інертною у необхідності розробки такої мови для того, щоб її використовувати (наприклад, я знаходжу навіть сам JSONPath потребує декількох удосконалень).
Бретт Замір

Здається, що SpahQL не має власних шаблонів, тому все ще здається, що немає конкурентів, які фактично використовують чистий JavaScript або JSON для коду шаблону (поряд із структурами даних), хоча є бібліотеки, які дозволяють виражати HTML як JSON / JS.
Бретт Замір

1
+1, незважаючи на те, що в XSLT є щось, що більше нічого не вдається копіювати. JSON, безумовно, буде складнішим синтаксисом, щоб написати відповідний еквівалент.
користувач52889

7

Хоча Джонатан значною мірою говорить про природу XSLT як мови у своїй відповіді, я думаю, є ще один кут, який слід розглянути.

Метою XSLT було перетворення XML-документів у якийсь інший документ (XML, HTML, SGML, PDF тощо). Таким чином, XSLT часто використовується, ефективно, як мова шаблонів.

Існує величезний набір бібліотек шаблонів, навіть якщо ви обмежуєте себе бібліотеками JavaScript (чого вам не потрібно, оскільки JS в JSON посилається лише на генезис позначень і не слід вважати, що JSON призначено лише для JavaScript). Цей селектор двигуна шаблону дає та вказує на різноманітність варіантів JS, які там є.

В останній половині ваших запитань детальніше йдеться про мови запитів, і XML-версія їх буде XPath (а не XSLT). Як ви зазначали, є різні варіанти, і я нічого не можу додати до цього списку. Цей район відносно новий, тому я б запропонував вибрати один і просто піти з ним.


Якщо є сумніви, я вважаю, що відповідь Джонатана чудова; Я просто хотів додати альтернативну точку зору.
Dancrumb

Так, справедливі бали (і так повторно: XPath є еквівалентом другої частини), але мені цікаво бачити, як мій JS XSL (називаючи його JTLT) використовує розширене перетворення JSONPath JSON в іншу мову (тобто HTML як рядок або DOM).
Бретт Замір

У мене є власна бібліотека під назвою Джаміліх, яку я віддаю перевагу висловлюванню сирого HTML як JS / JSON, але мені потрібно щось природне, і я сподіваюсь, що захоплююче 1) Шаблони та відповідність шляху 2) Ітераційні API, еквівалентні xsl: apply-templates та xsl: шаблон виклику (xsl: для-кожного очевидний для JS, але не JSON). Для JS я міг би використовувати функції як для шаблонів, так і для JSON (на основі Jamilih та тих ітераційних API). Wills ee як це йде ...
Бретт Замір

3

Ось кілька прикладів того, що ви можете зробити з моїм (малим [jslt.min.js] ) JSLT - полегшеними перетвореннями JavaScript:

https://jsfiddle.net/YSharpLanguage/c7usrpsL/10

( [jslt.min.js] важить ~ 3,1 кбіт мінімізовано )

тобто лише одна функція,

function Per ( subject ) { ... }

... що наслідує модель обробки XSLT (1.0) .

(пор. внутрішні функції "перетворення" та "шаблон" у тілі Пер)

Таким чином, по суті, це просто все, що вкладається в той сингл, function Per ( subject ) { ... }який формує свою оцінку за типом свого (також) унікального аргументу, щоб реалізувати:

1) Тема масиву

Створення набору вузлів / фільтрація / уплощение / Угруповання / впорядкування / і т.д. , якщо об'єкт є масив, в якому результуючий набір вузли (ий масив , а) тривають с, і пов'язані з методами , названих відповідним чином ( тільки повертається масивом екземпляром виклику Per ( subjectArray )IS розширено; тобто Array.prototype залишається недоторканим)

тобто Per :: Array --> Array

(отримані методи розширення масиву , що мають пояснювальні назви, такі як, groupBy, orderBy, flattenBy тощо - див. використання у прикладах)

2) Строковий предмет

інтерполяція рядків , якщо предметом є рядок

("Per" потім повертає об'єкт методом map ( source ), який пов'язаний з рядком шаблону теми )

тобто Per :: String --> {map :: ( AnyValue --> String )}

наприклад,

Per("Hi honey, my name is {last}. {first}, {last}.").map({ "first": "James", "last": "Bond" })

врожайність:

"Hi honey, my name is Bond. James, Bond."

в той час як будь-який з

Per("Those '{*}' are our 10 digits.").map([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ])

або

Per("Those '{*}' are our 10 digits.").map(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)

врожаї ж:

"Those '0123456789' are our 10 digits."

але тільки

Per("Those '{*}' are our 10 digits.").map([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ], ", ")

врожайність

"Those '0, 1, 2, 3, 4, 5, 6, 7, 8, 9' are our 10 digits."

3) Перетворення суб'єкта

XSLT подібне перетворення , якщо суб'єкт є хеш із умовно визначеним "$" членом, що забезпечує масив правил переписування (і те саме, що в (2), "Per" потім повертає об'єкт методом, map ( source )прив'язаним до суб'єкта перетворити - куди

"ruleName" в не Per ( subjectTransform [ , ruleName ])є обов'язковим і забезпечує функціональність, схожу на <xsl: call-template name = "templateName"> ...)

тобто Per :: ( Transform [, ruleName :: String ]) -->{map :: ( AnyValue --> AnyValue )}

з

Трансформація :: {$ :: Масив правил переписування [rw.r.] }

( [rw.r.] пари функцій предикатів і шаблонів)

наприклад, дано (... інший надуманий приклад)

// (A "Member" must have first and last names, and a gender)
function Member(obj) {
  return obj.first && obj.last && obj.sex;
}

var a_transform = { $: [
//...
  [ [ Member ], // (alike <xsl:template match="...">...)
      function(member) {
        return {
          li: Per("{first} {last}").map(member) +
              " " +
              Per(this).map({ gender: member.sex })
        };
      }
  ],

  [ [ function(info) { return info.gender; } ], // (alike <xsl:template match="...">...)
      function(info) { return Per("(gender: {gender})").map(info); }
  ],

  [ [ "betterGenderString" ], // (alike <xsl:template name="betterGenderString">...)
      function(info) {
        info.pronoun = info.pronoun || "his/her";
        return Per("({pronoun} gender is {gender})").map(info);
      }
  ]
//...
] };

потім

Per(a_transform).map({ "first": "John", "last": "Smith", "sex": "Male" })

врожайність:

{ "li": "John Smith (gender: Male)" }

поки ... (дуже схоже <xsl:call-template name="betterGenderString">...)

"James Bond... " +
Per(a_transform, "betterGenderString").map({ "pronoun": "his", "gender": "Male" })

врожайність:

"James Bond... (his gender is Male)"

і

"Someone... " +
Per(a_transform, "betterGenderString").map({ "gender": "Male or Female" })

врожайність:

"Someone... (his/her gender is Male or Female)"

4) Інакше

функція ідентичності у всіх інших випадках

тобто, Per :: T --> T

(тобто Per === function ( value ) { return value ; })

Примітка

у (3) вище, JavaScript "це" в тілі функції шаблону, таким чином, пов'язаний з контейнером / власником Transform та його набором правил (як визначено масивом $: [...]) - отже, роблячи вираз "Per (this)" у цьому контексті функціонально близьким еквівалентом XSLT

<xsl:apply-templates select="..."/>

'HTH,


1
Це досить круто.
Роберт Харві

@RobertHarvey: окрім того, що я помітив уже давно, про те, що я помітив давно, у розділі 5.1 , я врешті-решт також зацікавився і надихнувся прикметним зауваженням Евана Ленца "XSLT простіший, ніж ти думаєш!", На http: // www. lenzconsulting.com/how-xslt-works - і тому я вирішив спробувати перевірити цю претензію (якщо тільки з цікавості) на дуже податливій мові, якою є JavaScript.
YSharp

Дуже дякую за детальну відповідь. Я зайнятий деякими іншими речами (включаючи мій власний еквівалент XSLT), але я маю намір повернутися до цього, щоб більш уважно подивитися.
Бретт Замір

3

Нещодавно я створив бібліотеку json-перетворення саме для цієї мети:

https://github.com/ColinEberhardt/json-transforms

Він використовує комбінацію JSPath , DSL за моделлю XPath та рекурсивний підхід відповідності шаблону, натхненний безпосередньо XSLT.

Ось короткий приклад. З огляду на наступний об’єкт JSON:

const json = {
  "automobiles": [
    { "maker": "Nissan", "model": "Teana", "year": 2011 },
    { "maker": "Honda", "model": "Jazz", "year": 2010 },
    { "maker": "Honda", "model": "Civic", "year": 2007 },
    { "maker": "Toyota", "model": "Yaris", "year": 2008 },
    { "maker": "Honda", "model": "Accord", "year": 2011 }
  ]
};

Ось перетворення:

const jsont = require('json-transforms');
const rules = [
  jsont.pathRule(
    '.automobiles{.maker === "Honda"}', d => ({
      Honda: d.runner()
    })
  ),
  jsont.pathRule(
    '.{.maker}', d => ({
      model: d.match.model,
      year: d.match.year
    })
  ),
  jsont.identity
];

const transformed  = jsont.transform(json, rules);

Вихід якого:

{
  "Honda": [
    { "model": "Jazz", "year": 2010 },
    { "model": "Civic", "year": 2007 },
    { "model": "Accord", "year": 2011 }
  ]
}

Ця трансформація складається з трьох правил. Перший відповідає будь-якому автомобілю, який виготовляє Honda, випромінюючи предмет з Hondaвластивістю, а потім рекурсивно відповідає. Друге правило відповідає будь-якому об'єкту з makerвластивістю, виводить modelі yearвластивості. Фінал - трансформація ідентичності, яка рекурсивно відповідає.


+1 і спасибі за інформацію. Я сподіваюся завершити свій власний github.com/brettz9/jtlt в якийсь момент, але корисно мати більше реалізацій для порівняння.
Бретт Замір

-1

Я не думаю, що ви коли-небудь отримаєте варіант JSON для JSON. Існує кілька двигунів-шаблонів, таких як Jinja2 Python, JavaScripts Nunjucks, Groovy MarkupTemplateEngine та багато інших, які повинні бути добре підібрані до того, що ви хочете. .NET має підтримку серіалізації / десеріалізації T4 та JSON, тому у вас також є.

Оскільки дерсеріалізовані дані JSON в основному будуть словником або структурою карти, то це просто перейде до вашого механізму шаблонів, і ви перейдете до потрібних вузлів там. Дані JSON потім трансформуються шаблоном.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.