From dbbd94d5dbdec5e8083e34d2be4b85b2aed0e50b Mon Sep 17 00:00:00 2001 From: Adam Powers <apowers@ato.ms> Date: Sun, 16 Aug 2015 23:37:40 -0700 Subject: [PATCH] Fixes s3u/JSONPath#49 - parsing error when bracket paths contain dot Added six new tests for various path formats: $.store.book[*].author $['store']['book'][*]['author'] $[store][book][*][author] $.store.book[*]['author'] $['store']['book'][*]['application/vnd.wordperfect'] $.store.book[*]['vnd.wordperfect'] Prior to fixing a regular expression in the _normalize() function, the last two tests would fail due to the '.' in the bracket path 'vnd.wordperfect'. This is fixed by adding a negative forward lookahead (?![^\[]*\]) to the regular expression identifying '.'. The new negative forward lookahead assumes that any '.' before a '[' is okay, but any '.' before a ']' must be inside a bracket set and should be ignored. --- lib/jsonpath.js | 2 +- test/test.path_expressions.js | 113 ++++++++++++++++++++++++++++++++++ 2 files changed, 114 insertions(+), 1 deletion(-) create mode 100644 test/test.path_expressions.js diff --git a/lib/jsonpath.js b/lib/jsonpath.js index 28e0737..578901f 100644 --- a/lib/jsonpath.js +++ b/lib/jsonpath.js @@ -92,7 +92,7 @@ JSONPath.prototype._normalize = function (expr) { if (cache[expr]) {return cache[expr];} var subx = []; var normalized = expr.replace(/[\['](\??\(.*?\))[\]']/g, function ($0, $1) {return '[#' + (subx.push($1) - 1) + ']';}) - .replace(/'?\.'?|\['?/g, ';') + .replace(/'?\.'?(?![^\[]*\])|\['?/g, ';') .replace(/(?:;)?(\^+)(?:;)?/g, function ($0, ups) {return ';' + ups.split('').join(';') + ';';}) .replace(/;;;|;;/g, ';..;') .replace(/;$|'?\]|'$/g, ''); diff --git a/test/test.path_expressions.js b/test/test.path_expressions.js new file mode 100644 index 0000000..0418038 --- /dev/null +++ b/test/test.path_expressions.js @@ -0,0 +1,113 @@ +var JSONPath = require('../'), + testCase = require('nodeunit').testCase + +// tests based on examples at http://goessner.net/articles/JsonPath/ + +var json = {"store": { + "book": [ + { "category": "reference", + "author": "Nigel Rees", + "application/vnd.wordperfect": "sotc.wpd", + "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 + } + } +}; + + +module.exports = testCase({ + + // ============================================================================ + 'dot notation': function(test) { + // ============================================================================ + test.expect(1); + var books = json.store.book; + var expected = [books[0].author, books[1].author, books[2].author, books[3].author]; + var result = JSONPath({json: json, path: '$.store.book[*].author'}); + test.deepEqual(expected, result); + + test.done(); + }, + + // ============================================================================ + 'bracket notation': function(test) { + // ============================================================================ + test.expect(1); + var books = json.store.book; + var expected = [books[0].author, books[1].author, books[2].author, books[3].author]; + var result = JSONPath({json: json, path: "$['store']['book'][*]['author']"}); + test.deepEqual(expected, result); + + test.done(); + }, + + // ============================================================================ + 'bracket notation without quotes': function(test) { + // ============================================================================ + test.expect(1); + var books = json.store.book; + var expected = [books[0].author, books[1].author, books[2].author, books[3].author]; + var result = JSONPath({json: json, path: "$[store][book][*][author]"}); + test.deepEqual(expected, result); + + test.done(); + }, + + // ============================================================================ + 'mixed notation': function(test) { + // ============================================================================ + test.expect(1); + var books = json.store.book; + var expected = [books[0].author, books[1].author, books[2].author, books[3].author]; + var result = JSONPath({json: json, path: "$.store.book[*]['author']"}); + test.deepEqual(expected, result); + + test.done(); + }, + + // ============================================================================ + 'bracket notation containing dots': function(test) { + // ============================================================================ + test.expect(1); + var books = json.store.book; + var expected = [books[0]["application/vnd.wordperfect"]]; + var result = JSONPath({json: json, path: "$['store']['book'][*]['application/vnd.wordperfect']"}); + test.deepEqual(expected, result); + + test.done(); + }, + + // ============================================================================ + 'mixed notation continaing dots': function(test) { + // ============================================================================ + test.expect(1); + var books = json.store.book; + var expected = [books[0]["application/vnd.wordperfect"]]; + var result = JSONPath({json: json, path: "$.store.book[*]['application/vnd.wordperfect']"}); + test.deepEqual(expected, result); + + test.done(); + }, +}); -- GitLab