JsonPath与Xpath对比学习
来源:互联网 发布:修改表结构的sql语句 编辑:程序博客网 时间:2024/05/19 15:39
Xpath与JsonPath符号对比
JSONPath表达式
JSONPath表达式总是以与XPath相同的方式引用JSON结构
表达式与XML文档结合使用。 由于JSON结构是
通常是匿名的,并不一定有* root成员对象* JSONPath
假设分配给外层对象的抽象名称$
。
JSONPath表达式可以使用点符号:
$.store.book[0].title
或方括号:
$['store']['book'][0]['title']
为输入路径。内部或输出路径将始终转换为更一般的方括号。
JSONPath允许成员名称和数组索引使用通配符*
. 它从E4X和数组切片语法借用后代运算符..
来自ECMASCRIPT 4的提议[start:end:step]
.
底层脚本语言(<expr>)
的表达式可以用作一个
显式名称或索引的替代,如下所示:
$.store.book[(@.length-1)].title
Filter expressions are supported via
the syntax ?(<boolean expr>)
, as in:
使用符号@
作为当前对象。过滤器表达式通过
语法?(<boolean expr>)
,如下所示:
$.store.book[?(@.price < 10)].title
以下是对JSONPath的完整概述和并排比较语法元素与XPath相对应:
/
$
The root object/element .
@
The current object/element /
.
or []
Child operator ..
n/a Parent operator //
..
Recursive descent. JSONPath borrows this syntax from E4X. *
*
Wildcard. All objects/elements regardless their names. @
n/a Attribute access. JSON structures don’t have attributes. []
[]
Subscript operator. XPath uses it to iterate over element collections and for predicates. In Javascript and JSON it is the native array operator. ` ` [,]
n/a [start:end:step]
Array slice operator borrowed from ES4. []
?()
Applies a filter (script) expression. n/a ()
Script expression, using the underlying script engine. ()
n/a Grouping in XPath示例
让我们通过更多的例子来练习JSONPath表达式。 我们从一开始
在代表书店的XML示例之后构建的简单JSON结构:
{ "store": { "book": [ { "category": "reference", "author": "Nigel Rees", "title": "Sayings of the Century", "price": 8.95 }, { "category": "fiction", "author": "Evelyn Waugh", "title": "Sword of Honour", "price": 12.99 }, { "category": "fiction", "author": "Herman Melville", "title": "Moby Dick", "isbn": "0-553-21311-3", "price": 8.99 }, { "category": "fiction", "author": "J. R. R. Tolkien", "title": "The Lord of the Rings", "isbn": "0-395-19395-8", "price": 22.99 } ], "bicycle": { "color": "red", "price": 19.95 } } }
/store/book/author
$.store.book[*].author
The authors of all books in the store //author
$..author
All authors /store/*
$.store.*
All things in store, which are some books and a red bicycle /store//price
$.store..price
The price of everything in the store //book[3]
$..book[2]
The third book //book[last()]
$..book[(@.length-1)]<br>$..book[-1:]
The last book in order //book[position()<3]
$..book[0,1]
$..book[:2]
The first two books `//book/*[self::category self::author]or
//book/(category,author)` in XPath 2.0 $..book[category,author]
The categories and authors of all books //book[isbn]
$..book[?(@.isbn)]
Filter all books with isbn
number //book[price<10]
$..book[?(@.price<10)]
Filter all books cheapier than 10 //*[price>19]/..
$..[?(@.price>19)]
Categories with things more expensive than 19 Parent (caret) not present in original spec //*
$..*
All elements in XML document; all members of JSON structure /store/book/[position()!=1]
$.store.book[?(@path !== "$[\'store\'][\'book\'][0]")]
All books besides that at the path pointing to the first @path
not present in original specJsonPath.cs
namespace JsonPath{ #region Imports using System; using System.Collections; using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Text; using System.Text.RegularExpressions; #endregion public interface IJsonPathValueSystem { bool HasMember(object value, string member); object GetMemberValue(object value, string member); IEnumerable<string> GetMembers(object value); bool IsObject(object value); bool IsArray(object value); bool IsPrimitive(object value); } public sealed class JsonPathContext { public static readonly JsonPathContext Default = new JsonPathContext(); public Func<string /* script */, object /* value */, string /* context */, object /* result */> ScriptEvaluator { get; set; } public IJsonPathValueSystem ValueSystem { get; set; } public IEnumerable<object> Select(object obj, string expr) { return SelectNodes(obj, expr, (v, _) => v); } public IEnumerable<T> SelectNodes<T>(object obj, string expr, Func<object, string, T> resultor) { if (obj == null) throw new ArgumentNullException("obj"); if (resultor == null) throw new ArgumentNullException("resultor"); var i = new Interpreter(ValueSystem, ScriptEvaluator); expr = Normalize(expr); if (expr.Length >= 1 && expr[0] == '$') // ^\$:? expr = expr.Substring(expr.Length >= 2 && expr[1] == ';' ? 2 : 1); return i.Trace(expr, obj, "$", (value, path) => resultor(value, AsBracketNotation(path))); } static string Normalize(string expr) { var subx = new List<string>(); expr = RegExp.Replace(expr, @"[\['](\??\(.*?\))[\]']", m => { subx.Add(m.Groups[1].Value); return "[#" + subx.Count.ToString(CultureInfo.InvariantCulture) + "]"; }); expr = RegExp.Replace(expr, @"'?\.'?|\['?", ";"); expr = RegExp.Replace(expr, @";;;|;;", ";..;"); expr = RegExp.Replace(expr, @";$|'?\]|'$", string.Empty); expr = RegExp.Replace(expr, @"#([0-9]+)", m => { var index = int.Parse(m.Groups[1].Value, CultureInfo.InvariantCulture); return subx[index]; }); return expr; } public static string AsBracketNotation(string[] indicies) { if (indicies == null) throw new ArgumentNullException("indicies"); var sb = new StringBuilder(); foreach (var index in indicies) { if (sb.Length == 0) { sb.Append('$'); } else { sb.Append('['); if (RegExp.IsMatch(index, @"^[0-9*]+$")) sb.Append(index); else sb.Append('\'').Append(index).Append('\''); sb.Append(']'); } } return sb.ToString(); } static int ParseInt(string str, int defaultValue = 0) { if (string.IsNullOrEmpty(str)) return defaultValue; try { return int.Parse(str, NumberStyles.None, CultureInfo.InvariantCulture); } catch (FormatException) { return defaultValue; } } sealed class Interpreter { readonly Func<string, object, string, object> _eval; readonly IJsonPathValueSystem _system; static readonly IJsonPathValueSystem DefaultValueSystem = new BasicValueSystem(); static readonly char[] Colon = { ':' }; static readonly char[] Semicolon = { ';' }; delegate void WalkCallback(object member, string loc, string expr, object value, string path); public Interpreter(IJsonPathValueSystem valueSystem, Func<string, object, string, object> eval) { _eval = eval ?? delegate { // expr中的@符号必须专门解释才能解析为值。 在JavaScript中,实现将如下所示: // return obj && value && eval(expr.replace(/@/g, "value")); return null; }; _system = valueSystem ?? DefaultValueSystem; } sealed class TraceArgs { public readonly string Expr; public readonly object Value; public readonly string Path; public TraceArgs(string expr, object value, string path) { Expr = expr; Value = value; Path = path; } } public IEnumerable<T> Trace<T>(string expr, object value, string path, Func<object, string[], T> resultor) { return Trace(Args(expr, value, path), resultor); } static TraceArgs Args(string expr, object value, string path) { return new TraceArgs(expr, value, path); } IEnumerable<T> Trace<T>(TraceArgs args, Func<object, string[], T> resultor) { var stack = new Stack<TraceArgs>(); stack.Push(args); while (stack.Count > 0) { var popped = stack.Pop(); var expr = popped.Expr; var value = popped.Value; var path = popped.Path; if (string.IsNullOrEmpty(expr)) { if (path != null) yield return resultor(value, path.Split(Semicolon)); continue; } var i = expr.IndexOf(';'); var atom = i >= 0 ? expr.Substring(0, i) : expr; var tail = i >= 0 ? expr.Substring(i + 1) : string.Empty; if (value != null && _system.HasMember(value, atom)) { stack.Push(Args(tail, Index(value, atom), path + ";" + atom)); } else if (atom == "*") { Walk(atom, tail, value, path, (m, l, x, v, p) => stack.Push(Args(m + ";" + x, v, p))); } else if (atom == "..") { Walk(atom, tail, value, path, (m, l, x, v, p) => { var result = Index(v, m.ToString()); if (result != null && !_system.IsPrimitive(result)) stack.Push(Args("..;" + x, result, p + ";" + m)); }); stack.Push(Args(tail, value, path)); } else if (atom.Length > 2 && atom[0] == '(' && atom[atom.Length - 1] == ')') // [(exp)] { stack.Push(Args(_eval(atom, value, path.Substring(path.LastIndexOf(';') + 1)) + ";" + tail, value, path)); } else if (atom.Length > 3 && atom[0] == '?' && atom[1] == '(' && atom[atom.Length - 1] == ')') // [?(exp)] { Walk(atom, tail, value, path, (m, l, x, v, p) => { var result = _eval(RegExp.Replace(l, @"^\?\((.*?)\)$", "$1"), Index(v, m.ToString()), m.ToString()); if (Convert.ToBoolean(result, CultureInfo.InvariantCulture)) stack.Push(Args(m + ";" + x, v, p)); }); } else if (RegExp.IsMatch(atom, @"^(-?[0-9]*):(-?[0-9]*):?([0-9]*)$")) // [start:end:step] Phyton slice syntax { foreach (var a in Slice(atom, tail, value, path).Reverse()) stack.Push(a); } else if (atom.IndexOf(',') >= 0) // [name1,name2,...] { foreach (var part in RegExp.Split(atom, @"'?,'?").Reverse()) stack.Push(Args(part + ";" + tail, value, path)); } } } void Walk(string loc, string expr, object value, string path, WalkCallback callback) { if (_system.IsPrimitive(value)) return; if (_system.IsArray(value)) { var list = (IList) value; for (var i = list.Count - 1; i >= 0; i--) callback(i, loc, expr, value, path); } else if (_system.IsObject(value)) { foreach (var key in _system.GetMembers(value).Reverse()) callback(key, loc, expr, value, path); } } static IEnumerable<TraceArgs> Slice(string loc, string expr, object value, string path) { var list = value as IList; if (list == null) yield break; var length = list.Count; var parts = loc.Split(Colon); var start = ParseInt(parts[0]); var end = ParseInt(parts[1], list.Count); var step = parts.Length > 2 ? ParseInt(parts[2], 1) : 1; start = (start < 0) ? Math.Max(0, start + length) : Math.Min(length, start); end = (end < 0) ? Math.Max(0, end + length) : Math.Min(length, end); for (var i = start; i < end; i += step) yield return Args(i + ";" + expr, value, path); } object Index(object obj, string member) { return _system.GetMemberValue(obj, member); } } static class RegExp { const RegexOptions Options = RegexOptions.ECMAScript; public static bool IsMatch(string input, string pattern) { return Regex.IsMatch(input, pattern, Options); } public static string Replace(string input, string pattern, string replacement) { return Regex.Replace(input, pattern, replacement, Options); } public static string Replace(string input, string pattern, MatchEvaluator evaluator) { return Regex.Replace(input, pattern, evaluator, Options); } public static IEnumerable<string> Split(string input, string pattern) { return Regex.Split(input, pattern, Options); } } sealed class BasicValueSystem : IJsonPathValueSystem { public bool HasMember(object value, string member) { if (IsPrimitive(value)) return false; var dict = value as IDictionary; if (dict != null) return dict.Contains(member); var list = value as IList; if (list != null) { var index = ParseInt(member, -1); return index >= 0 && index < list.Count; } return false; } public object GetMemberValue(object value, string member) { if (IsPrimitive(value)) throw new ArgumentException("value"); var dict = value as IDictionary; if (dict != null) return dict[member]; var list = (IList) value; var index = ParseInt(member, -1); if (index >= 0 && index < list.Count) return list[index]; return null; } public IEnumerable<string> GetMembers(object value) { return ((IDictionary) value).Keys.Cast<string>(); } public bool IsObject(object value) { return value is IDictionary; } public bool IsArray(object value) { return value is IList; } public bool IsPrimitive(object value) { if (value == null) throw new ArgumentNullException("value"); return Type.GetTypeCode(value.GetType()) != TypeCode.Object; } } }}
阅读全文
0 0
- JsonPath 与Xpath对比学习
- JsonPath与Xpath对比学习
- JsonPath
- jsonpath
- XPath与多线程爬虫学习
- 数据提取之JSON与JsonPATH
- XPath学习
- xpath学习
- XPath 学习
- 学习XPath
- xpath学习
- Xpath学习
- 学习Xpath
- xpath学习
- xpath学习
- XPath学习
- xpath学习
- ServletContext与ServletConfig对比学习
- 区块链技术的应用了解
- 数据结构实验之图论一:基于邻接矩阵的广度优先搜索遍历
- 高级GLSL
- Netty学习(六)—WebSocket通信
- 芝麻信用919分的大神长啥样?手把手教你提高芝麻分
- JsonPath与Xpath对比学习
- zookeeper的barriers和queue简单案例
- NOI2015 Day1 T2 软件包管理器 树链剖分
- AI AI
- Ajax延迟请求数据
- ViewPager+Fragment+RecyclerView,当切换viewpager时,recyclerview自动滑动问题记录
- h264 sps pps详解
- Non-Local Image Dehazing_CVPR2016 理解
- Android网络开源框架