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

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

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

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

13
додано Автор sgwill, джерело
Мені також було цікаво: json-template.googlecode. com/svn/trunk/doc/& hellip;
додано Автор sgwill, джерело
Так, спасибі, я думаю, ваше рішення @ user2813274 (і, зокрема, Роберт Харві, "Stapling", згаданий в stackoverflow.com/a/ 10529400/271577 ) може задовольнити мої потреби. Якщо хтось будує реалізацію XSLT 3.0 в JS, то ми повинні бути встановлені, оскільки це має функції для імпорту та перетворення JSON в xml (і назад до JSON, якщо потрібно).
додано Автор user21948, джерело
Дякуємо, але я більше зацікавлений у використанні стандартного підходу (наприклад, принаймні один з потенційними, враховуючи, що загальні вирази шляху JSON були б загальновизнаним засобом посилання на JSON, а не на певний синтаксис, що відноситься до бібліотеки).
додано Автор user21948, джерело
Просто випадкова думка, JavaScript і вуса/ручки, може бути? :)
додано Автор Knerd, джерело
XSLT доступні для конвертації в/з json вже, як це
додано Автор digixplo1729, джерело
Я зробив Json -> xml -> XSLT -> Json раніше - він працює нормально, навіть якщо це не найефективніше рішення,
додано Автор digixplo1729, джерело

5 Відповіді

XML: XSLT :: JSON: x . Що таке 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, вони також взагалі вирішуватимуть це робити рідною мовою, а не додавати додаткову "іноземну" систему трансформації.

25
додано
Незважаючи на те, що у XSLT є щось таке, що неможливо реплікувати. JSON, безумовно, буде складнішим синтаксисом для написання придатного для використання еквівалента.
додано Автор Nick, джерело
SpahQL, схоже, не має своїх власних шаблонів, тому, як і раніше, немає претендентів, які б використовували чистий JavaScript або JSON для коду шаблону (разом з структурами даних), навіть якщо є бібліотеки, які дозволяють вираження HTML як JSON/JS.
додано Автор user21948, джерело
+1, оскільки це продумана відповідь, але я все ще думаю, що чистіше мати купу лінійно розташованих шаблонів з бібліотекою, яка виконує перехід, і хоча я думаю, що ви, мабуть, маєте рацію щодо ставлення до XSL (я б схилятися до табору, думаючи, що це питання форматування, хоча рекурсивний стиль, безумовно, потребує деякого пристосування), я можу посперечатися, що деякі проблеми можуть бути інерцією в необхідності розробки такої мови, щоб використовувати її (наприклад, я знаходжу Навіть сам JSONPath потребує декількох покращень).
додано Автор user21948, джерело

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

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

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

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

7
додано
У випадку, якщо є якісь сумніви, я думаю, що відповідь Джонатана велика; Я просто хотів додати альтернативну перспективу.
додано Автор Jeremy Stein, джерело
Я маю власну бібліотеку Jamilih, яку я висловлюю за вираження сирого HTML як JS/JSON, але мені потрібно щось відчувати природне, і я сподіваюся, що він помітний для 1) Шаблони та відповідні шляхи 2) Ітерація API, еквівалентна xsl: apply-templates та xsl: call-template (xsl: for-each очевидний для JS, але не JSON). Для JS, я міг би використовувати функції для шаблонів і для JSON (на основі Jamilih і тих ітераційних API). Поспішає, як вона йде ...
додано Автор user21948, джерело
Так, справедливі моменти (і так: XPath є еквівалентом для другої частини), але я зацікавлений у тому, щоб мій JS XSL (називаючи його JTLT) використовував розширений JSONPath перетворення JSON на іншу мову теж (тобто HTML як string або DOM).
додано Автор user21948, джерело

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

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

( [jslt.min.js] важить ~ 3.1kb мінімізовано

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

function Per ( subject ) { ... }

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

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

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

1) Тема Array

nodeset creation/filtering/flattening/grouping/абоdering/etc, if subject is an array, where the resulting nodeset (an Array as well) is extended с, і bound to methods named accабоdingly (only the returned Array instance of the call to Per ( subjectArray ) is extended; i.e., Array.prototype is left untouched)

i.e., Per :: Array --> Array

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

2) Тема String

string interpolation, if subject is a string

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

i.e., 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) Transfабоm subject

XSLT look-alike transfабоmation, if the subject is a hash с a conventionally-defined "$" member providing the array of rewriting rules (і same as in (2), "Per" потім returns an object с a method map ( source ) bound to the subject transfабоm -- where

"ruleName" in Per ( subjectTransfабоm [ , ruleName ]) is optional і provides functionality similar to ...)

i.e., Per :: (Transfабоm [ , ruleName :: String ]) --> { map :: (AnyValue --> AnyValue) }

с

Transfабоm :: { $ :: Array of rewriting rules[rw.r.] }

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

наприклад, given (... another contrived example)

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

var a_transfабоm = { $: [
//...
  [ [ Member ],//(alike ...)
      function(member) {
        return {
          li: Per("{first} {last}").map(member) +
              " " +
              Per(this).map({ gender: member.sex })
        };
      }
  ],

  [ [ function(info) { return info.gender; } ],//(alike ...)
      function(info) { return Per("(gender: {gender})").map(info); }
  ],

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

потім

Per(a_transfабоm).map({ "first": "John", "last": "Smith", "sex": "Male" })

врожаї:

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

while... (much alike ...)

"James Bond... " +
Per(a_transfабоm, "betterGenderString").map({ "pronoun": "his", "gender": "Male" })

врожаї:

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

і

"Someone... " +
Per(a_transfабоm, "betterGenderString").map({ "gender": "Male або Female" })

врожаї:

"Someone... (his/her gender is Male або Female)"

4) Інакше

the identity function, in all other cases

i.e., Per :: T --> T

(наприклад, Per === функція (значення) {повертається значення;} )

Примітка

in (3) above, a JavaScript's "this" in the body of a template function is thus bound to the container/owner Transfабоm і its set of rules (as defined by the $: [ ... ] array) -- therefабоe, making the expression "Per(this)", in that context, a functionally-close equivalent to XSLT's

'HTH,

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

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

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 . Останнім є перетворення ідентичності, яке рекурсивно збігається.

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

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

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

1
додано
ІТ КПІ - JavaScript
ІТ КПІ - JavaScript
504 учасників

співтовариство javascript розробників в Telegram