JSONに相当するXSLTを見つける(または必要に応じて開発する)ことに興味がありました。
何も見つからなかったため、JSONパスの一致に使用できるクエリ言語を検討し、一致した場合に(JavaScriptから)テンプレートを適用しました(おそらく、一致するパターンの配列を順番にチェックし、一致する最初のテンプレート。ただし、xsl:apply-templatesに相当するものを使用して、テンプレートを子に適用できます)。
JSONPath、JSONQuery、およびRQLをJSONクエリ言語として認識しています(ただし、RQLが絶対パスと相対パスをサポートしているかどうかは完全には明確ではありませんでした)。考慮すべき要因とそのような使用法に対するそれぞれの相対的な利点に関する提案。
XML:XSLT :: JSON:x。 xとは何ですか?
最も簡単な答えはx= JavaScriptです。あなたはこれを主張することはできますが、それは不満に感じます。 XSLTは技術的には Turing complete ですが、XSLTの declarative スタイルとJavaScriptで見られるより命令的または機能的なスタイルの間には対応が不十分です。
JSONPath 、 JSONiq 、および [〜#〜] rql [〜#〜] のようなスタンドアロンのJSONクエリ言語がいくつかあります。 XMLの中間にあるXPath :: JSON:y(または、おそらくXPathではなくXQuery)。そして、JSONに焦点を当てたすべてのドキュメントデータベースには JSON関連のクエリ言語 があります。
しかし実際には、 SpahQL のように完全なXSLTの位置についていくつかの候補者がいるにもかかわらず、広く受け入れられ、広くサポートされているXSLTに相当するJSONはありません。
なぜ?
世界のすべてのJSONで、なぜXSLTの(より直接的な)アナログがないないのですか?多くの開発者がXSLTを失敗した実験と見なしているためです。どの検索エンジンでも、「XSLTは苦痛に包まれた失敗です」のような引用につながります。他の人たちは、それがより適切にフォーマットされていれば、より人気があると主張しました。しかし、 XSLTへの関心は、一般的に年月とともに減少しています 。それをサポートする多くのツールは、1999年の仕様である バージョン1. のみをサポートします。 15年前のスペック?より新しい2.0仕様があり、人々がXSLTに熱心であれば、それはサポートされます。そうではありません。
概して、開発者は、変換テンプレートではなく、コードを使用してXMLドキュメントを処理および変換することを選択しています。したがって、JSONを操作する際に、「外国の」変換システムを追加するのではなく、一般的にはネイティブ言語で実行することを選択することも当然です。
ジョナサンは主にXSLTの言語としての性質について彼の回答で語っていますが、考慮すべき別の角度があると思います。
XSLTの目的は、XMLドキュメントを他のドキュメント(XML、HTML、SGML、PDFなど)に変換することでした。このように、XSLTはテンプレート言語として効果的に頻繁に使用されます。
JavaScriptライブラリーに制限する場合でも、テンプレートライブラリーの膨大な配列があります(JSONのJSは表記法の起源を参照するだけであり、JSONを暗示するものと解釈されるべきではないため、その必要はありません) JavaScript専用です)。 このテンプレートエンジンセレクター は、そこにあるさまざまなJSオプションを示し、示します。
質問の後半では、クエリ言語について詳しく説明しており、これらのXMLバージョンはXPath(XSLTではない)になります。ご指摘のとおり、さまざまなオプションがあり、そのリストに追加するものはありません。この領域は比較的新しいので、1つを選んでそのまま使用することをお勧めします。
私は最近、この目的のためにライブラリjson-transformsを作成しました:
https://github.com/ColinEberhardt/json-transforms
JSPath 、XPathでモデル化されたDSL、およびXSLTから直接ヒントを得た再帰的なパターンマッチングアプローチの組み合わせを使用します。
簡単な例を示します。次の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 }
]
};
ここに変換があります:
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);
次の出力:
{
"Honda": [
{ "model": "Jazz", "year": 2010 },
{ "model": "Civic", "year": 2007 },
{ "model": "Accord", "year": 2011 }
]
}
この変換は3つのルールで構成されています。 1つ目は、Hondaが製造した自動車に一致し、Honda
プロパティを持つオブジェクトを出力してから、再帰的に一致します。 2番目のルールは、maker
プロパティを持つすべてのオブジェクトに一致し、model
およびyear
プロパティを出力します。最後は、再帰的に一致する恒等変換です。
これは、私の(小さな[jslt.min.js])JSLT-JavaScript軽量変換:
https://jsfiddle.net/YSharpLanguage/c7usrpsL/1
([jslt.min.js] 重さ〜 .1kb縮小 )
つまり、関数は1つだけです。
_function Per ( subject ) { ... }
_
...実際に模倣します XSLT(1.0)の処理モデル 。
(Perの本体内の「変換」および「テンプレート」内部関数を参照)
したがって、本質的には、実装するために、その(また)一意の引数の型に対する評価を分岐する、その単一のfunction Per ( subject ) { ... }
に単純にすべてベイクされます。
ノードセットの作成/フィルタリング/フラット化/グループ化/順序付け/など、サブジェクトが配列の場合、結果のノードセット(-配列 =も)拡張され、それに応じて名前が付けられたメソッドにバインドされます(only返されたArrayPer ( subjectArray )
への呼び出しのインスタンス拡張されている、つまり、Array.prototypeはそのままです)
つまり、Per :: Array _-->
_ Array
(結果として得られるArrayの拡張メソッドには、groupBy、orderBy、flattenByなどの自明な名前が付いています-例の使用法を参照してください)
文字列補間、件名が文字列の場合
(「Per」は、サブジェクトにバインドされているメソッドmap ( source )
を持つオブジェクトを返しますtemplate文字列)
つまり、Per :: String _-->
_ {map ::(AnyValue _-->
_ String)}
例えば。、
_Per("Hi honey, my name is {last}. {first}, {last}.").map({ "first": "James", "last": "Bond" })
_
収量:
_"Hi honey, my name is Bond. James, Bond."
_
一方、
_Per("Those '{*}' are our 10 digits.").map([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ])
_
または
_Per("Those '{*}' are our 10 digits.").map(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
_
同じ結果になります:
_"Those '0123456789' are our 10 digits."
_
だけ
_Per("Those '{*}' are our 10 digits.").map([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ], ", ")
_
収量
_"Those '0, 1, 2, 3, 4, 5, 6, 7, 8, 9' are our 10 digits."
_
XSLTの類似変換、サブジェクトが従来どおりに定義された "$"メンバーのハッシュである場合、書き換えルール(および(2)と同様に、 "Per"は、サブジェクト変換にバインドされたメソッドmap ( source )
を持つオブジェクトを返します-ここで
Per ( subjectTransform [ , ruleName ])
の「ruleName」はオプションであり、<xsl:call-template name = "templateName"> ...と同様の機能を提供します
つまり、Per ::(Transform [、ruleName :: String])_-->
_ {map ::(AnyValue _-->
_ AnyValue)}
と
変換 :: {$ :: 配列書き換えルール[rw.r.] }
([rw.r.] 述語とテンプレート関数のペア)
例:(...別の不自然な例)
_// (A "Member" must have first and last names, and a gender)
function Member(obj) {
return obj.first && obj.last && obj.sex;
}
var a_transform = { $: [
//...
[ [ Member ], // (alike <xsl:template match="...">...)
function(member) {
return {
li: Per("{first} {last}").map(member) +
" " +
Per(this).map({ gender: member.sex })
};
}
],
[ [ function(info) { return info.gender; } ], // (alike <xsl:template match="...">...)
function(info) { return Per("(gender: {gender})").map(info); }
],
[ [ "betterGenderString" ], // (alike <xsl:template name="betterGenderString">...)
function(info) {
info.pronoun = info.pronoun || "his/her";
return Per("({pronoun} gender is {gender})").map(info);
}
]
//...
] };
_
その後
_Per(a_transform).map({ "first": "John", "last": "Smith", "sex": "Male" })
_
収量:
_{ "li": "John Smith (gender: Male)" }
_
while ...(非常に似ている_<xsl:call-template name="betterGenderString">...
_)
_"James Bond... " +
Per(a_transform, "betterGenderString").map({ "pronoun": "his", "gender": "Male" })
_
収量:
_"James Bond... (his gender is Male)"
_
そして
_"Someone... " +
Per(a_transform, "betterGenderString").map({ "gender": "Male or Female" })
_
収量:
_"Someone... (his/her gender is Male or Female)"
_
その他すべての場合の恒等関数
つまり、Per :: [〜#〜] t [〜#〜] _-->
_ [〜#〜] t [〜#〜]
(つまり、Per === function ( value ) { return value ; }
)
上記の(3)では、テンプレート関数の本文内のJavaScriptの「this」は、コンテナ/オーナーTransformとそのルールセット($:[... ] array)-したがって、「Per(this)」という表現を、そのコンテキストでは、XSLTの機能的に近いものにします。
_<xsl:apply-templates select="..."/>
_
'HTH、