Ticket #5957: jsonPath.diff

File jsonPath.diff, 21.2 kB (added by kriszyp, 6 months ago)

Patch

  • query.js

     
    11dojo.provide("dojox.jsonPath.query"); 
    22 
    33dojox.jsonPath.query = function(/*Object*/obj, /*String*/expr, /*Object*/arg){ 
    4         // summaRy 
     4        // summary 
    55        //      Perform jsonPath query `expr` on javascript object or json string `obj` 
    66        //      obj - object || json string to perform query on 
    77        //      expr - jsonPath expression (string) to be evaluated 
    88        //      arg - {}special arugments.   
    9         //              resultType: "VALUE"||"BOTH"||"PATH"} (defaults to value) 
     9        //              resultType: "VALUE"||"BOTH"||"PATH"} (defaults to VALUE) 
     10        //                              This indicates whether the result set will be the actual values returned by the JsonPath query 
     11        //                              or if it will just return results as normalized paths to the value that can later be used to  
     12        //                              retrieve the actual values. If both are desired, the "BOTH" option may be used an it will 
     13        //                              return an array of objects with a path property for the path and a value property for the 
     14        //                              value. 
    1015        //              evalType: "RESULT"||"ITEM"} (defaults to ?) 
     16        //                              This indicates whether to use result-based or item-based evaluation. See the README 
     17        //                              for more information. 
     18        //              safeEval: true || false} (defaults to false) 
     19        //                              This indicates whether to use safe eval for sub-expressions. Using safe-eval prevents 
     20        //                              the execution of arbitrary code, is recommended for user supplied queries. Safe-eval 
     21        //                              also uses a subset of operators that ensures portability of the JSONPath expressions  
     22        //                              across all languages (instead of just JavaScript).  
    1123 
    1224        var re = dojox.jsonPath._regularExpressions; 
    1325        if (!arg){arg={};} 
     
    2335                        expr = expr.replace(/'([^']|'')*'/g, function(t){return "_str("+(strs.push(eval(t))-1)+")";}); 
    2436                        var ll = -1; 
    2537                        while(ll!=subx.length){ 
    26                                 ll=subx.length;//TODO: Do expression syntax checking 
    27                                 expr = expr.replace(/(\??\([^\(\)]*\))/g, function($0){return "#"+(subx.push($0)-1);}); 
     38                                ll=subx.length; 
     39                                expr = expr.replace(/(\??\([^\(\)]*\))/g, function($0){ 
     40                                        if (arg.safeEval && !$0.match(/^\??\(\s*((_str)?#?[\w\]@]+\s*[\.\+\-\/\*\>\=\<\!\|\&\[\?\:]+\s*)*(_str)?#?[\w\]]+\s*\)$/g)) 
     41                                                throw Error("This expression " + $0 + " is not safely allowed"); 
     42                                        return "#"+(subx.push($0.replace(/([^=<>!])=([^=])/,"$1===$2"))-1); 
     43                                }); 
    2844                        } 
    2945                        expr = expr.replace(/[\['](#[0-9]+)[\]']/g,'[$1]') 
    3046                                                  .replace(/'?\.'?|\['?/g, ";") 
  • README

     
    1 ------------------------------------------------------------------------------- 
    2 dojox.jsonPath 
    3 ------------------------------------------------------------------------------- 
    4 Version 1.0 
    5 Release date: 11/14/2007 
    6 ------------------------------------------------------------------------------- 
    7 Project state: beta 
    8 ------------------------------------------------------------------------------- 
    9 Project authors 
    10         Dustin Machi 
    11         Kris Zyp 
    12 ------------------------------------------------------------------------------- 
    13 Project description 
    14  
    15 jsonPath is a query system similar in idea to xpath, but for use against 
    16 javascript objects.  This code is a port of the jsonPath code at  
    17 http://code.google.com/p/jsonpath/.  It was contributed under CLA by Stefan 
    18 Goessner.  Thanks Stefan!  
    19 ------------------------------------------------------------------------------- 
    20 Dependencies: 
    21  
    22 Dojo Core (package loader). 
    23 ------------------------------------------------------------------------------- 
    24 Documentation 
    25  
    26 Usage: 
    27  
    28 var matches = dojox.jsonPath.query(objectToQuery, jsonPathExpresson) 
    29  
    30 Expressions: 
    31  
    32         $                       The Root Object 
    33         @                       The current object/element 
    34         . or []                 The child operator 
    35         ..                      Recursive descent 
    36         *                       all objects 
    37         []                      subscript operator 
    38         [,]                     Union operator 
    39         [start:end:step]        array slice operator 
    40         ?()                     applies a filter/script expression 
    41         ()                      script expresions 
    42  
    43         some examples: 
    44  
    45         Given the following test data set: 
    46  
    47         var json =  
    48                   { "store": { 
    49                         "book": [  
    50                           { "category": "reference", 
    51                                 "author": "Nigel Rees", 
    52                                 "title": "Sayings of the Century", 
    53                                 "price": 8.95 
    54                           }, 
    55                           { "category": "fiction", 
    56                                 "author": "Evelyn Waugh", 
    57                                 "title": "Sword of Honour", 
    58                                 "price": 12.99 
    59                           }, 
    60                           { "category": "fiction", 
    61                                 "author": "Herman Melville", 
    62                                 "title": "Moby Dick", 
    63                                 "isbn": "0-553-21311-3", 
    64                                 "price": 8.99 
    65                           }, 
    66                           { "category": "fiction", 
    67                                 "author": "J. R. R. Tolkien", 
    68                                 "title": "The Lord of the Rings", 
    69                                 "isbn": "0-395-19395-8", 
    70                                 "price": 22.99 
    71                           } 
    72                         ], 
    73                         "bicycle": { 
    74                           "color": "red", 
    75                           "price": 19.95 
    76                         } 
    77                   } 
    78                 }; 
    79  
    80         Here are some example queries and their output: 
    81  
    82         $.store.book[*].author  
    83         ["Nigel Rees","Evelyn Waugh","Herman Melville","J. R. R. Tolkien"] 
    84  
    85         $..author 
    86         ["Nigel Rees","Evelyn Waugh","Herman Melville","J. R. R. Tolkien"] 
    87  
    88         $.store.* 
    89         [[{"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}],{"color":"red","price":19.95}] 
    90  
    91         $.store..price 
    92         [8.95,12.99,8.99,22.99,19.95] 
    93  
    94         $..book[(@.length-1)] 
    95         [{"category":"fiction","author":"J. R. R. Tolkien","title":"The Lord of the Rings","isbn":"0-395-19395-8","price":22.99}] 
    96  
    97         $..book[-1] 
    98         [{"category":"fiction","author":"J. R. R. Tolkien","title":"The Lord of the Rings","isbn":"0-395-19395-8","price":22.99}] 
    99  
    100         $..book[0,1] 
    101         [{"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}] 
    102          
    103         $..book[:2] 
    104         [{"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}] 
    105  
    106         $..book[?(@.isbn)] 
    107         [{"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}] 
    108  
    109         $..book[?(@.price<10)] 
    110         [{"category":"reference","author":"Nigel Rees","title":"Sayings of the Century","price":8.95},{"category":"fiction","author":"Herman Melville","title":"Moby Dick","isbn":"0-553-21311-3","price":8.99}] 
    111  
    112         $..* 
    113         [{"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}},[{"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}],{"color":"red","price":19.95},{"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},"reference","Nigel Rees","Sayings of the Century",8.95,"fiction","Evelyn Waugh","Sword of Honour",12.99,"fiction","Herman Melville","Moby Dick","0-553-21311-3",8.99,"fiction","J. R. R. Tolkien","The Lord of the Rings","0-395-19395-8",22.99,"red",19.95] 
    114  
    115  
    116 ------------------------------------------------------------------------------- 
    117 Installation instructions 
    118  
    119 Grab the following from the Dojo SVN Repository: 
    120 http://svn.dojotoolkit.org/var/src/dojo/dojox/trunk/jsonPath 
    121  
    122 Install into the following directory structure: 
    123 /dojox/jsonPath/ 
    124  
    125 ...which should be at the same level as your Dojo checkout. 
     1------------------------------------------------------------------------------- 
     2dojox.jsonPath 
     3------------------------------------------------------------------------------- 
     4Version 1.0 
     5Release date: 11/14/2007 
     6------------------------------------------------------------------------------- 
     7Project state: beta 
     8------------------------------------------------------------------------------- 
     9Project authors 
     10        Dustin Machi 
     11        Kris Zyp 
     12------------------------------------------------------------------------------- 
     13Project description 
     14 
     15jsonPath is a query system similar in idea to xpath, but for use against 
     16javascript objects.  This code is a port of the jsonPath code at  
     17http://code.google.com/p/jsonpath/.  It was contributed under CLA by Stefan 
     18Goessner.  Thanks Stefan!  
     19------------------------------------------------------------------------------- 
     20Dependencies: 
     21 
     22Dojo Core (package loader). 
     23------------------------------------------------------------------------------- 
     24Documentation 
     25 
     26Usage: 
     27 
     28var matches = dojox.jsonPath.query(objectToQuery, jsonPathExpresson, options) 
     29 
     30jsonPath supports two forms of evaluation. Item-based evaluation, which is the  
     31default evaluation, executes each expression on each item in the result at each step in evaluation. 
     32Result-based evaluation executes each expression on the result at each step in evaluation, and  
     33can be selected by providing the third parameter, options with an evalType equal to "RESULT" like: 
     34jsonPath(object,query, {evalType:"RESULT"});  
     35Item-based evaluation will always produce an array of results. Result-basd evaluation follows the 
     36semantics of normal JavaScript more closely. Selecting a single item from an array by index, will actually 
     37return that item rather than an array with that item in it. With result-based evaluation, you can also 
     38use the slice operator to narrow down search results, allowing you to request paged results of queries.  
     39 
     40   
     41Expressions: 
     42 
     43        $                       The Root Object 
     44        @                       The current object/element 
     45        . or []                 The child operator 
     46        ..                      Recursive descent 
     47        *                       all objects 
     48        []                      subscript operator 
     49        [,]                     Union operator 
     50        [start:end:step]        array slice operator 
     51        ?()                     applies a filter sub-expression to extract all items from an array that match the expression 
     52        ()                      sub-expression 
     53 
     54        some examples: 
     55         
     56        For portability, sub-expressions should be limited to the following operators: 
     57        &, |, =, !=, >=, <=, +, -, /, *, ?, : 
     58         
     59        You may use the safe-eval option {safeEval:true}, to restrict sub-expressions to these operators. This 
     60        prevents the execution of arbitrary code, and is recommended for user supplied queries. Safe-eval 
     61        also uses a subset of operators that ensures portability of the JSONPath expressions across all  
     62        languages (without requiring a JavaScript interpreter).  
     63         
     64        Given the following test data set: 
     65 
     66        var json =  
     67                  { "store": { 
     68                        "book": [  
     69                          { "category": "reference", 
     70                                "author": "Nigel Rees", 
     71                                "title": "Sayings of the Century", 
     72                                "price": 8.95 
     73                          }, 
     74                          { "category": "fiction", 
     75                                "author": "Evelyn Waugh", 
     76                                "title": "Sword of Honour", 
     77                                "price": 12.99 
     78                          }, 
     79                          { "category": "fiction", 
     80                                "author": "Herman Melville", 
     81                                "title": "Moby Dick", 
     82                                "isbn": "0-553-21311-3", 
     83                                "price": 8.99 
     84                          }, 
     85                          { "category": "fiction", 
     86                                "author": "J. R. R. Tolkien", 
     87                                "title": "The Lord of the Rings", 
     88                                "isbn": "0-395-19395-8", 
     89                                "price": 22.99 
     90                          } 
     91                        ], 
     92                        "bicycle": { 
     93                          "color": "red", 
     94                          "price": 19.95 
     95                        } 
     96                  } 
     97                }; 
     98 
     99        Here are some example queries and their output (when result-based  
     100        evaluation and item-based evaluation differ, it is noted): 
     101 
     102        $.store.book[*].author  
     103        ["Nigel Rees","Evelyn Waugh","Herman Melville","J. R. R. Tolkien"] 
     104 
     105        $..author 
     106        ["Nigel Rees","Evelyn Waugh","Herman Melville","J. R. R. Tolkien"] 
     107 
     108        $.store.* 
     109        [[{"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}],{"color":"red","price":19.95}] 
     110 
     111        $.store..price 
     112        [8.95,12.99,8.99,22.99,19.95] 
     113 
     114        $..book[(@.length-1)] 
     115item-based:     [{"category":"fiction","author":"J. R. R. Tolkien","title":"The Lord of the Rings","isbn":"0-395-19395-8","price":22.99}] 
     116result-based: {"category":"fiction","author":"J. R. R. Tolkien","title":"The Lord of the Rings","isbn":"0-395-19395-8","price":22.99} 
     117 
     118        $..book[-1] 
     119item-based:     [{"category":"fiction","author":"J. R. R. Tolkien","title":"The Lord of the Rings","isbn":"0-395-19395-8","price":22.99}] 
     120result-based: {"category":"fiction","author":"J. R. R. Tolkien","title":"The Lord of the Rings","isbn":"0-395-19395-8","price":22.99} 
     121         
     122        $..book[0,1] 
     123        [{"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}] 
     124         
     125        $..book[:2] 
     126        [{"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}] 
     127 
     128        $..book[?(@.isbn)] 
     129        [{"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}] 
     130 
     131        $..book[?(@.price<10)] 
     132        [{"category":"reference","author":"Nigel Rees","title":"Sayings of the Century","price":8.95},{"category":"fiction","author":"Herman Melville","title":"Moby Dick","isbn":"0-553-21311-3","price":8.99}] 
     133 
     134        $..* 
     135        [{"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}},[{"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}],{"color":"red","price":19.95},{"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},"reference","Nigel Rees","Sayings of the Century",8.95,"fiction","Evelyn Waugh","Sword of Honour",12.99,"fiction","Herman Melville","Moby Dick","0-553-21311-3",8.99,"fiction","J. R. R. Tolkien","The Lord of the Rings","0-395-19395-8",22.99,"red",19.95] 
     136 
     137        $..book[?(@.price<10)][0:2] 
     138item-based: [] 
     139result-based: [{"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}] 
     140 
     141------------------------------------------------------------------------------- 
     142Installation instructions 
     143 
     144Grab the following from the Dojo SVN Repository: 
     145http://svn.dojotoolkit.org/var/src/dojo/dojox/trunk/jsonPath 
     146 
     147Install into the following directory structure: 
     148/dojox/jsonPath/ 
     149 
     150...which should be at the same level as your Dojo checkout. 
  • tests/jsonPath.js

     
    116116                { 
    117117                        name: "$..book[?(@.isbn)]", 
    118118                        runTest: function(t) { 
    119                                 var result = dojo.toJson(dojox.jsonPath.query(dojox.jsonPath.tests.testData, this.name)); 
     119                                var result = dojo.toJson(dojox.jsonPath.query(dojox.jsonPath.tests.testData, this.name,{safeEval:true})); 
    120120                                var success =  '[{"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}]'; 
    121121                                doh.assertEqual(success,result); 
    122122                        } 
     
    124124                { 
    125125                        name: "$..book[?(@.price<10)]", 
    126126                        runTest: function(t) { 
    127                                 var result = dojo.toJson(dojox.jsonPath.query(dojox.jsonPath.tests.testData, this.name)); 
     127                                var result = dojo.toJson(dojox.jsonPath.query(dojox.jsonPath.tests.testData, this.name,{safeEval:true})); 
    128128                                var success =  '[{"category":"reference","author":"Nigel Rees","title":"Sayings of the Century","price":8.95},{"category":"fiction","author":"Herman Melville","title":"Moby Dick","isbn":"0-553-21311-3","price":8.99}]'; 
    129129                                doh.assertEqual(success,result); 
    130130                        } 
     
    132132                { 
    133133                        name: "$.symbols[*]", 
    134134                        runTest: function(t) { 
    135                                 var result = dojo.toJson(dojox.jsonPath.query(dojox.jsonPath.tests.testData, this.name)); 
     135                                var result = dojo.toJson(dojox.jsonPath.query(dojox.jsonPath.tests.testData, this.name,{safeEval:true})); 
    136136                                var success =  '[5]'; 
    137137                                doh.assertEqual(success,result); 
    138138                        } 
     
    148148                { 
    149149                        name: "$.symbols[(@[('@.$;')]?'@.$;':'@.$;')]", 
    150150                        runTest: function(t) { 
    151                                 var result = dojo.toJson(dojox.jsonPath.query(dojox.jsonPath.tests.testData, this.name)); 
     151                                var result = dojo.toJson(dojox.jsonPath.query(dojox.jsonPath.tests.testData, this.name,{safeEval:true})); 
    152152                                var success =  '[5]'; 
    153153                                doh.assertEqual(success,result); 
    154154                        } 
     
    201201                                doh.assertEqual(success,result); 
    202202                        } 
    203203                }, 
     204                { 
     205                        name: "safeEval: Illegal Eval", 
     206                        runTest: function(t) { 
     207                                try {  
     208                                        var result = dojo.toJson(dojox.jsonPath.query(dojox.jsonPath.tests.testData, "$.store.book[?(dangerousCall(5))]",{evalType:"RESULT", safeEval:true})); 
     209                                        console.log("Illegal eval permitted"); 
     210                                        doh.e("Illegal eval was permitted"); 
     211                                } catch(e) { 
     212                                        console.log("Eval properly blocked", e);         
     213                                } 
     214                        } 
     215                }, 
     216                { 
     217                        name: "safeEval: Illegal Eval 2", 
     218                        runTest: function(t) { 
     219                                try {  
     220                                        var result = dojo.toJson(dojox.jsonPath.query(dojox.jsonPath.tests.testData, "$.store.book[?(new Danger)]",{evalType:"RESULT", safeEval:true})); 
     221                                        console.log("Illegal eval permitted"); 
     222                                        doh.e("Illegal eval was permitted"); 
     223                                } catch(e) { 
     224                                        console.log("Eval properly blocked", e);                                                 
     225                                } 
     226                        } 
     227                }, 
     228                { 
     229                        name: "safeEval: Illegal Eval 3", 
     230                        runTest: function(t) { 
     231                                try {  
     232                                        var result = dojo.toJson(dojox.jsonPath.query(dojox.jsonPath.tests.testData, "$.store.book[?(@+=2)]",{evalType:"RESULT", safeEval:true})); 
     233                                        console.log("Illegal eval permitted"); 
     234                                        doh.e("Illegal eval was permitted"); 
     235                                } catch(e) { 
     236                                        console.log("Eval properly blocked", e);         
     237                                } 
     238                        } 
     239                } 
    204240 
    205241        ] 
    206242);