XSLT-Äquivalent für JSON [geschlossen]

411

Gibt es ein XSLT- Äquivalent für JSON? Etwas, das es mir ermöglicht, Transformationen unter JSON wie XSLT in XML durchzuführen.

luvieere
quelle
1
Übrigens, auf welcher Sprache / Plattform würde das sein?
StaxMan
6
@StaxMan XSLT ist ein Standard, der in vielen Sprachen und Plattformen implementiert ist. Meine Fragen zielen auf ein ähnliches Unterfangen ab.
luvieere
36
+1 für deine Frage. Viele Leute scheinen XSLT zu übersehen oder einfach nicht zu mögen, aber es kann einfach eine Reaktion auf die XML-Ausführlichkeit sein. Und tatsächlich, da XML allmählich in Ungnade fällt, gibt es immer weniger Möglichkeiten, XSLT zu verwenden, was schade ist! Ein XSLT-Äquivalent für JSON wäre fantastisch.
Nicolas Le Thierry d'Ennequin
10
@ NicolasLeThierryd'Ennequin Einverstanden. Viele Leute hassen XML und entlassen daher XSLT. Das XML-Ökosystem der Tools ist auch reich an Java-Entwicklern, was noch mehr Menschen abweist. Aber ich habe mich Mitte der 2000er Jahre intensiv mit XSLT beschäftigt, und es gibt eine enorme Leistung, die außerhalb des XML-Ökosystems keine direkte Entsprechung hat. Ich würde ein JSON-Äquivalent lieben !
Zearin

Antworten:

77

Interessante Idee. Einige Suchanfragen bei Google ergaben einige interessante Seiten, darunter:

Hoffe das hilft.

Tim
quelle
10
Ja, danke, das habe ich gesucht. Schade, dass die Technik nicht beliebter ist. JSON wird häufig als Rückgabeformat in REST-ähnlichen Diensten verwendet, und es wäre schön, eine Standardmethode für die Implementierung von Transformationen zu haben.
luvieere
8
Dieser Code verwendet string.eval () ... :-(
dreftymac
Nur Link Antwort
Jean-François Fabre
102

XSLT-Äquivalente für JSON - eine Liste von Kandidaten (Tools und Spezifikationen)

Werkzeuge

  1. XSLT

    Sie können XSLT für JSON mit dem Ziel von fn: json-to-xml verwenden .

    In diesem Abschnitt werden Funktionen beschrieben, mit denen JSON-Daten mit XSLT verarbeitet werden können.

  2. jq

    jq ist wie sed für JSON-Daten - Sie können es verwenden, um strukturierte Daten mit der gleichen Leichtigkeit zu schneiden, zu filtern, zuzuordnen und zu transformieren, mit der sed, awk, grep und Freunde Sie mit Text spielen lassen. Es gibt Installationspakete für verschiedene Betriebssysteme.

  3. jj

    JJ ist ein Befehlszeilenprogramm, mit dem Werte aus JSON-Dokumenten schnell und einfach abgerufen oder aktualisiert werden können. Es wird von GJSON und SJSON unter der Haube angetrieben.

  4. fx

    Befehlszeilen-JSON-Verarbeitungstool

    • Sie müssen keine neue Syntax lernen
    • Einfaches JavaScript
    • Formatieren und Hervorheben
    • Standalone-Binärdatei
  5. J L

    jl ("JSON lambda") ist eine winzige Funktionssprache zum Abfragen und Bearbeiten von JSON.

  6. RUCK

    In Java geschriebene JSON-zu-JSON-Transformationsbibliothek, wobei die "Spezifikation" für die Transformation selbst ein JSON-Dokument ist.

  7. gron

    Machen Sie JSON greifbar! gron wandelt JSON in diskrete Zuweisungen um, um es einfacher zu machen, nach dem zu suchen, was Sie wollen, und den absoluten "Pfad" dazu zu sehen. Es erleichtert die Erkundung von APIs, die große JSON-Blobs zurückgeben, aber eine schreckliche Dokumentation haben.

  8. json

    json ist ein schnelles CLI-Tool für die Arbeit mit JSON. Es handelt sich um ein Einzeldatei-Skript node.js ohne externe Deps (außer node.js selbst).

  9. json-e

    JSON-e ist ein Datenstruktur-Parametrisierungssystem zum Einbetten von Kontext in JSON-Objekte. Die zentrale Idee besteht darin, eine Datenstruktur als "Vorlage" zu behandeln und sie unter Verwendung einer anderen Datenstruktur als Kontext zu transformieren, um eine Ausgabedatenstruktur zu erzeugen.

  10. JSLT

    JSLT ist eine vollständige Abfrage- und Transformationssprache für JSON. Das Sprachdesign ist von jq, XPath und XQuery inspiriert.

  11. JSONata

    JSONata ist eine einfache Abfrage- und Transformationssprache für JSON-Daten. Inspiriert von der Semantik des Standortpfads in XPath 3.1 können anspruchsvolle Abfragen in einer kompakten und intuitiven Notation ausgedrückt werden.

  12. json-transforms Last Commit 1. Dezember 2017

    Bietet einen rekursiven Mustervergleichsansatz zum Transformieren von JSON-Daten. Transformationen werden als eine Reihe von Regeln definiert, die der Struktur eines JSON-Objekts entsprechen. Wenn eine Übereinstimmung auftritt, gibt die Regel die transformierten Daten aus und kann optional wiederkehren, um untergeordnete Objekte zu transformieren.

  13. jsawk Letztes Commit 4. März 2015

    Jsawk ist wie awk, aber für JSON. Sie arbeiten mit einem Array von JSON-Objekten, die aus stdin gelesen wurden, und filtern sie mit JavaScript, um ein Ergebnisarray zu erstellen, das in stdout gedruckt wird.

  14. yate Last Commit 13. März 2017

    Tests können als Dokument https://github.com/pasaran/yate/tree/master/tests verwendet werden

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

    Ruft mit JSONPath Daten aus einem Objektliteral ab und generiert neue Objekte basierend auf einer Vorlage.

  16. Heften Last Commit 16. September 2013

    Heften ist eine JavaScript-Bibliothek, die die XSLT-Formatierung für JSON-Objekte ermöglicht. Anstatt eine JavaScript-Vorlagen-Engine und Text- / HTML-Vorlagen zu verwenden, bietet Stapling die Möglichkeit, XSLT-Vorlagen zu verwenden, die asynchron mit Ajax geladen und dann clientseitig zwischengespeichert werden, um Ihre JSON-Datenquellen zu analysieren.

Technische Daten:

  • JsonPointer

    JSON Pointer definiert eine Zeichenfolgensyntax zum Identifizieren eines bestimmten Werts in einem JSON-Dokument (JavaScript Object Notation).

  • JsonPath

    JSONPath-Ausdrücke verweisen immer auf eine JSON-Struktur, genauso wie XPath-Ausdrücke in Kombination mit einem XML-Dokument verwendet werden

  • JSPath

    JSPath für JSON ist wie XPath für XML. "

  • JSONiq

    Die Hauptinspirationsquelle für JSONiq ist XQuery, eine bewährte und produktive Abfragesprache für halbstrukturierte Daten

jschnasse
quelle
2
Vielen Dank für Ihren sehr detaillierten und nützlichen Beitrag. Um einzeiliges json in eine lesbare Form umzuwandeln, ist jq (Nr. 2 in Ihrer Liste) für mich die beste Wahl. Danke noch einmal!
Primehunter
1
Ich benutze oft json_pp für hübsches Drucken. Es ist für viele Distributionen verfügbar.
jschnasse
70

Versuchen Sie es mit JOLT . Es ist eine in Java geschriebene JSON-zu-JSON-Transformationsbibliothek.

Es wurde speziell erstellt, weil wir das Spiel "JSON -> XML -> XSLT -> XML -> JSON" nicht spielen wollten und die Verwendung einer Vorlage für eine ausreichend komplexe Transformation nicht möglich ist.

Milo S.
quelle
4
+9000: Dies ist ein ernstes Projekt! Huzzah. Die Online-Demo mit Beispielen hilft sehr, die Lernkurve zu erklimmen: jolt-demo.appspot.com
kevinarpe
15

jq - leichter und flexibler Befehlszeilen-JSON-Prozessor

Es ist nicht vorlagenbasiert wie XSLT, sondern prägnanter. zB zu extrahieren nameund addressFelder in ein Array:[.name, .address]

Das Tutorial führt Sie durch ein Beispiel für die Transformation der JSON-API von Twitter (und das Handbuch enthält viele Beispiele).

13ren
quelle
4
Es ist prägnanter, weil es viel weniger kann.
Ihe Onwuka
Ich habe nicht gefunden, wie man ein bestimmtes Attribut in einem Json-Baum rekursiv sucht
Daniel
@ Daniel ist .. | .attr_name?was du suchst? (von stedolan.github.io/jq/manual/#RecursiveDescent: .. )
ankostis
1
Vielleicht nicht so fähig wie XSLT, aber sehr nützlich und nicht so kompliziert wie XSLT
flq
15

XSLT unterstützt JSON unter http://www.w3.org/TR/xslt-30/#json

XML verwendet eckige Klammern für Trennzeichen, JSON Klammern, eckige Klammern, ... I. e. XMLs weniger Token-Erkennungsvergleiche bedeuten, dass es für die deklarative Transformation optimiert ist, während mehr Vergleiche, wie z. B. switch-Anweisungen, aus Geschwindigkeitsgründen eine spekulative Verzweigungsvorhersage voraussetzen, für die zwingender Code in Skriptsprachen nützlich ist. Als direkte Konsequenz möchten Sie für verschiedene Mischungen von halbstrukturierten Daten möglicherweise die Leistung von XSLT- und Javascript-Engines als Teil reaktionsfähiger Seiten bewerten. Bei vernachlässigbarer Datennutzlast funktionieren Transformationen möglicherweise genauso gut mit JSON ohne XML-Serialisierung. Die Entscheidung von W3 sollte auf einer besseren Analyse beruhen.

Chawathe Vipul S.
quelle
15

Ich habe kürzlich ein Tool gefunden, das ich für das Styling von JSON liebe: https://github.com/twigkit/tempo . Sehr einfach zu bedienendes Tool - meiner Meinung nach ist die Arbeit mit XSLT viel einfacher - es sind keine XPATH-Abfragen erforderlich.

Derek Curtis
quelle
9
Tempo sieht gut aus, wenn das Endergebnis der Transformation HTML ist. Was aber, wenn Sie nur eine implizite Struktur in eine andere umordnen möchten, das Endergebnis jedoch immer noch JSON ist ? Ich würde immer noch ein Analogon von XPath wollen, damit ich die Transformation auf funktionale Weise schreiben kann.
Toddius Zho
1
Tempo ist in der Tat sehr interessant, danke. Sie können jedoch eine XML an den Browser und eine xslt (<? Xsl-stylesheet>) senden, und Ihr Browser wendet die xslt auf die xml an und zeigt eine definierte Ansicht Ihrer xml ohne weiteren Code an. Dies sollte auch für jsonT / tempo der Fall sein.
Martin Meeser
11

Zu sagen, dass mangelnde Werkzeuge auf mangelnde Notwendigkeit hindeuten, wirft nur die Frage auf. Das Gleiche könnte auf die Unterstützung von X oder Y unter Linux angewendet werden (Warum sollten Sie sich die Mühe machen, hochwertige Treiber und / oder Spiele für ein Betriebssystem einer solchen Minderheit zu entwickeln? Und warum sollten Sie auf ein Betriebssystem achten, für das große Spiele- und Hardwareunternehmen nicht entwickeln?). Wahrscheinlich verwenden die Leute, die XSLT und JSON verwenden müssten, eine etwas triviale Problemumgehung: JSON in XML umwandeln. Aber das ist nicht die optimale Lösung, oder?

Wenn Sie ein natives JSON-Format haben und es "wysywyg" im Browser bearbeiten möchten, ist XSLT eine mehr als angemessene Lösung für das Problem. Dies mit traditioneller Javascript-Programmierung zu tun, kann zu einem Ärgernis werden.

Tatsächlich habe ich einen "Steinzeit" -Ansatz für XSLT implementiert, bei dem Teilstring-Parsing verwendet wird, um einige grundlegende Befehle für Javascript zu interpretieren, z. B. das Aufrufen einer Vorlage, das Verarbeiten von untergeordneten Elementen usw. Die Implementierung einer Transformations-Engine mit einem JSON-Objekt ist sicherlich viel einfacher als Implementierung eines vollwertigen XML-Parsers zum Parsen des XSLT. Das Problem ist, dass Sie zum Verwenden von XML-Vorlagen zum Transformieren eines JSON-Objekts das XML der Vorlagen analysieren müssen.

Um ein JSON-Objekt mit XML (oder HTML oder Text oder was auch immer) zu transformieren, müssen Sie sorgfältig über die Syntax und die Sonderzeichen nachdenken, die Sie zur Identifizierung der Transformationsbefehle verwenden müssen. Andernfalls müssen Sie einen Parser für Ihre eigene benutzerdefinierte Vorlagensprache entwerfen. Nachdem ich diesen Weg gegangen bin, kann ich Ihnen sagen, dass er nicht schön ist.

Update (12. November 2010): Nachdem ich einige Wochen an meinem Parser gearbeitet habe, konnte ich ihn optimieren. Vorlagen werden zuvor analysiert und Befehle als JSON-Objekte gespeichert. Transformationsregeln sind auch JSON-Objekte, während der Vorlagencode eine Mischung aus HTML und einer Homebrew-Syntax ähnlich dem Shell-Code ist. Ich konnte ein komplexes JSON-Dokument in HTML umwandeln, um einen Dokumenteditor zu erstellen. Der Code enthält ungefähr 1 KB Zeilen für den Editor (für ein privates Projekt, daher kann ich ihn nicht freigeben) und ungefähr 990 Zeilen für den JSON-Transformationscode (einschließlich Iterationsbefehlen, einfachen Vergleichen, Aufruf von Vorlagen, Speichern und Auswerten von Variablen). Ich plane, es unter einer MIT-Lizenz zu veröffentlichen. Schreiben Sie mir eine E-Mail, wenn Sie sich beteiligen möchten.

Rick
quelle
11

Ich habe kürzlich meine eigene kleine Bibliothek darüber geschrieben, die versucht, so nah wie möglich zu bleiben

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

wie es möglich ist (wie ich es sowieso könnte), in ein paar Zeilen JavaScript-Code.

Hier sind einige nicht ganz triviale Anwendungsbeispiele ...

1. JSON-to-Some-Markup:

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

(inspiriert von D.1 Document Example (XSLT REC) https://www.w3.org/TR/xslt#section-Document-Example )

wo dies:

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

... gibt:

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

und

2. JSON-zu-JSON:

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

wo dies:

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

... gibt:

{
    "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:

Ein JavaScript-Äquivalent von ...

XSLT 3.0 REC Abschnitt 14.4 Beispiel: Gruppieren von Knoten basierend auf gemeinsamen Werten

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

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

wo...

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

... gibt:

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

Ein JavaScript-Äquivalent von ...

JSONiq-Anwendungsfälle Abschnitt 1.1.2. Gruppieren von Abfragen für JSON

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

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

wo...

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

... gibt:

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

Es ist auch nützlich, die Einschränkungen von JSONPath wrt zu überwinden. Abfragen gegen die Ahnenachse, wie durch diese SO-Frage (und sicherlich andere) aufgeworfen .

ZB, wie man den Rabatt eines Lebensmittels erhält, wenn man seine Marken-ID kennt, in

{
 "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"
     }
 ]
}

?

Eine mögliche Lösung ist:

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

... was gibt:

Discount of #983: 20

'HTH,

YSharp
quelle
10

Da ist jetzt! Ich habe kürzlich eine Bibliothek erstellt, json-transforms , genau zu diesem Zweck:

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

Es verwendet eine Kombination aus JSPath , einem auf XPath modellierten DSL und einem rekursiven Pattern-Matching-Ansatz, der direkt von XSLT inspiriert wurde.

Hier ist ein kurzes Beispiel. Gegeben das folgende JSON-Objekt:

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

Hier ist eine 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);

Welche Ausgabe die folgenden:

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

Diese Transformation besteht aus drei Regeln. Das erste passt zu jedem Auto, das von Honda hergestellt wird, sendet ein Objekt mit einer HondaEigenschaft aus und passt dann rekursiv zusammen. Die zweite Regel vergleicht jedes Objekt mit einer makerEigenschaft modelund gibt die yearEigenschaften und aus . Das Finale ist die Identitätstransformation, die rekursiv übereinstimmt.

ColinE
quelle
9

Als weitere neue Antwort auf eine alte Frage würde ich einen Blick auf DefiantJS vorschlagen . Es ist nicht ein XSLT - Äquivalent für JSON, es ist XSLT für JSON. Der Abschnitt "Vorlagen" der Dokumentation enthält dieses Beispiel:

<!-- 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
quelle
5

Ich war der enormen Menge an JavaScript-Vorlagen-Engines und all ihren Inline-HTML-Vorlagen, verschiedenen Markup-Stilen usw. wirklich überdrüssig und habe beschlossen , eine kleine Bibliothek zu erstellen , die die XSLT-Formatierung für JSON-Datenstrukturen ermöglicht. In keiner Weise Raketenwissenschaft - es ist nur JSON, das in XML analysiert und dann mit einem XSLT-Dokument formatiert wird. Es ist auch schnell, nicht so schnell wie JavaScript-Template-Engines in Chrome, aber in den meisten anderen Browsern ist es mindestens so schnell wie die JS-Engine-Alternative für größere Datenstrukturen.

Björn
quelle
4

Ich benutze Camel Route Umarshal (xmljson) -> nach (xlst) -> Marschall (xmljson). Effizient genug (obwohl nicht 100% perfekt), aber einfach, wenn Sie bereits Camel verwenden.

Ben Goldin
quelle
3

JSONiq ist ein solcher Standard und Zorba eine Open-Source-C ++ - Implementierung. JSONiq kann auch als XQuery angesehen werden, wenn JSON als nativer Datentyp hinzugefügt wird.

mb21
quelle
2

Yate ( https://github.com/pasaran/yate ) wurde speziell nach XSLT entwickelt, verfügt über JPath (ein natürliches XPath-Äquivalent für JS), kompiliert mit JavaScript und hat eine lange Tradition in der Produktion. Es ist praktisch undokumentiert, aber das Durchlesen von Proben und Tests sollte ausreichen.

K Lee
quelle
2

JSLT kommt einem JSON-Äquivalent von XSLT sehr nahe. Es ist eine Transformationssprache, in der Sie den festen Teil der Ausgabe in JSON-Syntax schreiben und dann Ausdrücke einfügen, um die Werte zu berechnen, die Sie in die Vorlage einfügen möchten.

Ein Beispiel:

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

Es ist in Java zusätzlich zu Jackson implementiert.

Lars Marius Garshol
quelle
0

Ich bin mir nicht sicher, ob dies notwendig ist, und für mich deutet ein Mangel an Werkzeugen auf einen Mangel an Bedarf hin. JSON wird am besten als Objekte verarbeitet (wie es in JS sowieso der Fall ist), und Sie verwenden normalerweise die Sprache der Objekte selbst, um Transformationen durchzuführen (Java für Java-Objekte, die aus JSON erstellt wurden, ebenso für Perl, Python, Perl, c #, PHP usw.) auf). Nur mit normalen Zuweisungen (oder setzen, erhalten), Schleifen und so weiter.

Ich meine, XSLT ist nur eine andere Sprache, und ein Grund dafür ist, dass XML keine Objektnotation ist und daher Objekte von Programmiersprachen nicht exakt passen (Impedanz zwischen hierarchischem XML-Modell und Objekten / Strukturen).

StaxMan
quelle
Nachdem Facebook von XML auf Json konvertiert hat, brauche ich dringend ein solches Tool.
Joe Soul-Bringer
Welchen Anwendungsfall denken Sie? Ist es in der Lage, JSON-Inhalte so zu rendern, wie Sie XML-Antworten als HTML rendern würden? Oder etwas anderes?
StaxMan
Ich frage mich, wie einfach es wäre, die JSON-Transformation auf programmatische Weise zu manipulieren (mit Schleifen, Verzweigen nach Bedarf usw.), anstatt die XSLT-Methode zu verwenden, insbesondere im Fall der Transformation eines massiven JSON-Objekts und wenn einige Daten in Quell-JSON verschoben werden Einige Knoten im Ziel-JSON nach oben / unten (also nicht einfach eine direkte Kopie der Struktur) und sagen, wo ein bestimmter Knoten im Quell- oder Ziel-JSON Teil des Objektarrays im JSON ist und der andere JSON (Quelle / Ziel) nicht .
David
Leichtigkeit ist sehr subjektiv, daher vermute ich, dass vieles damit zu tun hat, was man gewohnt ist.
StaxMan
Es besteht definitiv die Notwendigkeit einer JSON-Transformation, aber Sie haben Recht, dass JS diese weitgehend erfüllt. :-) Aber haben Sie jq gesehen - einen leichten und flexiblen Befehlszeilen-JSON-Prozessor ? Besonders wenn JS nicht verfügbar ist. Ich würde sagen, Transformation ist dramatisch einfacher und intuitiver als JS. zB um die Felder nameund zu extrahieren addressund sie in ein Array zu legen:[.name, .address]
13ren
0

Warum konvertieren Sie JSON nicht mit Mr. Data Coverter in XML , transformieren es mit XSLT und ändern es dann mit demselben wieder in JSON.

user1058322
quelle
1
Dies ist keine Option, wenn Sie möchten, dass Ihr Code dies mit guter Leistung für Sie erledigt.
Orad
0

Ein funktionierendes Doodle / Proof of Concept eines Ansatzes zur Verwendung von reinem JavaScript zusammen mit dem bekannten und deklarativen Muster hinter den übereinstimmenden Ausdrücken und rekursiven Vorlagen von XSLT finden Sie unter https://gist.github.com/brettz9/0e661b3093764f496e36

(Ein ähnlicher Ansatz könnte für JSON gewählt werden.)

Beachten Sie, dass die Demo auch auf JavaScript 1.8-Ausdrucksschließungen basiert, um das Ausdrücken von Vorlagen in Firefox zu vereinfachen (zumindest bis die ES6-Kurzform für Methoden implementiert werden kann).

Haftungsausschluss: Dies ist mein eigener Code.

Brett Zamir
quelle
0

Ich habe vor langer Zeit einen Dom-Adapter für mein Jackson-basiertes JSON-Verarbeitungsframework geschrieben. Es verwendet die nu.xom-Bibliothek. Der resultierende Dom-Baum funktioniert mit den Funktionen Java xpath und xslt. Ich habe einige Implementierungsentscheidungen getroffen, die ziemlich einfach sind. Zum Beispiel wird der Wurzelknoten immer "Wurzel" genannt, Arrays gehen in einen alten Knoten mit li Unterelementen (wie in HTML) und alles andere ist nur ein Unterknoten mit einem primitiven Wert oder ein anderer Objektknoten.

JsonXmlConverter.java

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

Jilles van Gurp
quelle
0

Ein noch nicht gegebener Ansatz besteht darin, einen Parser-Generator zu verwenden, um einen Parser in XSLT zu erstellen, der JSON analysiert und eine XML-Ausgabe erzeugt.

Eine Option, die auf den XML-Konferenzen häufig erwähnt wird, ist der ReX-Parser-Generator ( http://www.bottlecaps.de/rex/ ). Obwohl auf der Website völlig undokumentiert, sind Rezepte bei der Suche verfügbar.

Tom Hillman
quelle
0

Möglicherweise kann XSLT mit JSON verwendet werden. Verson 3 von XPath (3.1) XSLT (3.0) und XQuery (3.1) unterstützt JSON in gewisser Weise. Dies scheint in der kommerziellen Version von Saxon verfügbar zu sein und könnte irgendwann in der HE-Version enthalten sein. https://www.saxonica.com/html/documentation/functions/fn/parse-json.html

- -

Was ich von einer alternativen Lösung erwarten würde:

Ich möchte JSON eingeben können, um einen passenden Datensatz abzurufen, und JSON oder TEXT ausgeben.

Greifen Sie auf beliebige Eigenschaften zu und werten Sie die Werte aus

Unterstützung für bedingte Logik

Ich möchte, dass die Transformationsskripte außerhalb des Tools, textbasiert und vorzugsweise eine häufig verwendete Sprache sind.

Mögliche Alternative?

Ich frage mich, ob SQL eine geeignete Alternative sein könnte. https://docs.microsoft.com/en-us/sql/relational-databases/json/json-data-sql-server

Es wäre schön, wenn das alternative Tool JSON und XML verarbeiten könnte https://docs.microsoft.com/en-us/sql/relational-databases/xml/openxml-sql-server verarbeiten könnte

Ich habe noch nicht versucht, die von mir verwendeten XSLT-Skripte in SQL zu konvertieren, oder diese Option noch nicht vollständig evaluiert, hoffe jedoch, sie bald genauer untersuchen zu können. Nur ein paar Gedanken bisher.

Onceler
quelle