JSONPath Plus

repository·main·Indexed 22 days ago

https://github.com/jsonpath-plus/jsonpath

A JavaScript implementation of JSONPath (version 10.4.1) designed to analyze, transform, and extract data from JSON documents and JavaScript objects. It extends the standard JSONPath specification with advanced operators such as parent selectors (^), property name access (~), and type selectors (@string, @number, etc.), as well as specialized variables like @root and @parent for complex filtering.

Tokens
6.2K
Snippets
21
Records
29
Agent score
73%

What's inside jsonpath-plus

  1. Advanced JSONPath Filtering and Selectors

    main

    JSONPath Plus provides several non-standard selectors that extend the original specification to allow for more complex queries:

    • @parent: Access the parent object of the current item.
    • @root: Access the root of the JSON document.
    • @property: Access the name of the property of the current item (useful when iterating over object members).
    • @path: Access the full path of the current item.
    • @parentProperty: Access the name of the property that holds the current item (e.g., the key in an object or the index in an array).
    • ^ (Caret): A trailing selector that returns the parent of the current selection.
    • ~ (Tilde): A trailing selector that returns the property names (keys) instead of the values.
    • @number(), @string(), @boolean(), etc.: Type-based selectors to filter by data type.
    • @match(regex): Filter items based on a regular expression match.

    Note: To access properties with special characters within a filter, use the bracket notation: [?(@['special-property'])] or [?(@['...'])].

  2. Understand JSONPath vs XPath differences

    main

    If you are transitioning from XPath, note these three key behavioral differences in JSONPath Plus:

    1. Filter Selection: In JSONPath, a filter expression (using @) selects the immediate children that satisfy the condition. In XPath, filter conditions delimit which parent nodes are returned but do not select the children themselves.
    2. Array Indexing: JSONPath uses 0-based indexing (consistent with JavaScript), whereas XPath uses 1-based indexing.
    3. Equality Tests: JSONPath uses JavaScript-style equality operators (e.g., == or ===), whereas XPath uses a single = sign.
  3. Prevent Query Injection in JSONPath-Plus

    main

    JSONPath-Plus evaluates expressions provided by the caller. While the default eval: "safe" option prevents arbitrary code execution, it does not prevent data exposure if the query itself is manipulated. If untrusted input is interpolated into a JSONPath expression, an attacker can alter the query structure to return broader or unexpected data (data leakage).

    To mitigate this risk:

    1. Do not interpolate unsanitized user input into JSONPath queries.
    2. If user-controlled input must be included, ensure the target JSON object contains only non-confidential data.

    Treat JSONPath expressions as code and avoid constructing them dynamically from untrusted sources.

  4. Set up jsonpath-plus with Bundlers (ESM)

    main

    If you are using a bundler like Rollup, import JSONPath from the package. For browser builds, ensure your bundler's mainFields includes browser.

    import {JSONPath} from 'jsonpath-plus';
    
    const result = JSONPath({path: '...', json});
  5. Set up jsonpath-plus in the Browser (UMD)

    main

    For direct browser usage without a bundler, include the UMD build via a <script> tag. Note that when using the UMD build, you access the function via JSONPath.JSONPath.

    <script src="node_modules/jsonpath-plus/dist/index-browser-umd.cjs"></script>
    
    <script>
    const result = JSONPath.JSONPath({path: '...', json: {}});
    </script>
  6. JSONPath Syntax and XPath Equivalents

    main

    JSONPath Plus extends the original JSONPath specification with several powerful features, including parent selectors, property name access, and advanced filtering. The following table provides a mapping between XPath expressions and their JSONPath Plus equivalents using a sample JSON store structure.

    Key Syntax Features

    • Root Selector: $ represents the root of the JSON object.
    • Deep Scan: $.. searches for all occurrences of a property at any depth.
    • Wildcards: * matches all elements or properties.
    • Filtering: [?(@.property === 'value')] allows for conditional selection.
    • Parent Selector: Adding ^ at the end of an expression returns the parent of the matched items.
    • Property Name Access: Using ~ (e.g., $.store.*~) retrieves the names of the properties rather than their values.
    • Escaping: Use backticks (`) to escape special characters like $ or literal backticks.
    • Custom Variables: Any variables provided in the optional sandbox option are available for use within filter expressions.
    XPathJSONPathResultNotes
    /store/book/author$.store.book[*].authorAuthors of all booksCan also be store.book[*].author
    //author$..authorAll authors
    /store/*$.store.*All things in store
    /store//price$.store..pricePrice of everything in store
    //book[3]$..book[2]The third book0-indexed
    //book[last()]$..book[(@.length-1)] or $..book[-1:]The last book
    //book[position()<3]$..book[0,1] or $..book[:2]The first two books
    //book[isbn]$..book[?(@.isbn)]Books with an ISBN
    //book[price<10]$..book[?(@.price<10)]Books cheaper than 10
    //*[name() = 'price' and . != 8.95]$..*[?(@property === 'price' && @ !== 8.95)]Values where property is price and not 8.95
    /$The root object
    //*/*|//*/*/text()$..*All members beneath root
    //*$..All parent components including root
    //*[price>19]/..$..[?(@.price>19)]^Parent of items with price > 19Uses ^ parent selector
    /store/*/name()$.store.*~Property names of store sub-objectUses ~ property name selector
    //book[parent::*/bicycle/color = "red"]/category$..book[?(@parent.bicycle && @parent.bicycle.color === "red")].categoryCategories of books where parent has a red bicycleUses @parent
    //book[price = /store/book[3]/price]$..book[?(@.price === @root.store.book[2].price)]Books with price equal to the 3rd bookUses @root
    //book/*[matches(name(), 'bn$')]$..book.*[?(@property.match(/bn$/i))]^Books with a property matching regexUses @property and ^
    ` (e.g. `$)Escapes the sequenceUse for literal characters
    {
    "store": {
      "book": [
        {
          "category": "reference",
          "author": "Nigel Rees",
          "title": "Sayings of the Century",
          "price": 8.95
        }
      ]
    }
    }
  7. Report a Security Vulnerability

    main

    Do not report security vulnerabilities through public GitHub issues. If you find a vulnerability, email one of the following addresses:

    • iamavinashthakur.at@gmail.com
    • brettz9@yahoo.com

    Include these details in your report:

    1. Description of the location and potential impact.
    2. Detailed steps to reproduce (including POC scripts).
    3. How you would like to be credited.

    Policy on Disclosure: Please do not disclose the vulnerability publicly until a fix is released. You may publicly report the vulnerability on the tracker after:

    • A fix has been published,
    • The vulnerability has been declined for address,
    • Or 30 days have passed without a reply.
  8. Set up jsonpath-plus in the Browser (ESM)

    main

    For modern browsers supporting ES6 modules, import JSONPath directly from the ESM build file.

    <script type="module">
    import {
        JSONPath
    } from './node_modules/jsonpath-plus/dist/index-browser-esm.js';
    
    const result = JSONPath({path: '...', json: {}});
    </script>
  9. Run tests for JSONPath Plus

    main

    To verify the installation or contribute to the project, you can run the test suites.

    Node.js tests: Run via npm in your terminal.

    In-browser tests:

    1. Serve the js/html files using the provided script.
    2. Open your browser and navigate to http://localhost:8082/test/.
    # Run Node tests
    npm test
    
    # Run browser tests
    npm run browser-test
  10. Handle custom types with `@other()`

    main

    The @other() operator allows you to define custom type filtering. To use it, you must provide an otherTypeCallback in your options. This callback is invoked when the query encounters @other(). It should return true if the value matches your custom criteria, or false otherwise.

    const data = { a: 1, b: 'hello', c: [1, 2] };
    
    JSONPath({
      json: data,
      path: '$.@other()',
      otherTypeCallback: (val) => typeof val === 'string'
    });
    // Returns ['hello']