Język szablonów dla danych JSON
Gdy większość pracy wykonujesz transformację JSON, możesz potrzebować tego języka szablonów, aby był skuteczny.
Motywacja
My ( Rudderstack ) jesteśmy platformą integracyjną i obsługujemy ponad 200 integracji. Zaimplementowaliśmy te integracje przy użyciu natywnego kodu Javascript , aby przekształcić zdarzenia przychodzące w ładunek docelowy, więc podsumowując, jest to manipulacja danymi JSON. Utrzymanie wszystkich tych integracji jest trudne, dlatego zbadaliśmy jsonata , aby pisać mniej kodu do przekształcania danych JSON. Chociaż ta biblioteka jest doskonała, nadal musimy spełnić nasze wymagania dotyczące wydajności. Na przykład JSONata analizuje podany szablon, tworzy abstrakcyjne drzewo składni (AST) i interpretuje AST dla danego wejścia. Ponieważ musimy przechodzić przez AST za każdym razem, jest on powolny, więc chcieliśmy zbudować silnik szablonów, który generuje kod JavaScript, aby zmniejszyć obciążenie podczas działania.
Przegląd
Biblioteka do przetwarzania danych JSON przy użyciu niestandardowej składni opartej na javascript i jspath . Dziękujemy autorom jspath za ich doskonałą pracę, ponieważ nasza biblioteka jest rozszerzeniem oryginalnej biblioteki. Chcemy również podziękować zespołowi IBM za pracę nad jsonata , ponieważ zaczerpnęliśmy kilka pomysłów z biblioteki. Możesz również rozważyć naszą bibliotekę jako alternatywę dla jsonata .
Ta biblioteka generuje kod funkcji javascript z szablonu, a następnie używa tej funkcji do oceny danych JSON. Wyprowadza kod javascript w następujących etapach:
- Lexing (tokenizacja)
- Parsowanie (tworzenie AST)
- Tłumaczenie (generowanie kodu)
- Klasa silnika streszcza powyższe kroki i zapewnia wygodny sposób używania szablonów JSON do oceny danych wejściowych.
Zainstalować:npm install rudder-json-template-engine
const engine = new JsonTemplateEngine(`'Hello ' + .name`);
engine.evaluate({name: 'World'}); // => Hello World
Szablon jest zbiorem instrukcji, a wynikiem ostatniej instrukcji jest wynik szablonu.
Zmienne
const a = 1
let b = a + 2
a + b
Dane wejściowe odnoszą się do dokumentu JSON, który chcielibyśmy przetworzyć za pomocą szablonu. Powiązania odnoszą się do dodatkowych danych lub funkcji, które zapewniamy w celu wydajnego przetwarzania danych.
Przykłady:
- Szablon:
"Hello " + (.name ?? $.defaultName) - Ocena:
engine.evaluate({name: 'World'}, {defaultName: 'World'}); {name: 'World'}jest wejście.^.nameodnosi się do właściwości „nazwa” danych wejściowych. Możemy również użyć.name, aby odnieść się do tego samego.^zawsze odnosi się do katalogu głównego danych wejściowych i.odnosi się do bieżącego kontekstu. Aby uzyskać większą przejrzystość, zapoznaj się z przykładem .{defaultName: 'World'}jest wiązaniem.$.defaultNameodnosi się do właściwości „defaultName” powiązań. Aby uzyskać większą przejrzystość, zapoznaj się z przykładem .
let arr = [1, 2, 3, 4]
let a = arr[1, 2] // [2, 3]
let b = arr[0:2] // [1, 2]
let c = arr[-2:] // [3, 4]
Obiekty
let key = "some key"
// { "a": 1, "b": 2, "c": 3, "some key": 4 }
let obj = {a: 1, b: 2, c: 3, [key]: 4 }
let a = obj["a"] // 1
let b = obj.a // 1
let c = obj{["a", "b"]} // { "a": 1, "b": 2}
let d = obj{~["a", "b"]} // { "c": 3, "some key": 4}
Funkcje
Normalne funkcje
let fn = function(arg1, arg2){
arg1 + arg2
}
Funkcje lambda/krótkie
let fn = array.map(lambda 2 * ?0);
let fn = array.map(function(args) {
2 * args[0]
})
Funkcje asynchroniczne
let fn = async function(arg1, arg2){
const result = await doSomethingAsync(arg1, arg2)
doSomethingSync(result)
}
let result = await doSomething(.a, .b)
Ścieżki są używane do uzyskiwania dostępu do właściwości w input, bindingsi variables.
Proste ścieżki
Ścieżki proste obsługują ograniczone funkcje ścieżek i są tłumaczone jako instrukcje bezpośredniego dostępu do właściwości w wygenerowanym kodzie javascript. a.b.czostaje przetłumaczony, a?.b?.cwięc są bardzo szybkie w porównaniu do ścieżek Rich . Proste ścieżki są idealne, gdy znamy strukturę obiektu.
Obsługiwane funkcje:
- Proste selektory
- Filtry pojedynczego indeksu Zapoznaj się z przykładem , aby uzyskać większą przejrzystość.
Bogate ścieżki są konwertowane na złożony kod w celu obsługi różnych odmian danych.
Jeśli użyjemy bogatej ścieżki do wyrażenia: a.b.c, automatycznie obsługuje ona następujące odmiany.
[{"a": { "b": [{"c": 2}]}}]{"a": { "b": [{"c": 2}]}}{"a": [{ "b": [{"c": 2}]}]}- Automatycznie obsługuje wybór z zagnieżdżonych obiektów i tablic.
let x = a.b.c;
let y = a."some key".c
Selektory wieloznaczne
a.*.c // selects c from any direct property of a
Selektory potomków
// selects c from any child property of a
// a.b.c, a.b1.b2.c or a.b1.b2.b3.c
let x = a..c;
let y = a.."some key";
Pojedynczy indeks lub filtry właściwości
let x = a[0].c;
let y = a[-1].c; // selects last element from array
let z = a["some key"].c
Wiele indeksów lub filtrów właściwości
let x = a[0, 2, 5].c;
let y = a["some key1", "some key2"].c;
Filtry zakresów
let x = a[2:5].c;
let y = a[:-2].c;
let z = a[2:].c;
let x = obj{["a", "b"]}; // selects a and b
let y = obj{~["a", "b"]}; // selects all properties except a and b
Filtry warunkowe lub obiektowe
let x = obj{.a > 1};
Zablokuj wyrażenia
let x = obj.({
a: .a + 1,
b: .b + 2
});
let x = obj.([.a+1, .b+2]);
Zmienne kontekstowe
.orders@order#idx.products.({
name: .name,
price: .price,
orderNum: idx,
orderId: order.id
})
Opcje ścieżki
Możemy wspomnieć o defaultPathType podczas tworzenia instancji silnika.
// For using simple path as default path type
// a.b.c will be treated as simple path
JsonTemplateEngine.create(`a.b.c`, {defaultPathType: PathType.SIMPLE});
// For using rich path as default path type
// a.b.c will be treated as rich path
JsonTemplateEngine.create(`a.b.c`, {defaultPathType: PathType.RICH});
// Use ~s to treat a.b.c as simple path
~s a.b.c
// Use ~r to treat a.b.c as rich path
~r a.b.c
Skompiluj wyrażenia czasowe
Wyrażenia czasu kompilacji są oceniane przy użyciu opcji powiązań czasu kompilacji podczas fazy kompilacji.
// {{$.a.b.c}} gets translated to 1 and
// final translated code will be "let a = 1;"
JsonTemplateEngine.create(`let a = {{$.a.b.c}};`, {
compileTimeBindings: {
a: {
b: {
c: 1
}
}
}
});
Wniosek
Stworzyliśmy prosty język do wydajnego przetwarzania danych JSON i uczyniliśmy go open-source . Budowanie języka było zabawne i mam nadzieję, że nauczyłeś się dziś czegoś nowego.

![Czym w ogóle jest lista połączona? [Część 1]](https://post.nghiatu.com/assets/images/m/max/724/1*Xokk6XOjWyIGCBujkJsCzQ.jpeg)



































