Code Monkey home page Code Monkey logo

jspath's Introduction

JSPath NPM Version Build Status

JSPath is a domain-specific language (DSL) that enables you to navigate and find data within your JSON documents. Using JSPath, you can select items of JSON in order to retrieve the data they contain.

JSPath for JSON is like XPath for XML.

It's heavily optimized both for Node.js and modern browsers.

Table of Contents

Getting Started

In the Node.js

You can install using Node Package Manager (npm):

npm install jspath

In the Browsers

<script type="text/javascript" src="jspath.min.js"></script>

It also supports RequireJS module format and YM module format.

JSPath has been tested in IE6+, Mozilla Firefox 3+, Chrome 5+, Safari 5+, Opera 10+.

Usage

JSPath.apply(path, json[, substs]);

where:

parameter data type description
path string path expression
json any valid JSON input JSON document
substs object substitutions (optional)

Quick example

JSPath.apply(
    '.automobiles{.maker === "Honda" && .year > 2009}.model',
    {
        "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 }
        ],
        "motorcycles" : [{ "maker" : "Honda", "model" : "ST1300", "year" : 2012 }]
    });

Result will be:

['Jazz', 'Accord']

Documentation

A JSPath path expression consists of two types of top-level expressions:

  1. the required location path and
  2. one or more optional predicates

This means, a path expression like

.automobiles{.maker === "Honda" && .year > 2009}.model

can be split into

the location path one predicate and the continued location path
.automobiles {.maker === "Honda" && .year > 2009} .model

Location path

To select items in JSPath, you use a location path which consists of one or more location steps.

Every location step starts with one period (.) or two periods (..), depending on the item you're trying to select:

location step description
.property locates property immediately descended from context items
..property locates property deeply descended from context items
. locates context items itself

You can use the wildcard symbol (*) instead of exact name of property:

location step description
.* locates all properties immediately descended from the context items
..* locates all properties deeply descended from the context items

Property must be a sequence of alphanumerical characters including _, $ and @ symbols, that cannot start with a number. If you need to locate properties containing any other characters, you have to quote them:

location step description
."property with non-alphanumerical characters" locates a property containing non-alphanumerical characters

Also JSPath allows to join several properties:

location step description
`(.property1 .property2
`(.property1 .property2.property2_1.property2_1_1)`

Location paths can be absolute or relative. If location path starts with the caret (^) you are using an absolute location path. This syntax is used to locate a property when another context is already used in the location path and/or the object predicates.

Consider the following JSON:

var doc = {
    "books" : [
        {
            "id"     : 1,
            "title"  : "Clean Code",
            "author" : { "name" : "Robert C. Martin" },
            "price"  : 17.96
        },
        {
            "id"     : 2,
            "title"  : "Maintainable JavaScript",
            "author" : { "name" : "Nicholas C. Zakas" },
            "price"  : 10
        },
        {
            "id"     : 3,
            "title"  : "Agile Software Development",
            "author" : { "name" : "Robert C. Martin" },
            "price"  : 20
        },
        {
            "id"     : 4,
            "title"  : "JavaScript: The Good Parts",
            "author" : { "name" : "Douglas Crockford" },
            "price"  : 15.67
        }
    ]
};

Examples

// find all books authors
JSPath.apply('.books.author', doc);
/* [{ name : 'Robert C. Martin' }, { name : 'Nicholas C. Zakas' }, { name : 'Robert C. Martin' }, { name : 'Douglas Crockford' }] */

// find all books author names
JSPath.apply('.books.author.name', doc);
/* ['Robert C. Martin', 'Nicholas C. Zakas', 'Robert C. Martin', 'Douglas Crockford' ] */

// find all names in books
JSPath.apply('.books..name', doc);
/* ['Robert C. Martin', 'Nicholas C. Zakas', 'Robert C. Martin', 'Douglas Crockford' ] */

Predicates

JSPath predicates allow you to write very specific rules about items you'd like to select when constructing your path expression. Predicates are filters that restrict the items selected by the location path. There are two possible types of predicates: object and positional predicates.

Object predicates

Object predicates can be used in a path expression to filter a subset of items according to boolean expressions working on the properties of each item. All object predicates are parenthesized by curly brackets ({ and }).

In JSPath these basic expressions can be used inside an object predicate:

  • numeric literals (e.g. 1.23)
  • string literals (e.g. "John Gold")
  • boolean literals (true and false)
  • null literal (null)
  • subpaths (e.g. .nestedProp.deeplyNestedProp)
  • nested predicates (e.g. .prop{.nestedProp{.deeplyNestedProp{.stillMore || .yetAnother} || .otherDeeplyNested}}

Furthermore, the following types of operators are valid inside an object predicate:

Comparison operators

operator description example
== returns true if both operands are equal .books{.id == "1"}
=== returns true if both operands are strictly equal with no type conversion .books{.id === 1}
!= returns true if the operands are not equal .books{.id != "1"}
!== returns true if the operands are not equal and_or not of the same data type .books{.id !== 1}
> returns true if the left operand is greater than the right operand .books{.id > 1}
>= returns true if the left operand is greater than or equal to the right operand .books{.id >= 1}
< returns true if the left operand is smaller than the right operand .books{.id < 1}
<= returns true if the left operand is smaller than or equal to the right operand .books{.id <= 1}

JSPath uses the following rules to compare arrays and objects of different types:

  • if both operands to be compared are arrays, then the comparison will be true if there is an element in the first array and an element in the second array such that the result of performing the comparison of two elements is true
  • if one operand is array and another is not, then the comparison will be true if there is element in array such that the result of performing the comparison of element and another operand is true
  • primitives to be compared as usual javascript primitives

String comparison operators

If both operands are strings, there're also available additional comparison operators:

operator description example
== returns true if both strings are equal .books{.title == "clean code"}
^== case sensitive; returns true if the left operand starts with the right operand .books{.title ^== "Javascript"}
^= case insensitive; returns true if the left operand starts with the right operand .books{.title ^= "javascript"}
==^ case sensitive; returns true if the right operand starts with the left operand .books{.title ==^ "Javascript"}
=^ case insensitive; returns true if the right operand starts with the left operand .books{.title =^ "javascript"}
$== case sensitive; returns true if the left operand ends with the right operand .books{.title $== "Javascript"}
$= case insensitive; returns true if the left operand ends with the right operand .books{.title $= "javascript"}
==$ case sensitive; returns true if the right operand ends with the left operand .books{.title ==$ "Javascript"}
=$ case insensitive; returns true if the right operand ends with the left operand .books{.title =$ "javascript"}
*== case sensitive; returns true if the left operand contains right operand .books{.title *== "Javascript"}
*= case insensitive; returns true if the left operand contains right operand .books{.title *= "javascript"}
==* case sensitive; returns true if the right operand contains left operand .books{.title ==* "Javascript"}
=* case insensitive; returns true if the right operand contains left operand .books{.title =* "javascript"}

Logical operators

operator description example
&& returns true if both operands are true .books{.price > 19 && .author.name === "Robert C. Martin"}
|| returns true if either or both operands are true .books{.title === "Maintainable JavaScript" || .title === "Clean Code"}
! returns true if operand is false .books{!.title}

In JSPath logical operators convert their operands to boolean values using following rules:

  • if an operand is an array with a length greater than 0 the result will be true else false
  • a casting with double NOT javascript operator (!!) is used in any other cases

Arithmetic operators

operator description
+ addition
- subtraction
* multiplication
/ division
% modulus

Operator precedence

precedence operator
1 (highest) !, unary -
2 *, /, %
3 +, binary -
4 <, <=, >, >=
5 ==, ===, !=, !==, ^=, ^==, $==, $=, *=, *==, =^, ==^, =$, ==$, =*, ==*
6 &&
7 (lowest) ||

Parentheses (( and )) are used to explicitly denote precedence by grouping parts of an expression that should be evaluated first.

Examples

// find all book titles whose author is Robert C. Martin
JSPath.apply('.books{.author.name === "Robert C. Martin"}.title', doc);
/* ['Clean Code', 'Agile Software Development'] */

// find all book titles with price less than 17
JSPath.apply('.books{.price < 17}.title', doc);
/* ['Maintainable JavaScript', 'JavaScript: The Good Parts'] */

Positional predicates

Positional predicates allow you to filter items by their context position. All positional predicates are parenthesized by square brackets ([ and ]).

JSPath supports four types of positional predicates – also known as slicing methods:

operator description example
[index] returns item in context at index index – the first item has index 0, positional predicates are zero-based [3] returns fourth item in context
[start:] returns range of items whose index in context is greater or equal to start [2:] returns items whose index is greater or equal to 2
[:end] returns range of items whose index in context is smaller than end [:5] returns first five items in context
[start:end] returns range of items whose index in context is greater or equal to start and smaller than end [2:5] returns three items on the indices 2, 3 and 4

index, start or end may be a negative number, which means JSPath counts from the end instead of the beginning:

example description
[-1] returns last item in context
[-3:] returns last three items in context

Examples

// find first book title
JSPath.apply('.books[0].title', doc);
/* ['Clean Code'] */

// find first title of books
JSPath.apply('.books.title[0]', doc);
/* 'Clean Code' */

// find last book title
JSPath.apply('.books[-1].title', doc);
/* ['JavaScript: The Good Parts'] */

// find two first book titles
JSPath.apply('.books[:2].title', doc);
/* ['Clean Code', 'Maintainable JavaScript'] */

// find two last book titles
JSPath.apply('.books[-2:].title', doc);
/* ['Agile Software Development', 'JavaScript: The Good Parts'] */

// find two book titles from second position
JSPath.apply('.books[1:3].title', doc);
/* ['Maintainable JavaScript', 'Agile Software Development'] */

Multiple predicates

You can use more than one predicate – any combination of object and positional predicates. The result will contain only items that match all predicates.

Examples

// find first book name whose price less than 15 and greater than 5
JSPath.apply('.books{.price < 15}{.price > 5}[0].title', doc);
/* ['Maintainable JavaScript'] */

Nested predicates

You can nest predicates as deeply as you like — saves having to repeat deep subpaths each time, shortening query length. Similar to JavaScript's "with" operator, all properties of the object become first-level properties inside the nested predicate.

Examples

// long subpaths: find books by various authors, for under $20
JSPath.apply('.books{.price < 20 && (.author.name *== "Zakas" || .author.name *== "Martin")}.title', doc);
/* ['Clean Code', 'Maintainable JavaScript'] */

// nested predicates: same query, however ".author.name" isn't repeated. For JSON with many levels, enables much more compact queries.
JSPath.apply('.books{.price < 20 && .author{.name *== "Zakas" || .name *== "Martin"}}.title', doc);
/* ['Clean Code', 'Maintainable JavaScript'] */

Substitutions

Substitutions allow you to use runtime-evaluated values in predicates and pathes (as a path root).

Examples

var path = '.books{.author.name === $author}.title';

// find book name whose author Nicholas C. Zakas
JSPath.apply(path, doc, { author : 'Nicholas C. Zakas' });
/* ['Maintainable JavaScript'] */

// find books name whose authors Robert C. Martin or Douglas Crockford
JSPath.apply(path, doc, { author : ['Robert C. Martin', 'Douglas Crockford'] });
/* ['Clean Code', 'Agile Software Development', 'JavaScript: The Good Parts'] */

Result

If the last predicate in an expression is a positional predicate using an index (e.g. [0], [5], [-1]), the result is the item at the specified index or undefined if the index is out of range. In any other cases the result of applying JSPath.apply() is always an array – empty ([]), if found nothing.

jspath's People

Contributors

colineberhardt avatar dfilatov avatar fiaxhs avatar ikokostya avatar kevin-prichard avatar mdevils avatar xpol avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

jspath's Issues

Actual “find” method

Right now I can see only apply method that returns the values themselves. However if I'd like to manipulate the data in some way, I'd need to know those items' locations.

What I propose is to add something like JSPath.find method, which would get all the things you could throw to the apply method:

JSPath.find(
    '.automobiles{.maker === "Honda" && .year > 2009}.model',
    {
        "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 }
        ],
        "motorcycles" : [{ "maker" : "Honda", "model" : "ST1300", "year" : 2012 }]
    });

But this would return an array of the “steps” which lead to every found element, so in the case above the result would be:

[
    [ "automobiles", 1, "model" ],
    [ "automobiles", 4, "model" ]
]

This way you could then easily find any specific item or it's parent/siblings using any helper functions, so you then could change this item (like in #13) or change anything around it — its parents or siblings.

Numeric Keys in JSON Throw

As per JSON spec numeric keys are valid.

This snippet however throws an error.

var o = { "123" : "ABC" };
var p = "$.123";
console.log(require('jspath').apply(p, o));

Returned object structure is different from original

Here is my code:
var data = {"fields":[
{"700":{"subfields":[{"a":"author 1"},{"g":"affiliation 1"}]}},
{"700":{"subfields":[{"a":"author 2"},{"g":"affiliation 2"}]}}
]};
var path = '.fields."700".subfields';

After applying the path I am getting:
[
{"a":"author 1"},
{"g":"affiliation 1"},
{"a":"author 2"},
{"g":"affiliation 2"}
]

instead of expected:
[
[{"a":"author 1"},{"g":"affiliation 1"}],
[{"a":"author 2"},{"g":"affiliation 2"}]
]

Is there something I am doing incorrectly?
Thank you, Lana

Relative positional predicates ? (Question)

Hi

If I have an object like this :

{ "shows" : [
  { "cast" : [ "Fred" ,"Wilma", "Barney" ] },
  { "cast" : [ "Homer" ,"Marge", "Bart" ] },
  { "cast" : [ "Peter" ,"Louis", "Meg" ] }
] }

And I'd like to get the first cast member of each show.
If I try the path '.shows.cast[0]' I'll only get 'Fred'

Anything I'm missing that might make this work ?

Thanks

Input Json is being modified

Hi,

I am feeding the following json structure into the jspath:

var json = {"books":{"book":{"chapters":[{"pages":[],"size":100}]}}};
JSPath.apply("..",json);

checking the JSON object it appears to have been modified to:
"{"books":{"book":{"chapters":[{"pages":["100"],"size":"100"}]}}}"

Pages array now contains an entry that did not exist before.

I tests with the latest 0.3.1

Thanks

[Question] Is it possible to select a subset of properties?

Eg. I want to select all cars but taking only maker and models (leaving year property.

Is it possible with jspath. I couldn't find anything related to this in README.

Thank you.

"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 }
        ],

Can't select array

Hi, great tool!

I think i found a bug: when i try to select an array i get the elements of it instead of the array itself. So the '.array' produces the same result as '.array[0:]'.

example:

data = {arr: [1,2,3]};
JSPath.apply('.arr', data);//[1, 2, 3] instead of [[1, 2, 3]]

data = {arr: [1,2,3], b: {arr:[7,8,9]}};
JSPath.apply('..arr', data);//[1, 2, 3, 7, 8, 9] instead of [[1, 2, 3],[7.8.9]]

data = {a: [1,2,3], b: 4};
JSPath.apply('.*', data);//[1, 2, 3, 4] instead of [[1,2,3],4]

Unexpected token is thrown when the path contains hyphen

It's not possible to lookup when there is an hyphen on path.

var object = { something: { anotherthing : { "other-thing" : "abc"} } };
JSPath.apply(".something.anotherthing.other-thing", object);

Uncaught Error: Unexpected token "-"
at throwError (http://localhost:8080/configuration/js/external/bower_components/jspath/lib/jspath.js:636:21)
at throwUnexpected (http://localhost:8080/configuration/js/external/bower_components/jspath/lib/jspath.js:626:9)
at parse (http://localhost:8080/configuration/js/external/bower_components/jspath/lib/jspath.js:58:13)
at compile (http://localhost:8080/configuration/js/external/bower_components/jspath/lib/jspath.js:1269:45)
at Function.decl as apply

Difference between multiple predicates and the logical AND operator

Consider the following example JSON:

var doc = {
    "books" : [
            {
            "id"     : 1,
            "title"  : "Clean Code",
            "author" : { "name" : "Robert C. Martin" },
            "price"  : 7
        },
        {
            "id"     : 2,
            "title"  : "Maintainable JavaScript",
            "author" : { "name" : "Nicholas C. Zakas" },
            "price"  : 12
        },
        {
            "id"     : 3,
            "title"  : "Agile Software Development",
            "author" : { "name" : "Robert C. Martin" },
            "price"  : 15
        }
    ]
};

I wonder now if there is a difference between the usage of multiple predicates,

JSPath.apply('.books{.price < 15}{.price > 5}.title', doc);
//yields ["Clean Code", "Maintainable JavaScript"]

or the logical AND operator (&&),

JSPath.apply('.books{.price < 15 && .price > 5}.title', doc);
//yields ["Clean Code", "Maintainable JavaScript"]

to find all books whose price is between 5 and 15?

Access property containing spaces

Am I missing something or is there no way to access a property containing spaces? I tried two things:

> JSPath.apply("['hello world']", { 'hello world': 7 });
Error: Unexpected token "["
> JSPath.apply(".$name", { 'hello world': 7 }, {name: 'hello world'});
[]

I think it would be great to add the obj['prop'] syntax in addition to obj.prop. To remain consistent with obj[0], it should probably also return an object instead of an array.

Selecting variables and from variables

I can do something like JSPath.apply('.aa{$bb === 2}', {aa: 1}, {bb: 2}).

It would be nice to be able to do something like JSPath.apply('.aa{$bb.cc === 2}', {aa: 1}, {bb: {cc: 2}}) and JSPath.apply('$aa', {}, {aa: [1,2,3]}).

Allow escaping of control characters

Need to be able to do a query on a structure like this:

{
    "A:B": {
        "id": "123456"
   }
}

Using a selector like this

JSPath('.A:B.id', data);

But get an error saying the ':' is unexpected - would be good to be able to escape this.

How to find keys of type "name:name"?

When parsing some RSS XML to JSON, some keys are create as 'name:name':value. When providing a path: .name:name, JSPath throws an error: Error: Unexpected token ":". How can I get around this?

Problem with module declaration

Hi, I have an angular application that requires various open source project, one of those is jspath. Aparently one of the other projects creates an empty exports object, and in line 1274 of the lib/jspath.js is checking this

if(typeof exports === 'object') {
    module.exports = decl;
}

The problem I have is that this is not a node project so module doesn't exists. I suggest changing to this

if(typeof exports === 'object' && typeof module === 'object') {
    module.exports = decl;
}

Not having this makes my app think its in node and fail because module does not exists.
Thanks! Great library

predicate result is wrong

json:
{
"books" : [
{
"id" : 1,
"title" : "Clean Code",
"author" : { "name" : "Robert C. Martin" },
"price" : 17.96
},
{
"id" : 2,
"title" : "Maintainable JavaScript",
"author" : { "name" : "Nicholas C. Zakas" },
"price" : -10
},
{
"id" : 3,
"title" : "Agile Software Development",
"author" : { "name" : "Robert C. Martin" },
"price" : 20
},
{
"id" : 4,
"title" : "JavaScript: The Good Parts",
"author" : { "name" : "Douglas Crockford" },
"price" : 15.67
}
],
"oks":[{"id":8}]
}

query: .books{ -(.price - 5 + 5 ) == 10 } is null
but query: .books{ -(.price + 5 - 5 ) == 10 } is right

Bug when {. $== $var} will return substitutions item length -1 items.

it('$== should work with substitutions', () => {
    const array = ['a', 'b', 'C', 'hi', 'ho', 'xi', 'big', 'pig', 'ball', 'cake', 'path/to/a.m4a', 'path/to/b.jpg']

    let resources = JSPath.apply('.{. $== $ext}', array, {ext: ['.m4a', '.jpg']})
    expect(resources).toEqual(['path/to/a.m4a', 'path/to/b.jpg'])
//    Received:
//      resources: ["big", "pig", "path/to/a.m4a", "path/to/b.jpg"]


    resources = JSPath.apply('.{. $== $ext}', array, {ext: ['.m4a', 'jpg']})
    expect(resources).toEqual(['path/to/a.m4a', 'path/to/b.jpg'])
//    Received:
//      resources: ["hi", "ho", "xi", "big", "pig", "path/to/a.m4a", "path/to/b.jpg"]
})

Depends on the string length in ext, all items with length - 1 in array will returned.

  • When ext is ['.m4a', '.jpg'] the length are all 4, so all items in array have length 3 will also returned that is "big", "pig"
  • When ext is ['.m4a', 'jpg'] the length are 4 and 3, so all items in array have length 3 and 2 will also returned that is "hi", "ho", "xi", "big", "pig"

Tested with jspath 0.3.3.

.[index] and {.[index] === xxx} for array like .prop and {.prop === xxx} for object.

For object we have:

const object = {
  categories: [
    [
      {name: 'apple', image: 'apple.jpg'},
      {name: 'pear', image: 'pear.jpg'}
    ],
    [
      {name: 'keyboard', image: 'keyboard.jpg'},
      {name: 'mouse', image: 'mouse.jpg'}
    ]
  ]
}


describe('jspath', () => {
  it('allows query object .name and return .image', () => {
    const r = JSPath.apply('.categories..{.name === "apple"}.image', object)
    expect(r).toBe(['apple.jpg'])
  })
  it('allows query object props and return parent', () => {
    const r = JSPath.apply('.categories{..name === "apple"}[0]', object)
    expect(r).toEqual([{'name': 'apple', 'image': 'apple.jpg'}, {'name': 'pear', 'image': 'pear.jpg'}])
  })
})

When it come to array how can I do same queries? I have tried:

const array = {
  categories: [
    [
      ['apple', 'apple.jpg'],
      ['pear', 'pear.jpg']
    ],
    [
      ['keyboard', 'keyboard.jpg'],
      ['mouse', 'mouse.jpg']
    ]
  ]
}


  it('should allows query array by value at index (.[0]) and return value at another index (.[1])', () => {
    const r = JSPath.apply('.categories..{.[0] === "apple"}.[1]', array)
    expect(r).toBe(['apple.jpg']) // fails...
  })
  it('should allows query array by index and return parent object', () => {
    const r = JSPath.apply('.categories{..[0] === "apple"}[0]', array)
    expect(r).toEqual([['apple', 'apple.jpg'], ['pear', 'pear.jpg']]) // coincidentally works... 
  })
})
  1. How can I do the same query when inner object become array.
  2. Would it be possible to make .[index] and {.[index] === xxx} works like .prop and {.prop === xxx} for object?

Can null be supported when returning the results?

When null appears in the JSON, JSPath seems to ignore it. For example:

var data = JSON.parse('{"Colors":{"Color":[{"ColorName":"Cyan","ColorSpecifications":{"ColorSpec":[{"Name":"Printing Method","Value":"offset"}]}},{"ColorName":"Magenta","ColorSpecifications":{"ColorSpec":[{"Name":"Printing Method","Value":"offset"}]}},{"ColorName":"Yellow","ColorSpecifications":{"ColorSpec":[{"Name":"Printing Method","Value":null}]}},{"ColorName":"Black","ColorSpecifications":{"ColorSpec":[{"Name":"Printing Method","Value":"offset"}]}}]}}');

JSPath.apply('.Colors.Color.ColorSpecifications.ColorSpec', data);

Results in:

[
  {Name: "Printing Method", Value: "offset"},
  {Name: "Printing Method", Value: "offset"},
  {Name: "Printing Method", Value: null},
  {Name: "Printing Method", Value: "offset"}
]

But when asking down to the Value, I get:

JSPath.apply('.Colors.Color.ColorSpecifications.ColorSpec.Value', data);
[
  "offset",
  "offset",
  "offset"
]

But the correct result should be:

[
"offset",
"offset",
null,
"offset"
]

Joining properties does not seem to work

Readme promises to understand expressions like (.property1 | .property2 | .propertyN).

I try JSPath.compile('.aa | .bb') and JSPath.compile('(.aa | .bb)') and get Unexpected token "|" and Unexpected token "(" respectively.

0.2.14.

JSPath modifies the input object when it contains an array, which is unexpected behaviour

Please see attached image

image

Suite:

var chai = require('chai');
var expect = chai.expect;
var jsPath = require("jspath");


describe('jspath', function () {

    it('array', function () {
        var obj = {
            a: [
                {b: 1, c: {b: 2}},
                {n: 2}
            ]
        };

        expect(obj.a).to.have.length(2);
        var b = jsPath.apply("..*.b", obj);
        expect(b).to.have.length(2);
        expect(obj.a).to.have.length(2, 'jspath does not modify the input: ' + JSON.stringify(obj.a, null, '\t'));
    });

});

[Closed] Why can absolute location paths start with a "." instead of a "^"?

The documentation says that

If location path starts with the root (^) you are using an absolute location path—your location path begins from the root items.

But all examples use the leading .—which locates a context items itself—at the beginning of an absolute path:

//The JSON data…
var doc = {
    "books" : [
            {
            "id"     : 1,
            "title"  : "Clean Code",
            "author" : { "name" : "Robert C. Martin" },
            "price"  : 7
        },
        {
            "id"     : 2,
            "title"  : "Maintainable JavaScript",
            "author" : { "name" : "Nicholas C. Zakas" },
            "price"  : 12
        },
        {
            "id"     : 3,
            "title"  : "Agile Software Development",
            "author" : { "name" : "Robert C. Martin" },
            "price"  : 15
        }
    ]
};
// and the query to find all books authors

JSPath.apply('.books.author', doc);
/* [{ name : 'Robert C. Martin' }, { name : 'Nicholas C. Zakas' }, { name : 'Robert C. Martin' }, { name : 'Douglas Crockford' }] */

instead of

console.log(JSPath.apply('^book.author', doc));

which leads to an syntax error since ^ expects a trailing popery starting with a ..

Therefore

console.log(JSPath.apply('^.books.author', doc));

yields the expected data.


I wonder now why and when a ^ should be used.

Thanks 😄

unsafe-eval error

Hi

In my application, I have content security policy set (I have to) and it does not allow 'unsafe-eval'.
jspath gives me an error EvalError: Refused to evaluate a string as JavaScript because 'unsafe-eval' is not an allowed source of script in the following Content Security Policy directive: "script-src 'self' 'unsafe-inline'".(…)"

I cannot change the CSP. Is there anyway to get around this error?

Anand

Siblings

Hello,
Wonder how do I address a sibling node in predicates, if ever?
TIA,
--Vladimir

Inverse string comparison operators

"Get every book title whichs author doesn't have 'C.' in its name"

JSPath.apply('.books{!.author.name *= "C."}.title', doc);
or
JSPath.apply('.books{.author.name *!= "C."}.title', doc);

doesn't work

cache[path] is not a function

var doc = {
"books" : [
{
"id" : 1,
"title" : "Clean Code",
"author" : { "name" : "Robert C. Martin" },
"price" : 17.96
},
{
"id" : 2,
"title" : "Maintainable JavaScript",
"author" : { "name" : "Nicholas C. Zakas" },
"price" : 10
},
{
"id" : 3,
"title" : "Agile Software Development",
"author" : { "name" : "Robert C. Martin" },
"price" : 20
},
{
"id" : 4,
"title" : "JavaScript: The Good Parts",
"author" : { "name" : "Douglas Crockford" },
"price" : 15.67
}
]
};

trying to get title using query

JSPath.apply('.books.title',doc )

getting an error

cache[path] is not a function

querying for the first element as

JSPath.apply('.books.id',doc )

getting desire responce but for other elment first throwing an error

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.