Odpowiednik XSLT dla JSON [zamknięty]

411

Czy istnieje odpowiednik XSLT dla JSON? Coś, co pozwala mi dokonywać transformacji w JSON, tak jak XSLT robi XML.

luvieere
źródło
1
Btw, w jakim języku / platformie to by było?
StaxMan
6
@StaxMan XSLT to standard, który ma faktyczne implementacje w wielu językach i platformach, moje pytania dotyczą podobnych przedsięwzięć.
luvieere
36
+1 za twoje pytanie. Wiele osób wydaje się przeoczyć lub po prostu nie lubić XSLT, ale może to być po prostu reakcja na gadatliwość XML. I rzeczywiście, ponieważ XML stopniowo traci popularność, jest coraz mniej możliwości korzystania z XSLT, a szkoda! Odpowiednik XSLT dla JSON byłby niesamowity.
Nicolas Le Thierry d'Ennequin
10
@ NicolasLeThierryd'Ennequin Zgoda. Wiele osób nienawidzi XML i dlatego odrzuca XSLT. Ekosystem narzędzi XML jest również ciężki dla programistów Java, co odwraca uwagę jeszcze większej liczby osób. Ale w połowie 2000 roku byłem bardzo zaangażowany w XSLT i istnieje ogromna moc, która nie ma bezpośredniego odpowiednika poza ekosystemem XML. Chciałbym kochać odpowiednik JSON!
Zearin

Odpowiedzi:

77

Ciekawy pomysł. Niektóre wyszukiwania w Google wytworzyły kilka interesujących stron, w tym:

Mam nadzieję że to pomoże.

Tim
źródło
10
Tak, dziękuję, tego właśnie szukałem. Szkoda, że ​​technika nie jest bardziej popularna, JSON jest dość często używany jako format zwrotny w usługach w stylu REST i byłoby miło mieć standardowy sposób implementacji transformacji.
luvieere
8
Ten kod używa string.eval () ... :-(
dreftymac
Link tylko odpowiedź
Jean-François Fabre
102

Ekwiwalenty XSLT dla JSON - lista kandydatów (narzędzia i specyfikacje)

Przybory

  1. XSLT

    Możesz użyć XSLT dla JSON w celu fn: json-to-xml .

    W tej sekcji opisano funkcje umożliwiające przetwarzanie danych JSON za pomocą XSLT.

  2. jq

    jq jest podobny do sed dla danych JSON - możesz go używać do wycinania, filtrowania i mapowania oraz przekształcania danych strukturalnych z taką samą łatwością, jak sed, awk, grep i znajomi pozwalają bawić się z tekstem. Istnieją pakiety instalacyjne dla różnych systemów operacyjnych.

  3. jj

    JJ to narzędzie wiersza polecenia, które zapewnia szybki i prosty sposób pobierania lub aktualizowania wartości z dokumentów JSON. Jest zasilany przez GJSON i SJSON pod maską.

  4. fx

    Narzędzie przetwarzania JSON z wiersza poleceń

    • Nie musisz uczyć się nowej składni
    • Zwykły JavaScript
    • Formatowanie i wyróżnianie
    • Samodzielny plik binarny
  5. J l

    jl („JSON lambda”) to mały funkcjonalny język do wysyłania zapytań i manipulowania JSON.

  6. WSTRZĄS

    Biblioteka transformacji JSON do JSON napisana w Javie, gdzie sama „specyfikacja” transformacji jest dokumentem JSON.

  7. gron

    Uczyń JSON greppable! gron przekształca JSON w dyskretne zadania, aby ułatwić grep dla tego, czego chcesz i zobaczyć absolutną „ścieżkę” do niego. Ułatwia eksplorację interfejsów API, które zwracają duże obiekty BLS JSON, ale mają okropną dokumentację.

  8. json

    json to szybkie narzędzie CLI do pracy z JSON. Jest to skrypt z jednym plikiem node.js bez plików zewnętrznych (oprócz samego node.js).

  9. json-e

    JSON-e to system parametryzacji struktury danych do osadzania kontekstu w obiektach JSON. Główną ideą jest traktowanie struktury danych jako „szablonu” i przekształcenie jej, używając innej struktury danych jako kontekstu, w celu wytworzenia wyjściowej struktury danych.

  10. JSLT

    JSLT to kompletny język zapytań i transformacji dla JSON. Projekt języka jest inspirowany przez jq, XPath i XQuery.

  11. JSONata

    JSONata to lekki język zapytań i transformacji danych JSON. Zainspirowany semantyką „ścieżki lokalizacji” w XPath 3.1, umożliwia wyrażanie skomplikowanych zapytań w zwartej i intuicyjnej notacji.

  12. json-transforms Last Commit 1 grudnia 2017 r

    Zapewnia rekurencyjne, dopasowujące wzorce podejście do transformacji danych JSON. Transformacje są zdefiniowane jako zestaw reguł, które pasują do struktury obiektu JSON. Gdy występuje dopasowanie, reguła emituje przekształcone dane, opcjonalnie rekurencyjne w celu przekształcenia obiektów potomnych.

  13. jsawk Last commit 4 marca 2015

    Jsawk jest jak awk, ale dla JSON. Pracujesz z tablicą obiektów JSON odczytanych ze standardowego wejścia, filtrujesz je za pomocą JavaScript, aby utworzyć tablicę wyników, która jest drukowana na standardowe wyjście.

  14. yate Last Commit 13 marca 2017

    Testy mogą być używane jako docu https://github.com/pasaran/yate/tree/master/tests

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

    Pobiera dane z literału obiektu za pomocą JSONPath i generuje nowe obiekty na podstawie szablonu.

  16. Stapling Last Commit 16 września 2013

    Zszywanie to biblioteka JavaScript, która umożliwia formatowanie XSLT dla obiektów JSON. Zamiast korzystać z silnika szablonów JavaScript i szablonów tekstowych / html, Stapling daje Ci możliwość korzystania z szablonów XSLT - ładowanych asynchronicznie z Ajax, a następnie buforowanych po stronie klienta - do analizowania źródeł danych JSON.

Okular:

  • JsonPointer

    Wskaźnik JSON definiuje składnię łańcuchową do identyfikowania określonej wartości w dokumencie JavaScript Object Notation (JSON).

  • JsonPath

    Wyrażenia JSONPath zawsze odnoszą się do struktury JSON w taki sam sposób, jak wyrażenia XPath są używane w połączeniu z dokumentem XML

  • JSPath

    JSPath dla JSON jest jak XPath dla XML. ”

  • JSONiq

    Głównym źródłem inspiracji dla JSONiq jest XQuery, który jak dotąd okazał się skutecznym i produktywnym językiem zapytań o częściowo ustrukturyzowane dane

jschnasse
źródło
2
Dziękujemy za bardzo szczegółowy i użyteczny post. Aby przekształcić jednowierszowy plik Json do postaci czytelnej, najlepszym wyborem jest dla mnie jq (nr 2 na liście). Dzięki jeszcze raz!
primehunter
1
Często używam json_pp do ładnego drukowania. Jest dostępny dla wielu dystrybucji.
jschnasse
70

Wypróbuj JOLT . Jest to biblioteka transformacji JSON do JSON napisana w Javie.

Został stworzony specjalnie dlatego, że nie chcieliśmy grać w grę „JSON -> XML -> XSLT -> XML -> JSON”, a użycie szablonu dla wystarczająco złożonej transformacji jest niemożliwe do utrzymania.

Milo S.
źródło
4
+9000: To poważny projekt! Huzzah. Demo online z przykładami bardzo pomaga wspiąć się na krzywą uczenia się: jolt-demo.appspot.com
kevinarpe
15

jq - lekki i elastyczny procesor JSON z wiersza poleceń

Nie jest oparty na szablonie jak XSLT, ale bardziej zwięzły. np. aby wyodrębnić namei addresspola do tablicy:[.name, .address]

W samouczku przedstawiono przykład transformacji interfejsu API JSON na Twitterze (w instrukcji jest wiele przykładów).

13ren
źródło
4
Jest bardziej zwięzły, ponieważ jest w stanie o wiele mniej.
Ihe Onwuka
Nie znalazłem sposobu wyszukiwania rekurencyjnie danego atrybutu w drzewie Jsona
Daniel
@Daniel jest .. | .attr_name?tym, czego szukasz? (od stedolan.github.io/jq/manual/#RecursiveDescent: .. )
ankostis
1
Może nie tak zdolny jak XSLT, ale bardzo przydatny i nie tak skomplikowany jak XSLT
flq 23'18
15

XSLT obsługuje JSON, jak widać na stronie http://www.w3.org/TR/xslt-30/#json

XML używa nawiasów kątowych do tokenów ograniczników, JSON używa nawiasów klamrowych, nawiasów kwadratowych, ... I. e. Mniej porównań rozpoznawania tokena w języku XML oznacza, że ​​jest on zoptymalizowany pod kątem deklaratywnej transformacji, podczas gdy więcej porównań, które są podobne do instrukcji switch, ze względów szybkości zakładają spekulacyjne przewidywanie gałęzi, do czego przydatny jest kod imperatywny w językach skryptowych. Bezpośrednią konsekwencją jest to, że w przypadku różnych mieszanin częściowo ustrukturyzowanych danych możesz przetestować wydajność XSLT i silników javascript w ramach responsywnych stron. W przypadku niewielkiej ilości danych transformacje mogą równie dobrze działać z JSON bez serializacji XML. Decyzja W3 powinna opierać się na lepszej analizie.

Chawathe Vipul S.
źródło
15

Niedawno znalazłem narzędzie, które uwielbiam do stylizacji JSON: https://github.com/twigkit/tempo . Bardzo łatwe w użyciu narzędzie - moim zdaniem jest o wiele łatwiejsze w obsłudze niż XSLT - nie potrzeba zapytań XPATH.

Derek Curtis
źródło
9
Tempo wygląda świetnie, jeśli końcowym wynikiem transformacji jest HTML. Ale co, jeśli chcesz po prostu zmienić domyślną strukturę na inną, ale ostatecznym rezultatem jest nadal JSON. Nadal chciałbym analogi XPath, abym mógł napisać transformację w funkcjonalny sposób.
Toddius Zho
1
Tempo jest bardzo interesujące, naprawdę dziękuję. Możesz jednak wysłać xml do przeglądarki i xslt (<? Xsl-stylesheet>), a twoja przeglądarka zastosuje xslt do xml, pokazując zdefiniowany widok twojego xml bez dalszego kodu. Tak też powinno być w przypadku jsonT / tempo.
Martin Meeser,
11

Stwierdzenie, że brak narzędzi sugeruje, że brak potrzeby jest tylko pytaniem. To samo można zastosować do obsługi X lub Y w systemie Linux (po co zawracać sobie głowę opracowywaniem wysokiej jakości sterowników i / lub gier dla tak niewielkiego systemu operacyjnego? Dlaczego warto zwracać uwagę na system operacyjny, dla którego duże firmy produkujące gry i sprzęt nie opracowują?). Prawdopodobnie ludzie, którzy musieliby używać XSLT i JSON, używają nieco trywialnego obejścia: Przekształcanie JSON w XML. Ale to nie jest optymalne rozwiązanie, prawda?

Jeśli masz natywny format JSON i chcesz go edytować w przeglądarce „wysywyg”, XSLT byłoby rozwiązaniem bardziej niż wystarczającym. Robienie tego przy tradycyjnym programowaniu w javascript może stać się trudnym zadaniem.

W rzeczywistości wdrożyłem podejście XSLT w „epoce kamienia”, używając analizy składniowej do interpretacji niektórych podstawowych poleceń javascript, takich jak wywoływanie szablonu, przetwarzanie potomków itp. Z pewnością implementacja silnika transformacji z obiektem JSON jest znacznie łatwiejsza niż implementacja pełnoprawnego analizatora składni XML w celu parsowania XSLT. Problem polega na tym, że aby użyć szablonów XML do transformacji obiektu JSON, musisz przeanalizować XML szablonów.

Aby przekształcić obiekt JSON za pomocą XML (lub HTML, tekst lub cokolwiek innego), należy dokładnie przemyśleć składnię i znaki specjalne, których należy użyć do zidentyfikowania poleceń transformacji. W przeciwnym razie będziesz musiał zaprojektować parser dla własnego, niestandardowego języka szablonów. Po przejściu tej ścieżki mogę powiedzieć, że nie jest ładna.

Aktualizacja (12 listopada 2010 r.): Po kilku tygodniach pracy nad moim parserem byłem w stanie go zoptymalizować. Szablony są wcześniej analizowane, a polecenia są przechowywane jako obiekty JSON. Reguły transformacji są również obiektami JSON, podczas gdy kod szablonu jest mieszanką HTML i składni homebrew podobnej do kodu powłoki. Byłem w stanie przekształcić złożony dokument JSON w HTML, aby utworzyć edytor dokumentów. Kod zawiera około 1 000 wierszy dla edytora (dotyczy prywatnego projektu, więc nie mogę go udostępnić) i około 990 wierszy dla kodu transformacji JSON (zawiera polecenia iteracji, proste porównania, wywoływanie szablonów, zapisywanie zmiennych i ocenę). Planuję wydać go na licencji MIT. Napisz do mnie, jeśli chcesz się zaangażować.

Stóg
źródło
11

Ostatnio napisałem o tym swoją małą bibliotekę, która stara się być tak blisko

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

jak to możliwe (jak mogłem i tak), w kilku wierszach kodu JavaScript.

Oto kilka niezupełnie trywialnych przykładów użycia ...

1. JSON-to-some-markup:

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

(zainspirowany przykładem dokumentu D.1 (XSLT REC) https://www.w3.org/TR/xslt#section-Document-Example )

gdzie to:

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

... daje:

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

i

2. JSON-to-JSON:

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

gdzie to:

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

... daje:

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

JavaScriptowy odpowiednik ...

XSLT 3.0 REC Sekcja 14.4 Przykład: Grupowanie węzłów na podstawie wspólnych wartości

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

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

gdzie...

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

... daje:

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

JavaScriptowy odpowiednik ...

Przypadki użycia JSONiq Sekcja 1.1.2. Grupowanie zapytań dla JSON

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

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

gdzie...

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

... daje:

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

Przydatne jest także pokonanie ograniczeń JSONPath wrt. kwerendy względem osi przodka, jak podnosi to pytanie SO (i na pewno inne).

Na przykład, jak uzyskać zniżkę na artykuł spożywczy, znając jego identyfikator marki, w

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

?

Możliwym rozwiązaniem jest:

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

... co daje:

Discount of #983: 20

„HTH,

YSharp
źródło
10

Jest teraz! Niedawno stworzyłem bibliotekę, transformaty json , właśnie w tym celu:

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

Wykorzystuje kombinację JSPath , DSL wzorowany na XPath oraz rekurencyjne podejście do dopasowywania wzorców, zainspirowane bezpośrednio XSLT.

Oto szybki przykład. Biorąc pod uwagę następujący obiekt 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 }
  ]
};

Oto transformacja:

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

Które generują następujące:

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

Ta transformacja składa się z trzech zasad. Pierwszy pasuje do każdego samochodu wyprodukowanego przez Hondę, emitując obiekt z Hondawłaściwością, a następnie dopasowując rekurencyjnie. Druga reguła dopasowuje dowolny obiekt z makerwłaściwością, wyprowadzając właściwości modeli year. Ostatnim jest transformacja tożsamości, która rekurencyjnie pasuje.

ColinE
źródło
9

Jako kolejną nową odpowiedź na stare pytanie, proponuję spojrzeć na DefiantJS . To nie jest XSLT odpowiednik dla formatu JSON, to jest XSLT do JSON. Sekcja „Szablony” dokumentacji zawiera ten przykład:

<!-- 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
źródło
5

Naprawdę zmęczyło mnie ogromna ilość silników szablonów JavaScript i wszystkich ich wbudowanych szablonów HTML, różnych stylów znaczników itp., I postanowiłem zbudować małą bibliotekę, która umożliwia formatowanie XSLT dla struktur danych JSON. W żaden sposób nie jest to nauka rakietowa - jest to po prostu JSON przetworzony na XML, a następnie sformatowany za pomocą dokumentu XSLT. Jest także szybki, nie tak szybki jak silniki szablonów JavaScript w Chrome, ale w większości innych przeglądarek jest co najmniej tak szybki, jak silnik JS alternatywa dla większych struktur danych.

Björn
źródło
4

Korzystam z trasy wielbłąda umarshal (xmljson) -> do (xlst) -> marshal (xmljson). Wystarczająco wydajny (choć nie w 100% idealny), ale prosty, jeśli już używasz Camel.

Ben Goldin
źródło
3

JSONiq jest takim standardem, a Zorba implementacją C ++ typu open source. JSONiq można również postrzegać jako XQuery z dodaniem JSON jako rodzimego typu danych.

mb21
źródło
2

Yate ( https://github.com/pasaran/yate ) jest specjalnie zaprojektowany po XSLT, zawiera JPath (naturalny odpowiednik XPath dla JS), kompiluje się w JavaScript i ma dość długą historię zastosowań produkcyjnych. Jest praktycznie nieudokumentowany, ale wystarczy przejrzeć próbki i testy.

K Lee
źródło
2

JSLT jest bardzo zbliżony do JSON- owego odpowiednika XSLT. Jest to język transformacji, w którym zapisujesz stałą część wyniku w składni JSON, a następnie wstawiasz wyrażenia, aby obliczyć wartości, które chcesz wstawić do szablonu.

Przykład:

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

Jest zaimplementowany w Javie na Jacksonie.

Lars Marius Garshol
źródło
0

Nie jestem pewien, czy jest to potrzebne, a dla mnie brak narzędzi sugeruje brak takiej potrzeby. JSON najlepiej przetwarzać jako obiekty (tak jak i tak robi się w JS) i zwykle używasz języka samych obiektów do wykonywania transformacji (Java dla obiektów Java utworzonych z JSON, to samo dla Perla, Pythona, Perla, c #, PHP itd. na). Po prostu z normalnymi zadaniami (lub ustaw, pobierz), zapętlaniem i tak dalej.

Mam na myśli, że XSLT jest po prostu innym językiem, a jednym z powodów, dla których jest potrzebny, jest to, że XML nie jest notacją obiektową, a zatem obiekty języków programowania nie są dokładnie dopasowane (impedancja między hierarchicznym modelem xml a obiektami / strukturami).

StaxMan
źródło
Po konwersji Facebooka z XML na Json, desperacko potrzebuję takiego narzędzia.
Przynoszący duszę
O jakim przypadku myślisz? Czy jest w stanie renderować treść JSON w podobny sposób, w jaki renderowałbyś odpowiedzi XML jako HTML? A może coś innego?
StaxMan
Zastanawiam się, jak łatwo byłoby manipulować transformacją JSON za pomocą programowego sposobu obiektowego (w / zapętlanie, rozgałęzianie w razie potrzeby itp.) W porównaniu z użyciem metody typu XSLT, szczególnie w przypadku transformacji masywnego obiektu JSON i gdy niektóre dane w źródłowym JSON są przesunięte w górę / w dół niektóre węzły w docelowym JSON (a więc nie tylko bezpośrednia kopia struktury) i powiedz, gdzie określony węzeł w źródłowym lub docelowym JSON jest częścią tablicy obiektowej w JSON, a drugi JSON (źródło / cel) nie jest .
David
Łatwość jest bardzo subiektywna, więc podejrzewam, że wiele z tego ma związek z tym, do czego się przywykliśmy.
StaxMan
Chociaż zdecydowanie istnieje potrzeba transformacji JSON, masz rację, w dużej mierze JS. :-) Ale czy widziałeś jq - lekki i elastyczny procesor JSON z wierszem poleceń ? Zwłaszcza gdy JS nie jest dostępne. Powiedziałbym, że transformacja jest znacznie łatwiejsza i bardziej intuicyjna, nawet niż JS. np. aby wyodrębnić pola namei address, i umieścić je w tablicy:[.name, .address]
13ren
0

Dlaczego nie konwertujesz JSON na XML za pomocą Mr. Data Coverter , przekształcasz go za pomocą XSLT, a następnie zmieniasz z powrotem na JSON za pomocą tego samego.

użytkownik1058322
źródło
1
To nie jest opcja, jeśli chcesz, aby Twój kod zrobił to za Ciebie z dobrą wydajnością.
orad
0

Aby zapoznać się z działającym doodle / dowodem koncepcji podejścia do wykorzystania czystego JavaScript wraz ze znanym i deklaratywnym wzorcem odpowiadającym wyrażeniom XSLT i szablonom rekurencyjnym, zobacz https://gist.github.com/brettz9/0e661b3093764f496e36

(Podobne podejście można zastosować w przypadku JSON.)

Zwróć uwagę, że wersja demonstracyjna opiera się również na zamykaniu wyrażeń JavaScript 1.8 w celu ułatwienia wyrażania szablonów w przeglądarce Firefox (przynajmniej do czasu wdrożenia krótkiej formy metod ES6).

Oświadczenie: To jest mój własny kod.

Brett Zamir
źródło
0

Dawno temu napisałem adapter dom dla mojej platformy przetwarzania Json opartej na Jacksonie. Korzysta z biblioteki nu.xom. Powstałe drzewo dom działa z urządzeniami Java Xpath i xslt. Dokonałem kilku wyborów implementacyjnych, które są dość proste. Na przykład węzeł główny jest zawsze nazywany „korzeniem”, tablice przechodzą do węzła ol z podelementami li (jak w html), a wszystko inne to tylko podrzędny węzeł z pierwotną wartością lub inny węzeł obiektowy.

JsonXmlConverter.java

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

Jilles van Gurp
źródło
0

Jedną z metod, których jeszcze nie podano, jest użycie generatora analizatora składni w celu utworzenia analizatora składni w XSLT, który analizuje JSON i generuje dane wyjściowe XML.

Jedną z opcji, o której często się mówi na konferencjach XML, jest generator parsera ReX ( http://www.bottlecaps.de/rex/ ) - chociaż na stronie nie ma żadnej dokumentacji, przepisy są dostępne podczas wyszukiwania.

Tom Hillman
źródło
0

Możliwe jest użycie XSLT z JSON. Verson 3 XPath (3.1) XSLT (3.0) i XQuery (3.1) w jakiś sposób obsługuje JSON. Wydaje się, że jest to dostępne w komercyjnej wersji Saxon i może w pewnym momencie zostać uwzględnione w wersji HE. https://www.saxonica.com/html/documentation/functions/fn/parse-json.html

-

Czego oczekiwałbym od alternatywnego rozwiązania:

Chciałbym mieć możliwość wprowadzania danych JSON w celu pobrania pasującego zestawu danych i generowania danych JSON lub TEXT.

Uzyskaj dostęp do dowolnych właściwości i oceń wartości

Obsługa logiki warunkowej

Chciałbym, aby skrypty transformacji były zewnętrzne względem narzędzia, oparte na tekście, a najlepiej powszechnie używanym języku.

Potencjalna alternatywa?

Zastanawiam się, czy SQL może być odpowiednią alternatywą. https://docs.microsoft.com/en-us/sql/relational-databases/json/json-data-sql-server

Byłoby miło, gdyby alternatywne narzędzie mogło obsługiwać JSON i XML https://docs.microsoft.com/en-us/sql/relational-databases/xml/openxml-sql-server

Nie próbowałem jeszcze przekonwertować skryptów XSLT, których używam na SQL, ani w pełni nie oceniłem tej opcji, ale mam nadzieję, że przyjrzę się jej wkrótce. Jak dotąd kilka myśli.

Onceler
źródło