equivalente XSLT per JSON

13

Ero interessato a trovare (o se necessario lo sviluppo) un equivalente XSLT per JSON.

Come non ne ho trovato, stavo considerando il possibile linguaggio di query da utilizzare per la corrispondenza dei percorsi JSON in modo da applicare i template (da JavaScript) quando c'era una corrispondenza (probabilmente solo controllando un array di pattern corrispondenti in ordine, e fermandosi al primo modello che corrisponde, pur consentendo l'equivalente di xsl: apply-templates per mantenere i template attivi per i bambini).

Sono a conoscenza di JSONPath, JSONQuery e RQL come linguaggi di query JSON (sebbene non fosse chiaro se RQL supportava percorsi assoluti e relativi). Qualsiasi suggerimento su fattori da considerare e relativi vantaggi di ciascuno verso tale utilizzo.

    
posta Brett Zamir 05.12.2014 - 22:14
fonte

5 risposte

26

XML: XSLT :: JSON: x . Che cos'è x ?

La risposta più facile sarebbe x = JavaScript. Sebbene tu possa giustificare questo, è insoddisfacente. Anche se XSLT è tecnicamente Turing completo , c'è una scarsa corrispondenza tra declarativo stile di XSLT e gli stili più imperativi o funzionali visti in JavaScript.

Esistono alcuni linguaggi di query JSON standalone, come JSONPath , JSONiq e RQL che potrebbe rappresentare una via di mezzo per XML: XPath :: JSON: y (o possibilmente, XQuery piuttosto che XPath). E ogni database di documenti incentrato su JSON ha un linguaggio di query relativo a JSON .

Ma la realtà è che, nonostante ci siano alcuni contendenti per la posizione XSLT completa, come SpahQL , non ci sono equivalenti JSON generalmente accettati e ampiamente supportati su XSLT.

Perché?

Con tutto il JSON nel mondo, perché non c'è c'è un (più diretto) analogico a XSLT? Perché molti sviluppatori considerano XSLT come un esperimento fallito. Qualsiasi motore di ricerca porterà a citazioni come "XSLT è un fallimento avvolto nel dolore". Altri hanno sostenuto che se fosse stato formattato meglio sarebbe più popolare. Tuttavia, l'interesse per XSLT è generalmente diminuito nel corso degli anni . Molti strumenti che supportano supportano solo versione 1.0 , che è una specifica del 1999. Le specifiche di quindici anni? C'è una specifica 2.0 molto più recente, e se la gente fosse entusiasta di XSLT, sarebbe supportata. Non lo è.

Gli sviluppatori di grandi dimensioni hanno scelto di elaborare e trasformare documenti XML con codice, non modelli di trasformazione. Pertanto, non sorprende che, lavorando con JSON, decidano anche di farlo nella loro lingua nativa, piuttosto che aggiungere un ulteriore sistema di trasformazione "estraneo".

    
risposta data 06.12.2014 - 00:08
fonte
7

Mentre Jonathan parla in gran parte della natura dell'XSLT come lingua nella sua risposta, penso che ci sia un'altra angolazione da considerare.

Lo scopo di XSLT era trasformare documenti XML in qualche altro documento (XML, HTML, SGML, PDF, ecc.). In questo modo, XSLT è usato frequentemente, efficacemente, come linguaggio template.

Esiste una vasta gamma di librerie di template, anche se ci si limita a librerie JavaScript (che non dovrebbero essere necessarie, poiché il JS in JSON si riferisce solo alla genesi della notazione e non dovrebbe essere preso in implica che JSON sia solo per JavaScript). Questo selettore del motore di template fornisce e indica la varietà di opzioni JS là fuori.

La seconda metà delle tue domande parla più dei linguaggi di query e la versione XML di questi sarebbe XPath (non XSLT). Come hai notato, ci sono una varietà di opzioni lì e non ho nulla da aggiungere a quella lista. Quest'area è relativamente nuova, quindi ti suggerisco di sceglierne una e seguirla.

    
risposta data 06.12.2014 - 22:04
fonte
3

Ecco alcuni esempi di cosa puoi fare con il mio (piccolo [jslt.min.js] ) JSLT - JavaScript Lightweight Transforms:

link

( [jslt.min.js] pesa ~ 3.1kb minified )

cioè, una sola funzione,

function Per ( subject ) { ... }

... che imita in realtà il modello di elaborazione XSLT (1.0) .

(vedi le funzioni interne "transform" e "template", nel corpo di Per)

Quindi, in sostanza, è semplicemente tutto il tutto racchiuso in quel singolo function Per ( subject ) { ... } che forks la sua valutazione sul tipo del suo argomento (anche) univoco, da implementare, sia:

1) Matrice soggetto

creazione / filtraggio / appiattimento / raggruppamento / ordinamento / etc di nodeset, se subject è un array, dove il risultante nodeset (una Array pure) viene esteso con, e associato a metodi denominati di conseguenza ( solo l'istanza Array restituita alla chiamata a Per ( subjectArray ) viene estesa, ovvero, Array.prototype non viene toccato)

vale a dire, Per :: Matrice --> Matrice

(i metodi di estensione di Array risultanti con nomi autoesplicativi come, groupBy, orderBy, flattenBy, ecc. - cf. l'uso negli esempi)

2) Stringa soggetto

interpolazione stringa , se subject è una stringa

("Per" restituisce quindi un oggetto con un metodo map ( source ) , che è associato al soggetto modello stringa)

cioè, Per :: Stringa --> {map :: ( AnyValue --> Stringa )}

per es.,

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

rendimenti:

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

mentre uno dei

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

o

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

produce lo stesso risultato:

"Those '0123456789' are our 10 digits."

ma solo

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

rendimenti

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

3) Trasforma soggetto

Trasformazione simile allo XSLT , se il soggetto è un hash con un membro convenzionalmente definito "$" che fornisce l'array di regole di riscrittura (e lo stesso di ( 2), "Per" restituisce quindi un oggetto con un metodo map ( source ) associato alla trasformazione dell'oggetto - dove

"ruleName" in Per ( subjectTransform [ , ruleName ]) è facoltativo e offre funzionalità simili a < xsl: call-template name="templateName" > ...)

cioè, Per :: ( Trasforma [ ruleName :: Stringa ]) --> {map :: ( AnyValue --> AnyValue )}

con

Trasforma : {$ :: Array delle regole di riscrittura [rw.r.] }

( [rw.r.] predicato e coppie di funzioni template)

per esempio, dato (... un altro esempio forzato)

// (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);
      }
  ]
//...
] };

poi

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

rendimenti:

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

while ... (molto simile <xsl:call-template name="betterGenderString">... )

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

rendimenti:

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

e

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

rendimenti:

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

4) Altrimenti

la funzione di identità , in tutti gli altri casi

cioè, Per :: T --> T

(cioè, Per === function ( value ) { return value ; } )

Nota

in (3) sopra, un "questo" di JavaScript nel corpo di una funzione template è quindi legato al contenitore / proprietario Transform e al suo insieme di regole (come definito da $: [ ...] array) - quindi, facendo dell'espressione "Per (this)", in quel contesto, un equivalente funzionalmente simile a XSLT

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

'HTH,

    
risposta data 04.03.2016 - 02:50
fonte
2

Recentemente ho creato una libreria, json-transforms , esattamente per questo scopo:

link

Utilizza una combinazione di JSPath , una DSL modellata su XPath e un approccio di pattern matching ricorsivo, ispirato direttamente da XSLT.

Ecco un rapido esempio. Dato il seguente oggetto 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 }
  ]
};

Ecco una trasformazione:

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);

Quale risultato:

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

Questa trasformazione è composta da tre regole. Il primo corrisponde a qualsiasi automobile prodotta da Honda, che emette un oggetto con una proprietà Honda , quindi corrisponde in modo ricorsivo. La seconda regola corrisponde a qualsiasi oggetto con una proprietà maker , che emette le proprietà model e year . La finale è la trasformazione dell'identità che corrisponde ricorsivamente.

    
risposta data 10.07.2016 - 19:41
fonte
-1

Non penso che avrai mai una variante JSON per JSON di per sé. Esistono diversi modelli di motori come Python's Jinja2, JavaScripts Nunjucks, Groovy MarkupTemplateEngine e molti altri che dovrebbero essere adatti per quello che vuoi. .NET ha il supporto per la serializzazione / deserializzazione T4 e JSON, così anche tu.

Poiché i dati DSSerializzati di JSON sarebbero fondamentalmente un dizionario o una struttura di mappe, questo passerebbe al motore dei template e verrebbe eseguito l'iterazione sui nodi desiderati. I dati JSON vengono quindi trasformati dal modello.

    
risposta data 21.01.2015 - 22:26
fonte

Leggi altre domande sui tag