Équivalent XSLT pour JSON [fermé]


411

Existe-t-il un équivalent XSLT pour JSON? Quelque chose pour me permettre de faire des transformations sur JSON comme XSLT pour XML.


1
Btw, sur quelle langue / plateforme cela serait-il?
StaxMan

6
@StaxMan XSLT est une norme qui a des implémentations réelles dans de nombreux langages et plates-formes, mes questions visent un effort similaire.
luvieere

36
+1 pour votre question. Beaucoup de gens semblent ignorer ou ne pas aimer XSLT, mais cela peut simplement être une réaction à la verbosité XML. Et en effet, comme XML tombe progressivement en disgrâce, il y a de moins en moins de possibilités d'utiliser XSLT, ce qui est dommage! Un équivalent XSLT pour JSON serait génial.
Nicolas Le Thierry d'Ennequin

10
@ NicolasLeThierryd'Ennequin D'accord. Beaucoup de gens détestent XML et rejettent donc XSLT. L'écosystème d'outils XML est également lourd sur les développeurs Java, ce qui repousse encore plus de gens. Mais j'étais lourd dans XSLT au milieu des années 2000, et il y a une puissance énorme qui n'a pas d'équivalent direct en dehors de l'écosystème XML. J'aime un équivalent JSON!
Zearin

Réponses:


77

Idée intéressante. Certaines recherches sur Google ont produit quelques pages intéressantes, notamment:

J'espère que cela t'aides.


10
Oui, merci, c'est ce que je cherchais. Dommage que la technique ne soit pas plus populaire, JSON est assez souvent utilisé comme format de retour dans les services de style REST et il serait bien d'avoir un moyen standard d'implémenter des transformations.
luvieere

8
Ce code utilise string.eval () ... :-(
dreftymac

Lien uniquement réponse
Jean-François Fabre

102

Équivalents XSLT pour JSON - une liste de candidats (outils et spécifications)

Outils

  1. XSLT

    Vous pouvez utiliser XSLT pour JSON dans le but de fn: json-to-xml .

    Cette section décrit les fonctionnalités permettant le traitement des données JSON à l'aide de XSLT.

  2. jq

    jq est comme sed pour les données JSON - vous pouvez l'utiliser pour découper et filtrer et mapper et transformer des données structurées avec la même facilité que sed, awk, grep et amis vous permettent de jouer avec du texte. Il existe des packages d'installation pour différents systèmes d'exploitation.

  3. jj

    JJ est un utilitaire de ligne de commande qui fournit un moyen rapide et simple de récupérer ou de mettre à jour des valeurs à partir de documents JSON. Il est propulsé par GJSON et SJSON sous le capot.

  4. fx

    Outil de traitement JSON en ligne de commande

    • Pas besoin d'apprendre une nouvelle syntaxe
    • JavaScript simple
    • Formatage et surlignage
    • Binaire autonome
  5. jl

    jl ("JSON lambda") est un minuscule langage fonctionnel pour interroger et manipuler JSON.

  6. SECOUSSE

    Bibliothèque de transformation JSON en JSON écrite en Java où la "spécification" pour la transformation est elle-même un document JSON.

  7. gron

    Rendez JSON accessible! gron transforme JSON en affectations discrètes pour faciliter la recherche de ce que vous voulez et voir le «chemin» absolu vers celui-ci. Il facilite l'exploration des API qui renvoient de gros objets JSON mais qui ont une documentation terrible.

  8. json

    json est un outil CLI rapide pour travailler avec JSON. Il s'agit d'un script node.js à fichier unique sans deps externe (autre que node.js lui-même).

  9. json-e

    JSON-e est un système de paramétrage de structure de données pour incorporer du contexte dans des objets JSON. L'idée centrale est de traiter une structure de données comme un "modèle" et de la transformer, en utilisant une autre structure de données comme contexte, pour produire une structure de données de sortie.

  10. JSLT

    JSLT est un langage de requête et de transformation complet pour JSON. La conception du langage est inspirée de jq, XPath et XQuery.

  11. JSONata

    JSONata est un langage de requête et de transformation léger pour les données JSON. Inspiré par la sémantique du «chemin de localisation» de XPath 3.1, il permet d'exprimer des requêtes sophistiquées dans une notation compacte et intuitive.

  12. json-transforms Last Commit 1 déc.2017

    Fournit une approche récursive d'appariement de modèles pour transformer les données JSON. Les transformations sont définies comme un ensemble de règles qui correspondent à la structure d'un objet JSON. Lorsqu'une correspondance se produit, la règle émet les données transformées, récursives éventuellement pour transformer les objets enfants.

  13. jsawk Dernier commit 4 mars 2015

    Jsawk est comme awk, mais pour JSON. Vous travaillez avec un tableau d'objets JSON lus depuis stdin, les filtrez à l'aide de JavaScript pour produire un tableau de résultats qui est imprimé sur stdout.

  14. yate Last Commit 13 mars 2017

    Les tests peuvent être utilisés comme docu https://github.com/pasaran/yate/tree/master/tests

  15. jsonpath-object-transform Last Commit 18 janv.2017

    Extrait des données d'un objet littéral à l'aide de JSONPath et génère de nouveaux objets basés sur un modèle.

  16. Agrafage Last Commit 16 sept. 2013

    Stapling est une bibliothèque JavaScript qui permet le formatage XSLT pour les objets JSON. Au lieu d'utiliser un moteur de création de modèles JavaScript et des modèles texte / html, Stapling vous donne la possibilité d'utiliser des modèles XSLT - chargés de manière asynchrone avec Ajax puis mis en cache côté client - pour analyser vos sources de données JSON.

Spécifications:

  • JsonPointer

    Le pointeur JSON définit une syntaxe de chaîne pour identifier une valeur spécifique dans un document JSON (JavaScript Object Notation).

  • JsonPath

    Les expressions JSONPath font toujours référence à une structure JSON de la même manière que l'expression XPath est utilisée en combinaison avec un document XML

  • JSPath

    JSPath pour JSON est comme XPath pour XML. "

  • JSONiq

    La principale source d'inspiration derrière JSONiq est XQuery, qui s'est avéré jusqu'à présent un langage de requête efficace et productif pour les données semi-structurées


2
Merci pour votre message très détaillé et utile. Afin de transformer json d'une ligne en une forme lisible, jq (n ° 2 dans votre liste) est pour moi le meilleur choix. Merci encore!
primehunter

1
J'utilise souvent json_pp pour de jolies impressions. Il est disponible pour de nombreuses distributions.
jschnasse

70

Essayez JOLT . Il s'agit d'une bibliothèque de transformation JSON en JSON écrite en Java.

Il a été créé spécifiquement parce que nous ne voulions pas jouer au jeu "JSON -> XML -> XSLT -> XML -> JSON", et l'utilisation d'un modèle pour toute transformation suffisamment complexe est impossible à maintenir.


4
+9000: C'est un projet sérieux! Huzzah. La démo en ligne avec des exemples aide grandement à gravir la courbe d'apprentissage: jolt-demo.appspot.com
kevinarpe

15

jq - processeur JSON en ligne de commande léger et flexible

Ce n'est pas basé sur un modèle comme XSLT, mais plus concis. par exemple pour extraire nameet addresschamps dans un tableau:[.name, .address]

Le didacticiel présente un exemple de transformation de l'API JSON de Twitter (et le manuel contient de nombreux exemples).


4
C'est plus concis car il est capable de beaucoup moins.
Ihe Onwuka

Je n'ai pas trouvé comment rechercher récursivement un attribut donné dans un arbre Json
Daniel

@Daniel est .. | .attr_name?ce que vous cherchez? (à partir de stedolan.github.io/jq/manual/#RecursiveDescent: .. )
ankostis

1
Peut-être pas aussi capable que XSLT mais très utile et pas aussi compliqué que XSLT
flq

15

XSLT prend en charge JSON comme vu sur http://www.w3.org/TR/xslt-30/#json

XML utilise des crochets angulaires pour les jetons de délimitation, JSON utilise des accolades, des crochets, ... I. e. Moins de comparaisons de reconnaissance de jetons de XML signifient qu'il est optimisé pour la transformation déclarative, tandis que plus de comparaisons, comme une instruction switch, pour des raisons de vitesse supposent une prédiction de branche spéculative pour laquelle le code impératif dans les langages de script est utile. En conséquence directe, pour différentes combinaisons de données semi-structurées, vous souhaiterez peut-être comparer les performances des moteurs XSLT et javascript dans le cadre de pages réactives. Pour une charge utile de données négligeable, les transformations peuvent tout aussi bien fonctionner avec JSON sans sérialisation XML. La décision de W3 devrait être basée sur une meilleure analyse.


15

J'ai récemment trouvé un outil que j'aime pour styliser JSON: https://github.com/twigkit/tempo . Outil très facile à utiliser - à mon avis, il est beaucoup plus facile de travailler avec XSLT - pas besoin de requêtes XPATH.


9
Le tempo a fière allure si le résultat final de la transformation est HTML. Mais que se passe-t-il si vous souhaitez simplement réorganiser une structure implicite en une structure différente, mais le résultat final est toujours JSON. Je voudrais toujours un analogue de XPath pour pouvoir écrire la transformation de manière fonctionnelle.
Toddius Zho

1
Le tempo est très intéressant en effet merci. Cependant, vous pouvez envoyer un xml au navigateur et un xslt (<? Xsl-stylesheet>) et votre navigateur appliquera le xslt au xml, montrant une vue définie de votre xml sans autre code. Cela devrait également être le cas pour jsonT / tempo.
Martin Meeser


11

Dire le manque d'outils suggère que le manque de besoins ne fait qu'engendrer la question. La même chose pourrait être appliquée à la prise en charge de X ou Y sous Linux (Pourquoi prendre la peine de développer des pilotes et / ou des jeux de qualité pour un système d'exploitation aussi minoritaire? Et pourquoi faire attention à un système d'exploitation pour lequel les grandes sociétés de jeux et de matériel ne développent pas?). Les personnes qui auraient besoin d'utiliser XSLT et JSON finiront probablement par utiliser une solution de contournement quelque peu banale: la transformation de JSON en XML. Mais ce n'est pas la solution optimale, n'est-ce pas?

Lorsque vous avez un format JSON natif et que vous souhaitez le modifier "wysywyg" dans le navigateur, XSLT serait une solution plus que adéquate au problème. Faire cela avec la programmation javascript traditionnelle peut devenir pénible.

En fait, j'ai implémenté une approche "âge de pierre" pour XSLT, en utilisant l'analyse de sous-chaîne pour interpréter certaines commandes de base pour javascript, comme appeler un modèle, traiter des enfants, etc. l'implémentation d'un analyseur XML à part entière pour analyser le XSLT. Le problème est que pour utiliser des modèles XML pour transformer un objet JSON, vous devez analyser le XML des modèles.

Pour transformer un objet JSON avec XML (ou HTML, ou texte ou autre), vous devez réfléchir soigneusement à la syntaxe et aux caractères spéciaux que vous devez utiliser pour identifier les commandes de transformation. Sinon, vous finirez par devoir concevoir un analyseur pour votre propre langage de création de modèles personnalisé. Ayant parcouru ce chemin, je peux vous dire que ce n'est pas joli.

Mise à jour (12 novembre 2010): Après quelques semaines de travail sur mon analyseur, j'ai pu l'optimiser. Les modèles sont analysés au préalable et les commandes sont stockées en tant qu'objets JSON. Les règles de transformation sont également des objets JSON, tandis que le code modèle est un mélange de HTML et d'une syntaxe homebrew similaire au code shell. J'ai pu transformer un document JSON complexe en HTML pour en faire un éditeur de document. Le code est d'environ 1K lignes pour l'éditeur (c'est pour un projet privé donc je ne peux pas le partager) et environ 990 lignes pour le code de transformation JSON (comprend les commandes d'itération, les comparaisons simples, l'appel de modèle, l'enregistrement et l'évaluation des variables). J'ai l'intention de le publier sous une licence MIT. Envoyez-moi un mail si vous souhaitez vous impliquer.


11

J'ai écrit ma propre petite bibliothèque autour de cela, récemment, qui essaie de rester aussi proche de

5.1 Modèle de traitement (XSLT REC) https://www.w3.org/TR/xslt#section-Processing-Model

comme c'est possible (comme je pourrais de toute façon), en quelques lignes de code JavaScript.

Voici quelques exemples d'utilisation pas tout à fait triviaux ...

1. JSON-to-some-markup:

Violon: https://jsfiddle.net/YSharpLanguage/kj9pk8oz/10

(inspiré par l' exemple de document D.1 (XSLT REC) https://www.w3.org/TR/xslt#section-Document-Example )

où ce:

var D1document = {
    type: "document", title: [ "Document Title" ],
    "": [
      { type: "chapter", title: [ "Chapter Title" ],
        "": [
        { type: "section", title: [ "Section Title" ],
          "": [
            { type: "para", "": [ "This is a test." ] },
            { type: "note", "": [ "This is a note." ] }
        ] },
        { type: "section", title: [ "Another Section Title" ],
          "": [
            { type: "para", "": [ "This is ", { emph: "another" }, " test." ] },
            { type: "note", "": [ "This is another note." ] }
        ] }
      ] }
    ] };

var D1toHTML = { $: [
  [ [ function(node) { return node.type === "document"; } ],
    function(root) {
      return "<html>\r\n\
  <head>\r\n\
    <title>\r\n\
      {title}\r\n".of(root) + "\
    </title>\r\n\
  </head>\r\n\
  <body>\r\n\
{*}".of(root[""].through(this)) + "\
  </body>\r\n\
</html>";
    }
  ],
  [ [ function(node) { return node.type === "chapter"; } ],
    function(chapter) {
      return "    <h2>{title}</h2>\r\n".of(chapter) + "{*}".of(chapter[""].through(this));
    }
  ],
  [ [ function(node) { return node.type === "section"; } ],
    function(section) {
      return "    <h3>{title}</h3>\r\n".of(section) + "{*}".of(section[""].through(this));
    }
  ],
  [ [ function(node) { return node.type === "para"; } ],
    function(para) {
      return "    <p>{*}</p>\r\n".of(para[""].through(this));
    }
  ],
  [ [ function(node) { return node.type === "note"; } ],
    function(note) {
      return '    <p class="note"><b>NOTE: </b>{*}</p>\r\n'.of(note[""].through(this));
    }
  ],
  [ [ function(node) { return node.emph; } ],
    function(emph) {
      return "<em>{emph}</em>".of(emph);
    }
  ]
] };

console.log(D1document.through(D1toHTML));

... donne:

<html>
  <head>
    <title>
      Document Title
    </title>
  </head>
  <body>
    <h2>Chapter Title</h2>
    <h3>Section Title</h3>
    <p>This is a test.</p>
    <p class="note"><b>NOTE: </b>This is a note.</p>
    <h3>Another Section Title</h3>
    <p>This is <em>another</em> test.</p>
    <p class="note"><b>NOTE: </b>This is another note.</p>
  </body>
</html>

et

2. JSON à JSON:

Violon: https://jsfiddle.net/YSharpLanguage/ppfmmu15/10

où ce:

// (A "Company" is just an object with a "Team")
function Company(obj) {
  return obj.team && Team(obj.team);
}

// (A "Team" is just a non-empty array that contains at least one "Member")
function Team(obj) {
  return ({ }.toString.call(obj) === "[object Array]") &&
         obj.length &&
         obj.find(function(item) { return Member(item); });
}

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

function Dude(obj) {
  return Member(obj) && (obj.sex === "Male");
}

function Girl(obj) {
  return Member(obj) && (obj.sex === "Female");
}

var data = { team: [
  { first: "John", last: "Smith", sex: "Male" },
  { first: "Vaio", last: "Sony" },
  { first: "Anna", last: "Smith", sex: "Female" },
  { first: "Peter", last: "Olsen", sex: "Male" }
] };

var TO_SOMETHING_ELSE = { $: [

  [ [ Company ],
    function(company) {
      return { some_virtual_dom: {
        the_dudes: { ul: company.team.select(Dude).through(this) },
        the_grrls: { ul: company.team.select(Girl).through(this) }
      } }
    } ],

  [ [ Member ],
    function(member) {
      return { li: "{first} {last} ({sex})".of(member) };
    } ]

] };

console.log(JSON.stringify(data.through(TO_SOMETHING_ELSE), null, 4));

... donne:

{
    "some_virtual_dom": {
        "the_dudes": {
            "ul": [
                {
                    "li": "John Smith (Male)"
                },
                {
                    "li": "Peter Olsen (Male)"
                }
            ]
        },
        "the_grrls": {
            "ul": [
                {
                    "li": "Anna Smith (Female)"
                }
            ]
        }
    }
}

3. XSLT contre JavaScript:

Un équivalent JavaScript de ...

XSLT 3.0 REC Section 14.4 Exemple: regroupement de nœuds en fonction de valeurs communes

(à: http://jsfiddle.net/YSharpLanguage/8bqcd0ey/1 )

Cf. https://www.w3.org/TR/xslt-30/#grouping-examples

où...

var cities = [
  { name: "Milano",  country: "Italia",      pop: 5 },
  { name: "Paris",   country: "France",      pop: 7 },
  { name: "München", country: "Deutschland", pop: 4 },
  { name: "Lyon",    country: "France",      pop: 2 },
  { name: "Venezia", country: "Italia",      pop: 1 }
];

/*
  Cf.
  XSLT 3.0 REC Section 14.4
  Example: Grouping Nodes based on Common Values

  https://www.w3.org/TR/xslt-30/#grouping-examples
*/
var output = "<table>\r\n\
  <tr>\r\n\
    <th>Position</th>\r\n\
    <th>Country</th>\r\n\
    <th>City List</th>\r\n\
    <th>Population</th>\r\n\
  </tr>{*}\r\n\
</table>".of
  (
    cities.select().groupBy("country")(function(byCountry, index) {
      var country = byCountry[0],
          cities = byCountry[1].select().orderBy("name");
      return "\r\n\
  <tr>\r\n\
    <td>{position}</td>\r\n\
    <td>{country}</td>\r\n\
    <td>{cities}</td>\r\n\
    <td>{population}</td>\r\n\
  </tr>".
        of({ position: index + 1, country: country,
             cities: cities.map(function(city) { return city.name; }).join(", "),
             population: cities.reduce(function(sum, city) { return sum += city.pop; }, 0)
           });
    })
  );

... donne:

<table>
  <tr>
    <th>Position</th>
    <th>Country</th>
    <th>City List</th>
    <th>Population</th>
  </tr>
  <tr>
    <td>1</td>
    <td>Italia</td>
    <td>Milano, Venezia</td>
    <td>6</td>
  </tr>
  <tr>
    <td>2</td>
    <td>France</td>
    <td>Lyon, Paris</td>
    <td>9</td>
  </tr>
  <tr>
    <td>3</td>
    <td>Deutschland</td>
    <td>München</td>
    <td>4</td>
  </tr>
</table>

4. JSONiq contre JavaScript:

Un équivalent JavaScript de ...

Cas d'utilisation de JSONiq Section 1.1.2. Regroupement des requêtes pour JSON

(à: https://jsfiddle.net/YSharpLanguage/hvo24hmk/3 )

Cf. http://jsoniq.org/docs/JSONiq-usecases/html-single/index.html#jsongrouping

où...

/*
  1.1.2. Grouping Queries for JSON
  http://jsoniq.org/docs/JSONiq-usecases/html-single/index.html#jsongrouping
*/
var sales = [
  { "product" : "broiler", "store number" : 1, "quantity" : 20  },
  { "product" : "toaster", "store number" : 2, "quantity" : 100 },
  { "product" : "toaster", "store number" : 2, "quantity" : 50 },
  { "product" : "toaster", "store number" : 3, "quantity" : 50 },
  { "product" : "blender", "store number" : 3, "quantity" : 100 },
  { "product" : "blender", "store number" : 3, "quantity" : 150 },
  { "product" : "socks", "store number" : 1, "quantity" : 500 },
  { "product" : "socks", "store number" : 2, "quantity" : 10 },
  { "product" : "shirt", "store number" : 3, "quantity" : 10 }
];

var products = [
  { "name" : "broiler", "category" : "kitchen", "price" : 100, "cost" : 70 },
  { "name" : "toaster", "category" : "kitchen", "price" : 30, "cost" : 10 },
  { "name" : "blender", "category" : "kitchen", "price" : 50, "cost" : 25 },
  {  "name" : "socks", "category" : "clothes", "price" : 5, "cost" : 2 },
  { "name" : "shirt", "category" : "clothes", "price" : 10, "cost" : 3 }
];

var stores = [
  { "store number" : 1, "state" : "CA" },
  { "store number" : 2, "state" : "CA" },
  { "store number" : 3, "state" : "MA" },
  { "store number" : 4, "state" : "MA" }
];

var nestedGroupingAndAggregate = stores.select().orderBy("state").groupBy("state")
( function(byState) {
    var state = byState[0],
        stateStores = byState[1];
    byState = { };
    return (
      (
        byState[state] =
        products.select().orderBy("category").groupBy("category")
        ( function(byCategory) {
            var category = byCategory[0],
                categoryProducts = byCategory[1],
                categorySales = sales.filter(function(sale) {
                  return stateStores.find(function(store) { return sale["store number"] === store["store number"]; }) &&
                         categoryProducts.find(function(product) { return sale.product === product.name; });
                });
            byCategory = { };
            return (
              (
                byCategory[category] =
                categorySales.select().orderBy("product").groupBy("product")
                ( function(byProduct) {
                    var soldProduct = byProduct[0],
                        soldQuantities = byProduct[1];
                    byProduct = { };
                    return (
                      (
                        byProduct[soldProduct] =
                        soldQuantities.reduce(function(sum, sale) { return sum += sale.quantity; }, 0)
                      ),
                      byProduct
                    );
                } ) // byProduct()
              ),
              byCategory
            );
        } ) // byCategory()
      ),
      byState
    );
} ); // byState()

... donne:

[
  {
    "CA": [
      {
        "clothes": [
          {
            "socks": 510
          }
        ]
      },
      {
        "kitchen": [
          {
            "broiler": 20
          },
          {
            "toaster": 150
          }
        ]
      }
    ]
  },
  {
    "MA": [
      {
        "clothes": [
          {
            "shirt": 10
          }
        ]
      },
      {
        "kitchen": [
          {
            "blender": 250
          },
          {
            "toaster": 50
          }
        ]
      }
    ]
  }
]

Il est également utile de surmonter les limitations de JSONPath wrt. interroger contre l'axe des ancêtres, comme soulevé par cette question SO (et certainement d'autres).

Par exemple, comment obtenir la remise d'un article d'épicerie en connaissant son identifiant de marque, en

{
 "prods": [
    {
        "info": {
              "rate": 85
                },
        "grocery": [
                 {
                  "brand": "C",
                  "brand_id": "984"
                 },
                 {
                  "brand": "D",
                  "brand_id": "254"
                 }
                 ],
         "discount": "15"
    },
    {
        "info": {
              "rate": 100
                },
        "grocery": [
                 {
                  "brand": "A",
                  "brand_id": "983"
                 },
                 {
                  "brand": "B",
                  "brand_id": "253"
                 }
                 ],
         "discount": "20"
     }
 ]
}

?

Une solution possible est:

var products = {
     "prods": [
        {
            "info": {
                  "rate": 85
                    },
            "grocery": [
                     {
                      "brand": "C",
                      "brand_id": "984"
                     },
                     {
                      "brand": "D",
                      "brand_id": "254"
                     }
                     ],
             "discount": "15"
        },
        {
            "info": {
                  "rate": 100
                    },
            "grocery": [
                     {
                      "brand": "A",
                      "brand_id": "983"
                     },
                     {
                      "brand": "B",
                      "brand_id": "253"
                     }
                     ],
             "discount": "20"
         }
     ]
};

function GroceryItem(obj) {
  return (typeof obj.brand === "string") && (typeof obj.brand_id === "string");
}

    // last parameter set to "true", to grab all the "GroceryItem" instances
    // at any depth:
var itemsAndDiscounts = [ products ].nodeset(GroceryItem, true).
    map(
      function(node) {
        var item = node.value, // node.value: the current "GroceryItem" (aka "$.prods[*].grocery[*]")

            discount = node.parent. // node.parent: the array of "GroceryItem" (aka "$.prods[*].grocery")
                       parent. // node.parent.parent: the product (aka "$.prods[*]")
                       discount; // node.parent.parent.discount: the product discount

        // finally, project into an easy-to-filter form:
        return { id: item.brand_id, discount: discount };
      }
    ),
    discountOfItem983;

discountOfItem983 = itemsAndDiscounts.
  filter
  (
    function(mapped) {
      return mapped.id === "983";
    }
  )
  [0].discount;

console.log("Discount of #983: " + discountOfItem983);

... qui donne:

Discount of #983: 20

«HTH,


10

Il y a maintenant! J'ai récemment créé une bibliothèque, json-transforms , exactement à cet effet:

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

Il utilise une combinaison de JSPath , une DSL sur le modèle de XPath et une approche de correspondance de modèle récursive, directement inspirée de XSLT.

Voici un petit exemple. Étant donné l'objet JSON suivant:

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 }
  ]
};

Voici une transformation:

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

Qui a produit les éléments suivants:

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

Cette transformation est composée de trois règles. Le premier correspond à toute automobile fabriquée par Honda, émettant un objet avec une Hondapropriété, puis correspondant récursivement. La deuxième règle fait correspondre tout objet avec une makerpropriété, produisant les propriétés modelet year. La finale est la transformation d'identité qui correspond récursivement.


9

Comme encore une autre nouvelle réponse à une vieille question, je suggère un regard sur DefiantJS . Ce n'est pas un XSLT équivalent pour JSON, il est XSLT pour JSON. La section "Modèles" de la documentation inclut cet exemple:

<!-- Defiant template -->
<script type="defiant/xsl-template">
    <xsl:template name="books_template">
        <xsl:for-each select="//movie">
            <xsl:value-of select="title"/><br/>
        </xsl:for-each>
    </xsl:template>
</script>

<script type="text/javascript">

var data = {
        "movie": [
            {"title": "The Usual Suspects"},
            {"title": "Pulp Fiction"},
            {"title": "Independence Day"}
        ]
    },
    htm = Defiant.render('books_template', data);

console.log(htm);
// The Usual Suspects<br>
// Pulp Fiction<br>
// Independence Day<br>

5

Je suis vraiment fatigué de l'énorme quantité de moteurs de création de modèles JavaScript et de tous leurs modèles HTML en ligne, de différents styles de balisage, etc., et j'ai décidé de créer une petite bibliothèque qui permet le formatage XSLT pour les structures de données JSON. Pas du tout sorcier - c'est juste JSON analysé en XML puis formaté avec un document XSLT. Il est également rapide, pas aussi rapide que les moteurs de modèles JavaScript dans Chrome, mais dans la plupart des autres navigateurs, il est au moins aussi rapide que l'alternative du moteur JS pour les structures de données plus volumineuses.


4

J'utilise la route Camel umarshal (xmljson) -> vers (xlst) -> marshal (xmljson). Assez efficace (mais pas parfait à 100%), mais simple, si vous utilisez déjà Camel.


3

JSONiq est une telle norme et Zorba une implémentation C ++ open source. JSONiq peut également être considéré comme XQuery avec l'ajout de JSON comme type de données natif.



2

Yate ( https://github.com/pasaran/yate ) est spécialement conçu après XSLT, dispose de JPath (un équivalent XPath naturel pour JS), se compile en JavaScript et a tout un historique d'utilisation en production. C'est pratiquement non documenté, mais la lecture des échantillons et des tests devrait suffire.


2

JSLT est très proche d'un équivalent JSON de XSLT. Il s'agit d'un langage de transformation dans lequel vous écrivez la partie fixe de la sortie dans la syntaxe JSON, puis insérez des expressions pour calculer les valeurs que vous souhaitez insérer dans le modèle.

Un exemple:

{
  "time": round(parse-time(.published, "yyyy-MM-dd'T'HH:mm:ssX") * 1000),
  "device_manufacturer": .device.manufacturer,
  "device_model": .device.model,
  "language": .device.acceptLanguage
}

Il est implémenté en Java sur Jackson.


0

Je ne sais pas trop si cela est nécessaire, et pour moi le manque d'outils suggère le manque de besoin. JSON est mieux traité en tant qu'objets (comme c'est fait dans JS de toute façon), et vous utilisez généralement le langage des objets lui-même pour effectuer des transformations (Java pour les objets Java créés à partir de JSON, de même pour Perl, Python, Perl, c #, PHP, etc.) sur). Juste avec des affectations normales (ou set, get), en boucle et ainsi de suite.

Je veux dire, XSLT n'est qu'un autre langage, et l'une des raisons pour lesquelles il est nécessaire est que XML n'est pas une notation d'objet et que les objets des langages de programmation ne sont donc pas des ajustements exacts (impédance entre le modèle xml hiérarchique et les objets / structures).


Après la conversion de Facebook de XML en Json, j'ai désespérément besoin d'un outil comme celui-ci.
Joe Soul-bringer

Quel cas d'utilisation pensez-vous? Est-ce pour pouvoir rendre le contenu JSON de la même manière que vous rendriez les réponses XML en HTML? Ou quelque chose de différent?
StaxMan

Je me demande à quel point il serait facile de manipuler la transformation JSON de la manière objet programmatique (avec boucle, branchement selon les besoins, etc.) par rapport à l'utilisation de la méthode de type XSLT, en particulier en cas de transformation d'un objet JSON massif et où certaines données du JSON source sont déplacées monter / descendre certains nœuds dans le JSON cible (donc pas simplement une copie directe de la structure) et dire où un nœud particulier dans le JSON source ou cible fait partie du tableau d'objets dans le JSON et l'autre JSON (source / cible) n'est pas .
David

La facilité est très subjective, donc je soupçonne que cela a beaucoup à voir avec ce à quoi on est habitué.
StaxMan

Bien qu'il y ait définitivement un besoin de transformation JSON, vous avez raison, JS le satisfait en grande partie. :-) Mais avez-vous vu jq - un processeur JSON en ligne de commande léger et flexible ? Surtout quand JS n'est pas disponible. Je dirais que la transformation est considérablement plus facile et plus intuitive, même que JS. par exemple pour extraire les champs nameet address, et les mettre dans un tableau:[.name, .address]
13ren

0

Pourquoi ne convertissez-vous pas JSON en XML à l'aide de Mr. Data Coverter , transformez-le en utilisant XSLT, puis changez-le en JSON en utilisant le même.


1
Ce n'est pas une option si vous voulez que votre code le fasse pour vous avec de bonnes performances.
orad

0

Pour un doodle fonctionnel / preuve de concept d'une approche pour utiliser du JavaScript pur avec le modèle familier et déclaratif derrière les expressions correspondantes et les modèles récursifs de XSLT, voir https://gist.github.com/brettz9/0e661b3093764f496e36

(Une approche similaire pourrait être adoptée pour JSON.)

Notez que la démo s'appuie également sur les fermetures d'expressions JavaScript 1.8 pour faciliter l'expression des modèles dans Firefox (au moins jusqu'à ce que la forme abrégée ES6 pour les méthodes puisse être implémentée).

Avertissement: Ceci est mon propre code.


0

J'ai écrit un adaptateur dom pour mon framework de traitement json basé sur jackson il y a longtemps. Il utilise la bibliothèque nu.xom. L'arbre dom résultant fonctionne avec les fonctionnalités java xpath et xslt. J'ai fait des choix d'implémentation qui sont assez simples. Par exemple, le nœud racine est toujours appelé "racine", les tableaux vont dans un nœud ol avec des sous-éléments li (comme en html), et tout le reste n'est qu'un sous-nœud avec une valeur primitive ou un autre nœud d'objet.

JsonXmlConverter.java

Usage: JsonObject sampleJson = sampleJson(); org.w3c.dom.Document domNode = JsonXmlConverter.getW3cDocument(sampleJson, "root");


0

Une approche non encore donnée consiste à utiliser un générateur d'analyseur pour créer un analyseur en XSLT qui analyse JSON et produit une sortie XML.

Une option qui est souvent mentionnée lors des conférences XML est le générateur d'analyseur ReX ( http://www.bottlecaps.de/rex/ ) - bien que totalement non documenté sur le site, des recettes sont disponibles sur la recherche.


0

Il peut être possible d'utiliser XSLT avec JSON. Verson 3 de XPath (3.1) XSLT (3.0) et XQuery (3.1) prend en charge JSON d'une manière ou d'une autre. Cela semble être disponible dans la version commerciale de Saxon, et pourrait à un moment donné être inclus dans la version HE. https://www.saxonica.com/html/documentation/functions/fn/parse-json.html

-

Ce que j'attendrais d'une solution alternative:

Je voudrais pouvoir entrer JSON pour récupérer un ensemble de données correspondant et produire JSON ou TEXT.

Accéder à des propriétés arbitraires et évaluer les valeurs

Prise en charge de la logique conditionnelle

Je voudrais que les scripts de transformation soient externes à l'outil, basés sur du texte et de préférence une langue couramment utilisée.

Alternative potentielle?

Je me demande si SQL pourrait être une alternative appropriée. https://docs.microsoft.com/en-us/sql/relational-databases/json/json-data-sql-server

Ce serait bien si l'outil alternatif pouvait gérer JSON et XML https://docs.microsoft.com/en-us/sql/relational-databases/xml/openxml-sql-server

Je n'ai pas encore essayé de convertir les scripts XSLT que j'utilise en SQL, ni évalué pleinement cette option pour le moment, mais j'espère y réfléchir plus rapidement. Juste quelques réflexions jusqu'à présent.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.