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相对应:

XPath JSONPath Description / $ 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        }      }    }
XPath JSONPath Result Notes /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 spec

JsonPath.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;            }        }    }}
原创粉丝点击