XSLT equivalente para JSON [cerrado]

411

¿Hay un equivalente XSLT para JSON? Algo que me permita hacer transformaciones en JSON como XSLT hace a XML.

luvieere
fuente
1
Por cierto, ¿en qué idioma / plataforma estaría esto?
StaxMan
66
@StaxMan XSLT es un estándar que tiene implementaciones reales en muchos idiomas y plataformas, mis preguntas apuntan a un esfuerzo similar.
luvieere
36
+1 para tu pregunta. Muchas personas parecen pasar por alto o simplemente no les gusta XSLT, pero puede ser simplemente una reacción a la verbosidad XML. Y, de hecho, a medida que XML cae gradualmente en desgracia, hay cada vez menos oportunidades para usar XSLT, ¡lo cual es una pena! Un equivalente XSLT para JSON sería increíble.
Nicolas Le Thierry d'Ennequin
10
@ NicolasLeThierryd'Ennequin De acuerdo. Mucha gente odia XML y, por lo tanto, descarta XSLT. El ecosistema XML de herramientas también es pesado en los desarrolladores de Java, lo que aleja a más personas. Pero estaba muy metido en XSLT a mediados de la década de 2000, y hay un tremendo poder que no tiene un equivalente directo fuera del ecosistema XML. ¡Me encantaría un equivalente JSON!
Zearin

Respuestas:

77

Idea interesante. Algunas búsquedas en Google produjeron algunas páginas de interés, que incluyen:

Espero que esto ayude.

Tim
fuente
10
Sí, gracias, eso es lo que estaba buscando. Es una pena que la técnica no sea más popular, JSON se usa con bastante frecuencia como formato de retorno en los servicios de estilo REST y sería bueno tener una forma estándar de implementar transformaciones.
luvieere
8
Este código usa string.eval () ... :-(
dreftymac
Link only answer
Jean-François Fabre
102

Equivalentes XSLT para JSON: una lista de candidatos (herramientas y especificaciones)

Herramientas

  1. XSLT

    Puede usar XSLT para JSON con el objetivo de fn: json-to-xml .

    Esta sección describe las facilidades que permiten que los datos JSON se procesen usando XSLT.

  2. jq

    jq es como sed para datos JSON: puede usarlo para cortar, filtrar, mapear y transformar datos estructurados con la misma facilidad que sed, awk, grep y amigos le permiten jugar con texto. Hay paquetes de instalación para diferentes sistemas operativos.

  3. jj

    JJ es una utilidad de línea de comandos que proporciona una forma rápida y sencilla de recuperar o actualizar valores de documentos JSON. Funciona con GJSON y SJSON debajo del capó.

  4. fx

    Herramienta de procesamiento JSON de línea de comandos

    • No es necesario aprender una nueva sintaxis
    • JavaScript simple
    • Formateo y resaltado
    • Binario independiente
  5. jl

    jl ("JSON lambda") es un pequeño lenguaje funcional para consultar y manipular JSON.

  6. SACUDIDA

    Biblioteca de transformación JSON a JSON escrita en Java donde la "especificación" para la transformación es en sí misma un documento JSON.

  7. gron

    ¡Haz que JSON sea greppable! gron transforma JSON en asignaciones discretas para que sea más fácil buscar lo que desea y ver la 'ruta' absoluta hacia él. Facilita la exploración de las API que devuelven grandes bloques de JSON pero tienen una documentación terrible.

  8. json

    json es una herramienta CLI rápida para trabajar con JSON. Es un script de archivo único node.js sin deps externos (que no sea el nodo.js mismo).

  9. json-e

    JSON-e es un sistema de parametrización de estructura de datos para incrustar contexto en objetos JSON. La idea central es tratar una estructura de datos como una "plantilla" y transformarla, utilizando otra estructura de datos como contexto, para producir una estructura de datos de salida.

  10. JSLT

    JSLT es un lenguaje completo de consulta y transformación para JSON. El diseño del lenguaje está inspirado en jq, XPath y XQuery.

  11. JSONata

    JSONata es un lenguaje ligero de consulta y transformación para datos JSON. Inspirado en la semántica de 'ruta de ubicación' de XPath 3.1, permite que las consultas sofisticadas se expresen en una notación compacta e intuitiva.

  12. json-transforma el último compromiso Dec 1, 2017

    Proporciona un enfoque recursivo de coincidencia de patrones para transformar los datos JSON. Las transformaciones se definen como un conjunto de reglas que coinciden con la estructura de un objeto JSON. Cuando se produce una coincidencia, la regla emite los datos transformados, opcionalmente recurriendo para transformar objetos secundarios.

  13. jsawk Última confirmación Mar 4, 2015

    Jsawk es como awk, pero para JSON. Trabaja con una matriz de objetos JSON leídos de stdin, filtrándolos usando JavaScript para producir una matriz de resultados que se imprime en stdout.

  14. Yate Last Commit Mar 13, 2017

    Las pruebas se pueden usar como docu https://github.com/pasaran/yate/tree/master/tests

  15. jsonpath-object-transform Última confirmación 18 de enero de 2017

    Extrae datos de un objeto literal usando JSONPath y genera nuevos objetos basados ​​en una plantilla.

  16. Grapado último compromiso Sep 16, 2013

    Grapado es una biblioteca de JavaScript que permite el formato XSLT para objetos JSON. En lugar de utilizar un motor de plantillas de JavaScript y plantillas de texto / html, el grapado le brinda la oportunidad de usar plantillas XSLT, cargadas de forma asíncrona con Ajax y luego en el lado del cliente en caché, para analizar sus fuentes de datos JSON.

Especificaciones:

  • JsonPointer

    El puntero JSON define una sintaxis de cadena para identificar un valor específico dentro de un documento JSON (JavaScript Object Notation).

  • JsonPath

    Las expresiones JSONPath siempre se refieren a una estructura JSON de la misma manera que las expresiones XPath se usan en combinación con un documento XML

  • JSPath

    JSPath para JSON es como XPath para XML ".

  • JSONiq

    La principal fuente de inspiración detrás de JSONiq es XQuery, que hasta ahora ha demostrado ser un lenguaje de consulta exitoso y productivo para datos semiestructurados

jschnasse
fuente
2
Gracias por tu publicación muy detallada y útil. Para transformar json de una línea en una forma legible, jq (nr.2 en su lista) es para mí la mejor opción. ¡Gracias de nuevo!
Primehunter
1
A menudo uso json_pp para una bonita impresión. Está disponible para muchas distribuciones.
jschnasse
70

Prueba JOLT . Es una biblioteca de transformación JSON a JSON escrita en Java.

Fue creado específicamente porque no queríamos jugar al juego "JSON -> XML -> XSLT -> XML -> JSON", y el uso de una plantilla para cualquier transformación suficientemente compleja es imposible de mantener.

Milo S
fuente
44
+9000: ¡Este es un proyecto serio! Huzzah La demostración en línea con ejemplos ayuda enormemente a subir la curva de aprendizaje: jolt-demo.appspot.com
kevinarpe
15

jq: procesador JSON de línea de comandos ligero y flexible

No está basado en plantillas como XSLT, pero es más conciso. Por ejemplo, para extraer namey addresscampos en una matriz:[.name, .address]

El tutorial muestra un ejemplo de transformación de la API JSON de Twitter (y el manual tiene muchos ejemplos).

13ren
fuente
44
Es más conciso porque es capaz de mucho menos.
Ihe Onwuka
No encontré cómo buscar de forma recursiva un atributo dado en un árbol Json
Daniel
@Daniel es .. | .attr_name?lo que estás buscando? (de stedolan.github.io/jq/manual/#RecursiveDescent: .. )
ankostis
1
Tal vez no sea tan capaz como XSLT pero muy útil y no tan complicado como XSLT
flq
15

XSLT admite JSON como se ve en http://www.w3.org/TR/xslt-30/#json

XML usa corchetes angulares para tokens delimitadores, JSON usa corchetes, corchetes, ... I. e. Las pocas comparaciones de reconocimiento de token de XML significan que está optimizado para la transformación declarativa, mientras que más comparaciones, como una declaración de cambio, por razones de velocidad suponen una predicción de rama especulativa para la que es útil el código imperativo en los lenguajes de script. Como consecuencia directa, para diferentes mezclas de datos semiestructurados, es posible que desee comparar el rendimiento de los motores XSLT y javascript como parte de las páginas receptivas. Para una carga útil de datos insignificante, las transformaciones podrían funcionar igual de bien con JSON sin serialización XML. La decisión de W3 debería basarse en un mejor análisis.

Chawathe Vipul S
fuente
15

Recientemente encontré una herramienta que me encanta para diseñar JSON: https://github.com/twigkit/tempo . Herramienta muy fácil de usar, en mi opinión, es mucho más fácil trabajar con ella que XSLT, sin necesidad de consultas XPATH.

Derek Curtis
fuente
99
Tempo se ve muy bien si el resultado final de la transformación es HTML. Pero, ¿qué pasa si solo desea reorganizar una estructura implícita en una diferente, sin embargo, el resultado final sigue siendo JSON? Todavía quisiera un análogo de XPath para poder escribir la transformación de una manera funcional.
Toddius Zho
1
Tempo es muy interesante, de hecho gracias. Sin embargo, puede enviar un xml al navegador y un xslt (<? Xsl-stylesheet>) y su navegador aplicará el xslt al xml, mostrando una vista definida de su xml sin ningún código adicional. Este también debería ser el caso de jsonT / tempo.
Martin Meeser
11

Decir que la falta de herramientas sugiere que la falta de necesidad es solo una pregunta. Lo mismo podría aplicarse al soporte para X o Y en Linux (¿por qué molestarse en desarrollar controladores y / o juegos de calidad para un sistema operativo tan minoritario? ¿Y por qué prestar atención a un sistema operativo para el que las grandes empresas de hardware y juegos no desarrollan?). Probablemente, las personas que necesitarían usar XSLT y JSON terminan usando una solución algo trivial: transformar JSON en XML. Pero esa no es la solución óptima, ¿verdad?

Cuando tiene un formato JSON nativo y desea editarlo "wysywyg" en el navegador, XSLT sería una solución más que adecuada para el problema. Hacer eso con la programación tradicional de JavaScript puede convertirse en una molestia.

De hecho, he implementado un enfoque de "edad de piedra" para XSLT, utilizando el análisis de subcadenas para interpretar algunos comandos básicos para javascript, como llamar a una plantilla, procesar hijos, etc. Ciertamente, implementar un motor de transformación con un objeto JSON es mucho más fácil que implementar un analizador XML completo para analizar el XSLT. El problema es que para usar plantillas XML para transformar un objeto JSON necesita analizar el XML de las plantillas.

Para transformar un objeto JSON con XML (o HTML, o texto o lo que sea), debe pensar detenidamente sobre la sintaxis y los caracteres especiales que necesita para identificar los comandos de transformación. De lo contrario, terminarás teniendo que diseñar un analizador para tu propio lenguaje de plantillas personalizado. Después de haber recorrido ese camino, puedo decirte que no es bonito.

Actualización (12 de noviembre de 2010): después de un par de semanas trabajando en mi analizador, he podido optimizarlo. Las plantillas se analizan de antemano y los comandos se almacenan como objetos JSON. Las reglas de transformación también son objetos JSON, mientras que el código de la plantilla es una combinación de HTML y una sintaxis homebrew similar al código shell. He podido transformar un documento JSON complejo en HTML para crear un editor de documentos. El código tiene alrededor de 1K líneas para el editor (es para un proyecto privado, así que no puedo compartirlo) y alrededor de 990 líneas para el código de transformación JSON (incluye comandos de iteración, comparaciones simples, llamadas a plantillas, guardado y evaluación de variables). Planeo lanzarlo bajo una licencia MIT. Envíame un correo si quieres involucrarte.

Almiar
fuente
11

Recientemente escribí mi propia pequeña biblioteca sobre esto, que trata de mantenerse lo más cerca posible de

5.1 Modelo de procesamiento (XSLT REC) https://www.w3.org/TR/xslt#section-Processing-Model

como es posible (como pude de todos modos), en unas pocas líneas de código JavaScript.

Aquí hay algunos ejemplos de uso no completamente triviales ...

1. JSON-a-algún-marcado:

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

(inspirado en el ejemplo de documento D.1 (XSLT REC) https://www.w3.org/TR/xslt#section-Document-Example )

donde esto:

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

... da:

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

y

2. JSON a JSON:

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

donde esto:

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

... da:

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

3. XSLT vs. JavaScript:

Un equivalente de JavaScript de ...

XSLT 3.0 REC Sección 14.4 Ejemplo: Nodos de agrupación basados ​​en valores comunes

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

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

dónde...

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

... da:

<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 vs. JavaScript:

Un equivalente de JavaScript de ...

Casos de uso de JSONiq Sección 1.1.2. Consultas de agrupación para JSON

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

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

dónde...

/*
  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()

... da:

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

También es útil para superar las limitaciones de JSONPath wrt. consultas contra el eje ancestro, como lo plantea esta pregunta SO (y ciertamente otras).

Por ejemplo, cómo obtener el descuento de un artículo de supermercado conociendo su ID de marca, 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"
     }
 ]
}

?

Una posible solución es:

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

... lo que da:

Discount of #983: 20

'HTH,

YSharp
fuente
10

Hay ahora! Recientemente creé una biblioteca, json-transforma , exactamente para este propósito:

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

Utiliza una combinación de JSPath , un DSL modelado en XPath y un enfoque de coincidencia de patrones recursivo, inspirado directamente por XSLT.

Aquí hay un ejemplo rápido. Dado el siguiente objeto 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 }
  ]
};

Aquí hay una transformación:

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

Lo que produce lo siguiente:

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

Esta transformación se compone de tres reglas. El primero coincide con cualquier automóvil fabricado por Honda, que emite un objeto con una Hondapropiedad y luego coincide de forma recursiva. La segunda regla coincide con cualquier objeto con una makerpropiedad, generando las propiedades modely year. La final es la transformación de identidad que coincide recursivamente.

ColinE
fuente
9

Como otra nueva respuesta a una vieja pregunta, sugeriría un vistazo a DefiantJS . No es un equivalente XSLT para JSON, es XSLT para JSON. La sección "Plantilla" de la documentación incluye este ejemplo:

<!-- 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>
LS
fuente
5

Estoy realmente cansado de la enorme cantidad de motores de plantillas de JavaScript, y todas sus plantillas HTML en línea, diferentes estilos de marcado, etc., y decidí construir una pequeña biblioteca que permita el formato XSLT para estructuras de datos JSON. No es ciencia espacial de ninguna manera: es solo JSON analizado a XML y luego formateado con un documento XSLT. También es rápido, no tan rápido como los motores de plantillas JavaScript en Chrome, pero en la mayoría de los otros navegadores es al menos tan rápido como la alternativa del motor JS para estructuras de datos más grandes.

Björn
fuente
4

Estoy usando Camel route umarshal (xmljson) -> to (xlst) -> marshal (xmljson). Suficientemente eficiente (aunque no 100% perfecto), pero simple, si ya está usando Camel.

Ben Goldin
fuente
3

JSONiq es un estándar y Zorba una implementación de C ++ de código abierto. JSONiq también se puede ver como XQuery al agregar JSON como un tipo de datos nativo.

mb21
fuente
2

Yate ( https://github.com/pasaran/yate ) está específicamente diseñado después de XSLT, presenta JPath (un equivalente natural de XPath para JS), se compila a JavaScript y tiene un historial bastante amplio de uso de producción. Prácticamente no está documentado, pero leer muestras y pruebas debería ser suficiente.

K Lee
fuente
2

JSLT está muy cerca de un equivalente JSON de XSLT. Es un lenguaje de transformación donde escribe la parte fija de la salida en sintaxis JSON, luego inserta expresiones para calcular los valores que desea insertar en la plantilla.

Un ejemplo:

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

Está implementado en Java sobre Jackson.

Lars Marius Garshol
fuente
0

No estoy muy seguro de que sea necesario, y para mí la falta de herramientas sugiere falta de necesidad. JSON se procesa mejor como objetos (la forma en que se hace en JS de todos modos), y normalmente se usa el lenguaje de los objetos para hacer transformaciones (Java para objetos Java creados a partir de JSON, lo mismo para Perl, Python, Perl, c #, PHP, etc. en). Solo con asignaciones normales (o set, get), bucles, etc.

Quiero decir, XSLT es solo otro lenguaje, y una razón por la que se necesita es que XML no es una notación de objeto y, por lo tanto, los objetos de los lenguajes de programación no son ajustes exactos (impedancia entre el modelo jerárquico xml y los objetos / estructuras).

StaxMan
fuente
Después de que Facebook convirtió de XML a Json, necesito desesperadamente una herramienta como esta.
Joe Soul-bringer el
¿Qué caso de uso estás pensando? ¿Es capaz de representar el contenido JSON de forma similar a cómo representaría las respuestas XML como HTML? O algo diferente?
StaxMan
Me pregunto cuán fácil sería manipular la transformación JSON de la forma del objeto programático (con bucles, ramificaciones según sea necesario, etc.) en comparación con el uso del método de tipo XSLT, particularmente en el caso de la transformación de objetos JSON masivos y donde se cambian algunos datos en la fuente JSON. subir / bajar algunos nodos en el JSON de destino (por lo que no es simplemente una copia directa de la estructura) y decir dónde un nodo particular en el JSON de origen o de destino es parte de la matriz de objetos dentro del JSON y el otro JSON (origen / destino) no lo es .
David
La facilidad es muy subjetiva, por lo que sospecho que gran parte tiene que ver con lo que uno está acostumbrado.
StaxMan
Si bien definitivamente hay una necesidad de transformación JSON, tienes razón, JS la cumple en gran medida. :-) ¿Pero has visto jq - procesador JSON de línea de comandos ligero y flexible ? Especialmente para cuando JS no está disponible. Yo diría que la transformación es dramáticamente más fácil y más intuitiva, incluso que JS. por ejemplo, para extraer los campos namey addressponerlos en una matriz:[.name, .address]
13ren
0

¿Por qué no convierte JSON a XML con Mr. Data Coverter , lo transforma con XSLT y luego lo vuelve a cambiar a JSON con el mismo?

usuario1058322
fuente
1
Esa no es una opción si desea que su código lo haga por usted con un buen rendimiento.
orad
0

Para un garabato / prueba de concepto funcional de un enfoque para utilizar JavaScript puro junto con el patrón familiar y declarativo detrás de las expresiones coincidentes y las plantillas recursivas de XSLT, consulte https://gist.github.com/brettz9/0e661b3093764f496e36

(Se podría adoptar un enfoque similar para JSON).

Tenga en cuenta que la demostración también se basa en los cierres de expresiones de JavaScript 1.8 por conveniencia al expresar plantillas en Firefox (al menos hasta que se pueda implementar la forma corta ES6 para los métodos).

Descargo de responsabilidad: este es mi propio código.

Brett Zamir
fuente
0

Hace mucho tiempo escribí un adaptador dom para mi marco de procesamiento json basado en jackson. Utiliza la biblioteca nu.xom. El árbol dom resultante funciona con las instalaciones java xpath y xslt. Tomé algunas decisiones de implementación que son bastante sencillas. Por ejemplo, el nodo raíz siempre se llama "raíz", las matrices van a un nodo ol con elementos secundarios li (como en html), y todo lo demás es solo un nodo secundario con un valor primitivo u otro nodo de objeto.

JsonXmlConverter.java

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

Jilles van Gurp
fuente
0

Un enfoque que aún no se ha dado es utilizar un generador de analizadores para crear un analizador en XSLT que analice JSON y produzca una salida XML.

Una opción que se menciona mucho en las conferencias XML es el generador de analizador ReX ( http://www.bottlecaps.de/rex/ ), aunque está totalmente indocumentado en el sitio, las recetas están disponibles en la búsqueda.

Tom Hillman
fuente
0

Es posible usar XSLT con JSON. La versión 3 de XPath (3.1) XSLT (3.0) y XQuery (3.1) admite JSON de alguna manera. Esto parece estar disponible en la versión comercial de Saxon, y en algún momento podría incluirse en la versión HE. https://www.saxonica.com/html/documentation/functions/fn/parse-json.html

-

Lo que esperaría de una solución alternativa:

Me gustaría poder ingresar JSON para obtener un conjunto de datos coincidentes y generar JSON o TEXT.

Acceda a propiedades arbitrarias y evalúe los valores

Soporte para lógica condicional.

Me gustaría que los scripts de transformación fueran externos a la herramienta, basados ​​en texto y, preferiblemente, un lenguaje de uso común.

Alternativa potencial?

Me pregunto si SQL podría ser una alternativa adecuada. https://docs.microsoft.com/en-us/sql/relational-databases/json/json-data-sql-server

Sería bueno si la herramienta alternativa pudiera manejar JSON y XML https://docs.microsoft.com/en-us/sql/relational-databases/xml/openxml-sql-server

Todavía no he intentado convertir los scripts XSLT que uso a SQL, o he evaluado completamente esta opción todavía, pero espero verlo más pronto. Solo algunos pensamientos hasta ahora.

Onceler
fuente