JSONに相当するXSLTはありますか?XSLTがXMLに対して行うように、JSONで変換を実行できるようにするための何か。
23 に答える
興味深いアイデアです。Google で検索すると、次のような興味深いページがいくつか見つかりました。
- そのような「jsonT」ツールを実装する方法の概要と、いくつかのダウンロード
- その実装についてのいくつかの議論
- 適切なものを実装した可能性のある会社
お役に立てれば。
JOLTを試してください。Java で記述された JSON から JSON への変換ライブラリです。
これは、「JSON -> XML -> XSLT -> XML -> JSON」というゲームをプレイしたくなかったために特別に作成されたものであり、十分に複雑な変換にテンプレートを使用することは維持できません。
XSLT は、http://www.w3.org/TR/xslt-30/#jsonで見られるように JSON をサポートします
XML は区切りトークンに角かっこを使用し、JSON は中かっこ、角かっこなどを使用します。XML のトークン認識比較が少ないということは、宣言型変換に最適化されていることを意味します。一方、switch ステートメントのような比較が多いのは、速度上の理由から、スクリプト言語の命令型コードが役立つ投機的分岐予測を前提としています。直接的な結果として、半構造化データのさまざまな組み合わせについて、レスポンシブ ページの一部として XSLT および JavaScript エンジンのパフォーマンスをベンチマークしたい場合があります。ごくわずかなデータ ペイロードの場合、変換は、XML シリアライゼーションなしの JSON でも同様に機能する可能性があります。W3 の決定は、より適切な分析に基づくべきです。
私は最近、JSON のスタイリングに気に入っているツールを見つけました: https://github.com/twigkit/tempo。非常に使いやすいツールです。私の意見では、XSLT よりもはるかに使いやすく、XPATH クエリは必要ありません。
私は最近、これを中心に自分の小さなライブラリを書きました。
5.1 処理モデル (XSLT REC) https://www.w3.org/TR/xslt#section-Processing-Model
数行の JavaScript コードで (とにかく私ができるように) 可能です。
以下に、完全に自明ではない使用例をいくつか示します...
1. JSON から何らかのマークアップへ:
フィドル: https://jsfiddle.net/YSharpLanguage/kj9pk8oz/10
( D.1 Document Example (XSLT REC) https://www.w3.org/TR/xslt#section-Document-Exampleに触発された)
ここで:
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));
...与えます:
<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>
と
2. JSON から JSON へ:
フィドル: https://jsfiddle.net/YSharpLanguage/ppfmmu15/10
ここで:
// (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));
...与えます:
{
"some_virtual_dom": {
"the_dudes": {
"ul": [
{
"li": "John Smith (Male)"
},
{
"li": "Peter Olsen (Male)"
}
]
},
"the_grrls": {
"ul": [
{
"li": "Anna Smith (Female)"
}
]
}
}
}
3. XSLT 対 JavaScript:
JavaScript に相当する...
XSLT 3.0 REC セクション 14.4 例: 共通の値に基づくノードのグループ化
(で: http://jsfiddle.net/YSharpLanguage/8bqcd0ey/1 )
参照。https://www.w3.org/TR/xslt-30/#grouping-examples
どこ...
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)
});
})
);
...与えます:
<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 対 JavaScript:
JavaScript に相当する...
JSONiq ユース ケース セクション 1.1.2。JSON のクエリのグループ化
( https://jsfiddle.net/YSharpLanguage/hvo24hmk/3で)
参照。http://jsoniq.org/docs/JSONiq-usecases/html-single/index.html#jsongrouping
どこ...
/*
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()
...与えます:
[
{
"CA": [
{
"clothes": [
{
"socks": 510
}
]
},
{
"kitchen": [
{
"broiler": 20
},
{
"toaster": 150
}
]
}
]
},
{
"MA": [
{
"clothes": [
{
"shirt": 10
}
]
},
{
"kitchen": [
{
"blender": 250
},
{
"toaster": 50
}
]
}
]
}
]
また、JSONPath wrt の制限を克服するのにも役立ちます。このSOの質問(および確かに他の質問)によって提起されたように、祖先軸に対してクエリを実行します。
たとえば、ブランドIDを知っている食料品の割引を取得する方法、
{
"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"
}
]
}
?
考えられる解決策は次のとおりです。
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);
...これは次を与えます:
Discount of #983: 20
'HTH、
jsonpath-object-transformを見てください
ツールの欠如は必要性の欠如を示唆していると言うのは、単に疑問を投げかけているだけです。同じことが、Linux での X または Y のサポートにも当てはまります (なぜ、そのような少数派の OS 用に高品質のドライバーやゲームを開発する必要があるのでしょうか? また、大手ゲーム会社やハードウェア企業が開発していない OS に注意を払う必要があるのでしょうか?)。おそらく、XSLT と JSON を使用する必要がある人は、やや些細な回避策 (JSON を XML に変換する) を使用することになります。しかし、それは最適な解決策ではありませんね。
ネイティブの JSON 形式があり、それをブラウザーで "wysywyg" に編集したい場合、XSLT は問題に対する十分な解決策です。従来の JavaScript プログラミングでこれを行うと、骨の折れる作業になる可能性があります。
実際、私は XSLT に「石器時代」のアプローチを実装しました。部分文字列の解析を使用して、テンプレートの呼び出し、子の処理など、javascript のいくつかの基本的なコマンドを解釈します。確かに、JSON オブジェクトを使用して変換エンジンを実装するのは、 XSLT を解析するための本格的な XML パーサーを実装します。問題は、XML テンプレートを使用して JSON オブジェクトを変換するには、テンプレートの XML を解析する必要があることです。
JSON オブジェクトを XML (または HTML、テキストなど) で変換するには、構文と、変換コマンドを識別するために使用する必要がある特殊文字について慎重に検討する必要があります。そうしないと、独自のカスタム テンプレート言語用のパーサーを設計しなければならなくなります。その道を歩いてみると、きれいではないことがわかります。
更新 (2010 年 11 月 12 日): パーサーに数週間取り組んだ後、パーサーを最適化することができました。テンプレートは事前に解析され、コマンドは JSON オブジェクトとして保存されます。変換ルールも JSON オブジェクトですが、テンプレート コードは HTML とシェル コードに似た自作の構文を組み合わせたものです。複雑な JSON ドキュメントを HTML に変換して、ドキュメント エディターを作成することができました。コードはエディター用に約 1,000 行 (プライベート プロジェクト用なので共有できません)、JSON 変換コード用に約 990 行 (反復コマンド、単純な比較、テンプレート呼び出し、変数の保存と評価を含む) です。MITライセンスで公開する予定です。参加したい場合は、私にメールを送ってください。
古い質問に対するさらに別の新しい回答として、DefiantJSをご覧になることをお勧めします。これは JSONの XSLTに相当するものではなく、JSON のXSLT です。ドキュメントの「テンプレート」セクションには、次の例が含まれています。
<!-- 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>
今ある!私は最近、まさにこの目的のために、ライブラリjson-transformsを作成しました。
https://github.com/ColinEberhardt/json-transforms
XPath をモデルにした DSL であるJSPathと、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
膨大な量の JavaScript テンプレート エンジン、それらのすべてのインライン HTML テンプレート、さまざまなマークアップ スタイルなどに本当にうんざりしていたので、JSON データ構造の XSLT フォーマットを可能にする小さなライブラリを構築することにしました。決してロケット科学ではありません。JSON を XML に解析し、XSLT ドキュメントでフォーマットしただけです。これも高速で、Chrome の JavaScript テンプレート エンジンほど高速ではありませんが、他のほとんどのブラウザでは、少なくとも大規模なデータ構造用の JS エンジンの代替と同じくらい高速です。
Camel ルート umarshal(xmljson) -> to(xlst) -> marshal(xmljson) を使用しています。十分に効率的ですが (ただし 100% 完璧ではありません)、すでに Camel を使用している場合は単純です。
XSLTを使用してJSONを変換することは非常に可能です。JSON2SAXデシリアライザーとSAX2JSONシリアライザーが必要です。
Javaのサンプルコード:http: //www.gerixsoft.com/blog/json/xslt4json
Yate ( https://github.com/pasaran/yate ) は特に XSLT に基づいて設計されており、JPath (JS に相当する自然な XPath) を備えており、JavaScript にコンパイルされ、実稼働環境で使用されてきたかなりの歴史があります。実際には文書化されていませんが、サンプルとテストを読むだけで十分です。
私はずっと前に、Jackson ベースの json 処理フレームワーク用の dom アダプターを作成しました。nu.xom ライブラリを使用します。結果として得られる dom ツリーは、Java xpath および xslt 機能で動作します。非常に簡単な実装の選択をいくつか行いました。たとえば、ルート ノードは常に「ルート」と呼ばれ、配列は (html のように) li サブ要素を持つ ol ノードに入り、それ以外はすべてプリミティブ値または別のオブジェクト ノードを持つ単なるサブ ノードです。
使用法:
JsonObject sampleJson = sampleJson();
org.w3c.dom.Document domNode = JsonXmlConverter.getW3cDocument(sampleJson, "root");
XSLT の一致する式と再帰テンプレートの背後にあるおなじみの宣言型パターンと共に純粋な JavaScript を利用するアプローチの実用的な Doodle/概念実証については、https://gist.github.com/brettz9/0e661b3093764f496e36を参照してください。
(JSON についても同様のアプローチが取られる可能性があります。)
デモは、Firefox でテンプレートを表現する際の利便性のために、JavaScript 1.8 表現クロージャーにも依存していることに注意してください (少なくともメソッドの ES6 短縮形が実装されるまで)。
免責事項: これは私自身のコードです。
JSON をData Coverter さんで XMLに変換し、XSLT で変換してから、同じ方法で JSON に戻してみてはいかがでしょうか。
これが必要かどうかは定かではありません。ツールがないということは、必要がないことを示唆しています。JSON はオブジェクトとして処理するのが最適であり (とにかく JS で行われる方法)、通常はオブジェクト自体の言語を使用して変換を行います (JSON から作成された Java オブジェクトには Java、Perl、Python、Perl、C#、PHP などでも同じです)。の上)。通常の割り当て(または設定、取得)、ループなどだけです。
つまり、XSLT は単なる別の言語であり、必要な理由の 1 つは、XML がオブジェクト表記法ではないため、プログラミング言語のオブジェクトが正確に適合しない (階層的な xml モデルとオブジェクト/構造体の間のインピーダンス) ことです。