我对寻找(或必要时开发)JSON的XSLT等效项感兴趣。
由于没有发现任何内容,我正在考虑使用可能的查询语言来匹配JSON路径,以便在匹配时应用模板(来自JavaScript)(可能只是按顺序检查匹配模式的数组,然后在第一个匹配的模板,尽管允许使用xsl:apply-templates等效,以使模板适用于子级)。
我知道JSONPath,JSONQuery和RQL是JSON查询语言(尽管我还不太清楚RQL是否支持绝对路径和相对路径)。关于要考虑的因素和每种方法相对优势的任何建议。
我对寻找(或必要时开发)JSON的XSLT等效项感兴趣。
由于没有发现任何内容,我正在考虑使用可能的查询语言来匹配JSON路径,以便在匹配时应用模板(来自JavaScript)(可能只是按顺序检查匹配模式的数组,然后在第一个匹配的模板,尽管允许使用xsl:apply-templates等效,以使模板适用于子级)。
我知道JSONPath,JSONQuery和RQL是JSON查询语言(尽管我还不太清楚RQL是否支持绝对路径和相对路径)。关于要考虑的因素和每种方法相对优势的任何建议。
Answers:
XML:XSLT :: JSON:x。什么是x?
最简单的答案是x = JavaScript。尽管您可以为此提供理由,但感觉并不令人满意。即使XSLT从技术上讲是图灵完整的,但XSLT 的声明式样式与JavaScript中的命令式或函数式样式之间的对应关系仍然很差。
有几种独立的JSON查询语言,例如JSONPath,JSONiq和RQL可能代表XML的中间立场:XPath :: JSON:y(或者可能是XQuery而不是XPath)。每个以JSON为重点的文档数据库都有一种与JSON相关的查询语言。
但是现实是,尽管有一些争夺XSLT职位的竞争者,例如SpahQL,但是还没有普遍接受的,广泛支持的XSLT JSON等效项。
为什么?
对于世界上所有的JSON,为什么没有(更直接的)XSLT模拟?因为许多开发人员将XSLT视为失败的实验。任何搜索引擎都会引出诸如“ XSLT是一个痛苦缠身的失败”之类的引号。其他人则争辩说,如果只是更好地格式化,它将更受欢迎。但是,多年来,人们对XSLT的兴趣普遍有所减少。许多支持它的工具仅支持1.0版(这是1999年的规范)。十五岁的规格?有一个更新的2.0规范,如果人们对XSLT充满热情,它将得到支持。不是。
大体上,开发人员选择使用代码而不是转换模板来处理和转换XML文档。因此,毫不奇怪,当使用JSON时,他们通常也会选择以其母语进行操作,而不是添加其他“外部”转换系统。
虽然Jonathan在回答中主要谈到了XSLT作为一种语言的本质,但我认为还需要考虑另一个角度。
XSLT的目的是将XML文档转换为其他文档(XML,HTML,SGML,PDF等)。这样,XSLT通常有效地用作模板语言。
即使您将自己限制在JavaScript库中,也可以使用各种各样的模板库(您不必这样做,因为JSON中的JS仅指代符号的起源,因此不应被认为暗示着JSON仅适用于JavaScript)。此模板引擎选择器给出并指示了各种JS选项。
您的问题的后半部分将更多地讨论查询语言,这些语言的XML版本将是XPath(不是XSLT)。正如您所指出的,那里有多种选择,我没有什么可添加到该列表中的。这是一个相对较新的领域,所以我建议您选择一个并随身携带。
以下是您可以使用我的(小型[jslt.min.js])JSLT(JavaScript轻量级转换)执行的一些示例:
https://jsfiddle.net/YSharpLanguage/c7usrpsL/10
([jslt.min.js]晕死〜3.1kb缩小的)
也就是说,只有一个功能,
function Per ( subject ) { ... }
...实际上模仿XSLT(1.0)的处理模型。
(请参阅Per的正文中的“ transform”和“ template”内部函数)
因此,从本质上讲,它只是将所有内容烘焙到该单一代码中function Per ( subject ) { ... }
,从而将其评估基于其(也是)唯一参数的类型来实现:
节点集创建/过滤/展平/分组/排序/等,如果subject是一个数组,则在其中扩展所得的结点集(以及Array),并绑定到相应命名的方法(仅对的返回的Array实例Per ( subjectArray )
是扩展;即,Array.prototype保持不变)
即,Per :: Array -->
Array
(得到的Array的扩展方法具有不言自明的名称,例如groupBy,orderBy,flattenBy等-参见示例中的用法)
字符串插值(如果subject是字符串)
(然后,“ Per”返回一个带有method的对象,该方法map ( source )
绑定到主题模板字符串)
即,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 )
绑定到主题的方法的对象转换-在哪里
“ ruleName”输入Per ( subjectTransform [ , 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)" }
而...(非常相似<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及其规则集(由$:[...]数组定义)-因此,在这种情况下,使表达式“ Per(this)”在功能上与XSLT的等效
<xsl:apply-templates select="..."/>
'HTH,
我最近为此创建了一个库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 }
]
}
此转换由三个规则组成。第一个匹配本田制造的任何汽车,发射具有Honda
属性的对象,然后递归匹配。第二条规则将任何具有maker
属性的对象匹配,输出model
和year
属性。最后是递归匹配的身份转换。