今天,尝试了下让AI使用html+jsonpath-plus库实现jsonpath解析工具,要求可以离线使用。
结果并不理想,生成的代码无法直接运行,主要有两个问题:
1.deepseek非常执着于jsonpath-plus.min.js这个不存在的文件,查了下jsonpath-plus文档说明,可以使用https://github.com/JSONPath-Plus/JSONPath/blob/main/dist/index-browser-umd.cjs
2.AI调用相关方法时直接使用的是JSONPath({path: '...', json: {}}),结果一直跑不起来,报错JSONPath is not a function,让deepseek反复检查都无法修复,最后翻了下jsonpath-plus文档,正确的用法是:JSONPath.JSONPath({path: '...', json: {}});
成品截图
jsonpathtool.html源码
[HTML] 纯文本查看复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>JsonPath解析工具</title>
<script src="index-browser-umd.cjs"></script>
<style>
body {
font-family: Arial, sans-serif;
margin: 0;
padding: 20px;
display: flex;
flex-direction: column;
height: 100vh;
box-sizing: border-box;
}
.container {
display: flex;
flex: 1;
gap: 20px;
}
.panel {
flex: 1;
display: flex;
flex-direction: column;
min-width: 0;
}
.panel-header {
font-weight: bold;
margin-bottom: 10px;
display: flex;
justify-content: space-between;
align-items: center;
}
.editor {
flex: 1;
border: 1px solid #ccc;
border-radius: 4px;
padding: 10px;
font-family: monospace;
overflow: auto;
background-color: #f9f9f9;
min-height: 0;
}
#jsonInput {
width: 100%;
height: calc(100% - 60px);
resize: none;
border: none;
outline: none;
background-color: transparent;
font-family: monospace;
}
#resultOutput {
white-space: pre-wrap;
overflow: auto;
height: 100%;
}
.jsonpath-input {
margin-top: 10px;
display: flex;
gap: 10px;
}
#jsonpathInput {
flex: 1;
padding: 8px;
border: 1px solid #ccc;
border-radius: 4px;
}
button {
padding: 8px 16px;
background-color: #4caf50;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
white-space: nowrap;
}
button:hover {
background-color: #45a049;
}
.error {
color: red;
margin-top: 10px;
}
.examples {
font-size: 0.9em;
color: #666;
margin-left: 35px;
margin-top: 5px;
}
.example-btn {
background: none;
border: none;
color: #06c;
text-decoration: underline;
cursor: pointer;
padding: 0;
margin: 0 5px;
font-size: 0.9em;
}
.example-btn:hover {
color: #004080;
}
.copy-btn {
background-color: #f0f0f0;
color: #333;
padding: 2px 8px;
font-size: 0.8em;
border: 1px solid #ccc;
}
.copy-btn:hover {
background-color: #e0e0e0;
}
.tabs {
display: flex;
margin-bottom: 10px;
}
.tab {
padding: 8px 16px;
cursor: pointer;
border: 1px solid #ccc;
border-bottom: none;
border-radius: 4px 4px 0 0;
background-color: #f0f0f0;
margin-right: 5px;
}
.tab.active {
background-color: #fff;
border-bottom: 1px solid #fff;
margin-bottom: -1px;
z-index: 1;
}
.tab-content {
display: none;
}
.tab-content.active {
display: block;
}
/* Outer tabs styling */
.outer-tabs {
display: flex;
margin-bottom: 10px;
}
.outer-tab {
padding: 6px 20px;
cursor: pointer;
border: 1px solid #ccc;
border-bottom: none;
border-radius: 4px 4px 0 0;
background-color: #f0f0f0;
margin-right: 5px;
}
.outer-tab.active {
background-color: #fff;
border-bottom: 1px solid #fff;
margin-bottom: -1px;
z-index: 1;
}
.outer-tab-content {
display: none;
flex: 1;
flex-direction: column;
}
.outer-tab-content.active {
display: flex;
}
/* Reference table styling */
table {
width: 100%;
border-collapse: collapse;
margin-bottom: 20px;
}
th,
td {
border: 1px solid #ddd;
padding: 8px;
text-align: left;
}
th {
background-color: #f2f2f2;
}
tr:nth-child(even) {
background-color: #f9f9f9;
}
.reference-section {
margin-bottom: 30px;
}
.reference-section h3 {
border-bottom: 1px solid #eee;
padding-bottom: 5px;
}
/* File upload button */
.file-upload {
position: relative;
display: inline-block;
}
.file-upload input[type="file"] {
position: absolute;
left: 0;
top: 0;
opacity: 0;
width: 100%;
height: 100%;
cursor: pointer;
}
.file-upload-btn {
padding: 8px 10px;
background-color: #2196f3;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
}
.file-upload-btn:hover {
background-color: #0b7dda;
}
.panel-header-actions {
display: flex;
gap: 10px;
align-items: center;
}
</style>
</head>
<body>
<div class="outer-tabs">
<div class="outer-tab active" data-outer-tab="tool">JsonPath解析工具</div>
<div class="outer-tab" data-outer-tab="jsonpath-reference">
JsonPath标准语法参考
</div>
<div class="outer-tab" data-outer-tab="jsonpath-plus-reference">
JsonPath-Plus完整语法参考
</div>
</div>
<div class="outer-tab-content active" id="tool-content">
<div class="container">
<div class="panel">
<div class="panel-header">
<div class="panel-header-actions">
<div class="file-upload">
<button class="file-upload-btn">上传JSON文件</button>
<input type="file" id="jsonFileInput" accept=".json,application/json" />
</div>
<span>| 输入Json </span>
<div class="examples">
示例
<button class="example-btn" data-example="basic">基本路径</button>
<button class="example-btn" data-example="wildcard">
通配符
</button>
<button class="example-btn" data-example="filter">过滤器</button>
<button class="example-btn" data-example="script">
脚本表达式
</button>
</div>
</div>
<button class="copy-btn" id="copyJsonBtn">复制</button>
</div>
<div class="editor">
<textarea
id="jsonInput"
placeholder="请输入 Json 数据..."
></textarea>
</div>
<div class="jsonpath-input">
<input
type="text"
id="jsonpathInput"
placeholder="请输入 JSONPath 表达式,例如 $.store.book[*].author"
/>
<button id="executeBtn">执行</button>
</div>
<div id="errorMsg" class="error"></div>
</div>
<div class="panel">
<div class="panel-header">
<span>解析结果</span>
<button class="copy-btn" id="copyResultBtn">复制</button>
</div>
<div class="tabs">
<div class="tab active" data-tab="result">结果</div>
<div class="tab" data-tab="paths">路径</div>
<div class="tab" data-tab="ast">AST</div>
</div>
<div class="editor">
<div id="resultOutput" class="tab-content active"></div>
<div id="pathsOutput" class="tab-content"></div>
<div id="astOutput" class="tab-content"></div>
</div>
</div>
</div>
</div>
<div class="outer-tab-content" id="jsonpath-reference-content">
<div class="reference-section" style="overflow-y: auto; height: 100%;">
<p>
参考:
<a href="https://goessner.net/articles/JsonPath/" target="_blank"
>https://goessner.net/articles/JsonPath/</a
>
</p>
<h3>JsonPath语法对照表</h3>
<table>
<tbody>
<tr class="evn">
<td><strong>XPath</strong></td>
<td><strong>JsonPath</strong></td>
<td><strong>Result</strong></td>
</tr>
<tr class="odd">
<td class="lft"><code>/store/book/author</code></td>
<td class="lft"><code>$.store.book[*].author</code></td>
<td class="lft">the authors of all books in the store</td>
</tr>
<tr class="evn">
<td class="lft"><code>//author</code></td>
<td class="lft"><code>$..author</code></td>
<td class="lft">all authors</td>
</tr>
<tr class="odd">
<td class="lft"><code>/store/*</code></td>
<td class="lft"><code>$.store.*</code></td>
<td class="lft">
all things in store, which are some books and a red bicycle.
</td>
</tr>
<tr class="evn">
<td class="lft"><code>/store//price</code></td>
<td class="lft"><code>$.store..price</code></td>
<td class="lft">the price of everything in the store.</td>
</tr>
<tr class="odd">
<td class="lft"><code>//book[3]</code></td>
<td class="lft"><code>$..book[2]</code></td>
<td class="lft">the third book</td>
</tr>
<tr class="evn">
<td class="lft"><code>//book[last()]</code></td>
<td class="lft">
<code>$..book[(@.length-1)]</code><br />
<code>$..book[-1:]</code>
</td>
<td class="lft">the last book in order.</td>
</tr>
<tr class="odd">
<td class="lft"><code>//book[position()<3]</code></td>
<td class="lft">
<code>$..book[0,1]</code><br />
<code>$..book[:2]</code>
</td>
<td class="lft">the first two books</td>
</tr>
<tr class="evn">
<td class="lft"><code>//book[isbn]</code></td>
<td class="lft"><code>$..book[?(@.isbn)]</code></td>
<td class="lft">filter all books with isbn number</td>
</tr>
<tr class="odd">
<td class="lft"><code>//book[price<10]</code></td>
<td class="lft"><code>$..book[?(@.price<10)]</code></td>
<td class="lft">filter all books cheapier than 10</td>
</tr>
<tr class="evn">
<td class="lft"><code>//*</code></td>
<td class="lft"><code>$..*</code></td>
<td class="lft">
all Elements in XML document. All members of JSON structure.
</td>
</tr>
</tbody>
</table>
<h3>JsonPath示例表</h3>
<table>
<tbody>
<tr class="evn">
<td><strong>XPath</strong></td>
<td><strong>JSONPath</strong></td>
<td><strong>Result</strong></td>
</tr>
<tr class="odd">
<td class="lft"><code>/store/book/author</code></td>
<td class="lft"><code>$.store.book[*].author</code></td>
<td class="lft">the authors of all books in the store</td>
</tr>
<tr class="evn">
<td class="lft"><code>//author</code></td>
<td class="lft"><code>$..author</code></td>
<td class="lft">all authors</td>
</tr>
<tr class="odd">
<td class="lft"><code>/store/*</code></td>
<td class="lft"><code>$.store.*</code></td>
<td class="lft">
all things in store, which are some books and a red bicycle.
</td>
</tr>
<tr class="evn">
<td class="lft"><code>/store//price</code></td>
<td class="lft"><code>$.store..price</code></td>
<td class="lft">the price of everything in the store.</td>
</tr>
<tr class="odd">
<td class="lft"><code>//book[3]</code></td>
<td class="lft"><code>$..book[2]</code></td>
<td class="lft">the third book</td>
</tr>
<tr class="evn">
<td class="lft"><code>//book[last()]</code></td>
<td class="lft">
<code>$..book[(@.length-1)]</code><br />
<code>$..book[-1:]</code>
</td>
<td class="lft">the last book in order.</td>
</tr>
<tr class="odd">
<td class="lft"><code>//book[position()<3]</code></td>
<td class="lft">
<code>$..book[0,1]</code><br />
<code>$..book[:2]</code>
</td>
<td class="lft">the first two books</td>
</tr>
<tr class="evn">
<td class="lft"><code>//book[isbn]</code></td>
<td class="lft"><code>$..book[?(@.isbn)]</code></td>
<td class="lft">filter all books with isbn number</td>
</tr>
<tr class="odd">
<td class="lft"><code>//book[price<10]</code></td>
<td class="lft"><code>$..book[?(@.price<10)]</code></td>
<td class="lft">filter all books cheapier than 10</td>
</tr>
<tr class="evn">
<td class="lft"><code>//*</code></td>
<td class="lft"><code>$..*</code></td>
<td class="lft">
all Elements in XML document. All members of JSON structure.
</td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="outer-tab-content" id="jsonpath-plus-reference-content">
<div class="reference-section" style="overflow-y: auto; height: 100%;">
<p>
参考:
<a
href="https://github.com/JSONPath-Plus/JSONPath?tab=readme-ov-file"
target="_blank"
>https://github.com/JSONPath-Plus/JSONPath</a
>
</p>
<h3>JsonPath-Plus 扩展语法</h3>
<table>
<thead>
<tr>
<th>XPath</th>
<th>JsonPath</th>
<th>Result</th>
<th>Notes</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>/store/book/author</code></td>
<td><code>$.store.book[*].author</code></td>
<td>The authors of all books in the store</td>
<td>
Can also be represented without the <code>$.</code> as
<code>store.book[*].author</code> (though this is not present in
the original spec); note that some character literals (<code
>$</code
>
and <code>@</code>) require escaping, however
</td>
</tr>
<tr>
<td><code>//author</code></td>
<td><code>$..author</code></td>
<td>All authors</td>
<td></td>
</tr>
<tr>
<td><code>/store/*</code></td>
<td><code>$.store.*</code></td>
<td>
All things in store, which are its books (a book array) and a
red bicycle (a bicycle object).
</td>
<td></td>
</tr>
<tr>
<td><code>/store//price</code></td>
<td><code>$.store..price</code></td>
<td>The price of everything in the store.</td>
<td></td>
</tr>
<tr>
<td><code>//book[3]</code></td>
<td><code>$..book[2]</code></td>
<td>The third book (book object)</td>
<td></td>
</tr>
<tr>
<td><code>//book[last()]</code></td>
<td>
<code>$..book[(@.length-1)]</code> <br />
<code>$..book[-1:]</code>
</td>
<td>The last book in order.</td>
<td>
To access a property with a special character, utilize
<code>[(@['...'])]</code> for the filter (this particular
feature is not present in the original spec)
</td>
</tr>
<tr>
<td><code>//book[position()<3]</code></td>
<td>
<code>$..book[0,1]</code> <br />
<code>$..book[:2]</code>
</td>
<td>The first two books</td>
<td></td>
</tr>
<tr>
<td>
<code>//book/*[self::category|self::author]</code> or
<code>//book/(category,author)</code> in XPath 2.0
</td>
<td><code>$..book[0][category,author]</code></td>
<td>The categories and authors of all books</td>
<td></td>
</tr>
<tr>
<td><code>//book[isbn]</code></td>
<td><code>$..book[?(@.isbn)]</code></td>
<td>Filter all books with an ISBN number</td>
<td>
To access a property with a special character, utilize
<code>[?@['...']]</code> for the filter (this particular feature
is not present in the original spec)
</td>
</tr>
<tr>
<td><code>//book[price<10]</code></td>
<td><code>$..book[?(@.price<10)]</code></td>
<td>Filter all books cheaper than 10</td>
<td></td>
</tr>
<tr>
<td><code>//*[name() = 'price' and . != 8.95]</code></td>
<td>
<code
>$..*[?(@property === 'price' && @ !== 8.95)]</code
>
</td>
<td>
Obtain all property values of objects whose property is price
and which does not equal 8.95
</td>
<td>
With the bare <code>@</code> allowing filtering objects by
property value (not necessarily within arrays), you can add
<code>^</code> after the expression to get at the object
possessing the filtered properties
</td>
</tr>
<tr>
<td><code>/</code></td>
<td><code>$</code></td>
<td>
The root of the JSON object (i.e., the whole object itself)
</td>
<td>
To get a literal <code>$</code> (by itself or anywhere in the
path), you must use the backtick escape
</td>
</tr>
<tr>
<td><code>//*/*|//*/*/text()</code></td>
<td><code>$..*</code></td>
<td>
All Elements (and text) beneath root in an XML document. All
members of a JSON structure beneath the root.
</td>
<td></td>
</tr>
<tr>
<td><code>//*</code></td>
<td><code>$..</code></td>
<td>
All Elements in an XML document. All parent components of a JSON
structure including root.
</td>
<td>
This behavior was not directly specified in the original spec
</td>
</tr>
<tr>
<td><code>//*[price>19]/..</code></td>
<td><code>$..[?(@.price>19)]^</code></td>
<td>
Parent of those specific items with a price greater than 19
(i.e., the store value as the parent of the bicycle and the book
array as parent of an individual book)
</td>
<td>Parent (caret) not present in the original spec</td>
</tr>
<tr>
<td><code>/store/*/name()</code> (in XPath 2.0)</td>
<td><code>$.store.*~</code></td>
<td>
The property names of the store sub-object ("book" and
"bicycle"). Useful with wildcard properties.
</td>
<td>Property name (tilde) is not present in the original spec</td>
</tr>
<tr>
<td>
<code>/store/book[not(. is /store/book[1])]</code> (in XPath
2.0)
</td>
<td>
<code>$.store.book[?(@path !== "$['store']['book'][0]")]</code>
</td>
<td>All books besides that at the path pointing to the first</td>
<td><code>@path</code> is not present in the original spec</td>
</tr>
<tr>
<td>
<code>//book[parent::*/bicycle/color = "red"]/category</code>
</td>
<td>
<code
>$..book[?(@parent.bicycle && @parent.bicycle.color
=== "red")].category</code
>
</td>
<td>
Grabs all categories of books where the parent object of the
book has a bicycle child whose color is red (i.e., all the
books)
</td>
<td><code>@parent</code> is not present in the original spec</td>
</tr>
<tr>
<td><code>//book/*[name() != 'category']</code></td>
<td><code>$..book.*[?(@property !== "category")]</code></td>
<td>Grabs all children of "book" except for "category" ones</td>
<td>
<code>@property</code> is not present in the original spec
</td>
</tr>
<tr>
<td><code>//book[position() != 1]</code></td>
<td><code>$..book[?(@property !== 0)]</code></td>
<td>
Grabs all books whose property (which, being that we are
reaching inside an array, is the numeric index) is not 0
</td>
<td>
<code>@property</code> is not present in the original spec
</td>
</tr>
<tr>
<td><code>/store/*/*[name(parent::*) != 'book']</code></td>
<td><code>$.store.*[?(@parentProperty !== "book")]</code></td>
<td>
Grabs the grandchildren of store whose parent property is not
book (i.e., bicycle's children, "color" and "price")
</td>
<td>
<code>@parentProperty</code> is not present in the original spec
</td>
</tr>
<tr>
<td>
<code>//book[count(preceding-sibling::*) != 0]/*/text()</code>
</td>
<td><code>$..book.*[?(@parentProperty !== 0)]</code></td>
<td>
Get the property values of all book instances whereby the parent
property of these values (i.e., the array index holding the book
item parent object) is not 0
</td>
<td>
<code>@parentProperty</code> is not present in the original spec
</td>
</tr>
<tr>
<td><code>//book[price = /store/book[3]/price]</code></td>
<td>
<code>$..book[?(@.price === @root.store.book[2].price)]</code>
</td>
<td>
Filter all books whose price equals the price of the third book
</td>
<td><code>@root</code> is not present in the original spec</td>
</tr>
<tr>
<td>
<code>//book/../*[. instance of element(*, xs:decimal)]</code>
(in XPath 2.0)
</td>
<td><code>$..book..*@number()</code></td>
<td>Get the numeric values within the book array</td>
<td>
<code>@number()</code>, the other basic types
(<code>@boolean()</code>, <code>@string()</code>), other
low-level derived types (<code>@null()</code>,
<code>@object()</code>, <code>@array()</code>), the
JSONSchema-added type, <code>@integer()</code>, the compound
type <code>@scalar()</code> (which also accepts
<code>undefined</code> and non-finite numbers for JavaScript
objects as well as all of the basic non-object/non-function
types), the type, <code>@other()</code>, to be used in
conjunction with a user-defined callback (see
<code>otherTypeCallback</code>) and the following non-JSON types
that can nevertheless be used with JSONPath when querying
non-JSON JavaScript objects (<code>@undefined()</code>,
<code>@function()</code>, <code>@nonFinite()</code>) are not
present in the original spec
</td>
</tr>
<tr>
<td>
<code
>//book/*[name() = 'category' and matches(., 'tion$')]</code
>
(XPath 2.0)
</td>
<td>
<code
>$..book.*[?(@property === "category" &&
@.match(/TION$/i))]</code
>
</td>
<td>
All categories of books which match the regex (end in 'TION'
case insensitive)
</td>
<td>
<code>@property</code> is not present in the original spec.
</td>
</tr>
<tr>
<td>
<code>//book/*[matches(name(), 'bn$')]/parent::*</code> (XPath
2.0)
</td>
<td><code>$..book.*[?(@property.match(/bn$/i))]^</code></td>
<td>
All books which have a property matching the regex (end in
'TION' case insensitive)
</td>
<td>
<code>@property</code> is not present in the original spec.
Note: Uses the parent selector <code>^</code> at the end of the
expression to return to the parent object; without the parent
selector, it matches the two <code>isbn</code> key values.
</td>
</tr>
<tr>
<td></td>
<td>
<code>`</code> (e.g., <code> `$</code> to match a property
literally named <code>$</code>)
</td>
<td>
Escapes the entire sequence following (to be treated as a
literal)
</td>
<td>
<code>`</code> is not present in the original spec; to get a
literal backtick, use an additional backtick to escape
</td>
</tr>
</tbody>
</table>
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', function () {
const jsonInput = document.getElementById('jsonInput')
const jsonpathInput = document.getElementById('jsonpathInput')
const executeBtn = document.getElementById('executeBtn')
const resultOutput = document.getElementById('resultOutput')
const pathsOutput = document.getElementById('pathsOutput')
const astOutput = document.getElementById('astOutput')
const errorMsg = document.getElementById('errorMsg')
const copyJsonBtn = document.getElementById('copyJsonBtn')
const copyResultBtn = document.getElementById('copyResultBtn')
const exampleBtns = document.querySelectorAll('.example-btn')
const tabs = document.querySelectorAll('.tab')
const outerTabs = document.querySelectorAll('.outer-tab')
const jsonFileInput = document.getElementById('jsonFileInput')
// 设置默认JSON示例
const defaultJson = {
store: {
book: [
{
category: 'reference',
author: 'Nigel Rees',
title: 'Sayings of the Century',
price: 8.95,
inStock: true,
},
{
category: 'fiction',
author: 'Evelyn Waugh',
title: 'Sword of Honour',
price: 12.99,
inStock: false,
},
{
category: 'fiction',
author: 'Herman Melville',
title: 'Moby Dick',
isbn: '0-553-21311-3',
price: 8.99,
inStock: true,
},
{
category: 'fiction',
author: 'J. R. R. Tolkien',
title: 'The Lord of the Rings',
isbn: '0-395-19395-8',
price: 22.99,
inStock: false,
},
],
bicycle: {
color: 'red',
price: 19.95,
inStock: true,
},
meta: {
created: '2023-01-01',
updated: '2023-06-15',
},
},
authors: [
'Nigel Rees',
'Evelyn Waugh',
'Herman Melville',
'J. R. R. Tolkien',
],
timestamp: 1687046400,
}
jsonInput.value = JSON.stringify(defaultJson, null, 2)
// 设置默认JSONPath示例
jsonpathInput.value = '$.store.book[0].author'
// 示例数据
const examples = {
basic: {
path: '$.store.book[0].author',
desc: '获取第一本书的作者',
},
wildcard: {
path: '$..author',
desc: '递归查找所有author字段',
},
filter: {
path: '$.store.book[?(@.price < 10)]',
desc: '查找价格低于10的书',
},
script: {
path: '$.store.book[?(@.price > @root.store.bicycle.price)]',
desc: '查找价格高于自行车的书',
},
}
// 事件监听
executeBtn.addEventListener('click', executeJsonPath)
jsonpathInput.addEventListener('keyup', function (e) {
if (e.key === 'Enter') {
executeJsonPath()
}
})
copyJsonBtn.addEventListener('click', function () {
navigator.clipboard
.writeText(jsonInput.value)
.then(() => console.log('JSON已复制到剪贴板'))
.catch((err) => console.error('复制失败:', err))
})
copyResultBtn.addEventListener('click', function () {
const activeTab = document.querySelector('.tab.active')
let textToCopy = ''
if (activeTab.dataset.tab === 'result') {
textToCopy = resultOutput.textContent
} else if (activeTab.dataset.tab === 'paths') {
textToCopy = pathsOutput.textContent
} else if (activeTab.dataset.tab === 'ast') {
textToCopy = astOutput.textContent
}
navigator.clipboard
.writeText(textToCopy)
.then(() => console.log('内容已复制到剪贴板'))
.catch((err) => console.error('复制失败:', err))
})
exampleBtns.forEach((btn) => {
btn.addEventListener('click', function () {
const example = examples[this.dataset.example]
jsonpathInput.value = example.path
executeJsonPath()
})
})
tabs.forEach((tab) => {
tab.addEventListener('click', function () {
tabs.forEach((t) => t.classList.remove('active'))
this.classList.add('active')
document.querySelectorAll('.tab-content').forEach((content) => {
content.classList.remove('active')
})
document
.getElementById(`${this.dataset.tab}Output`)
.classList.add('active')
})
})
outerTabs.forEach((tab) => {
tab.addEventListener('click', function () {
outerTabs.forEach((t) => t.classList.remove('active'))
this.classList.add('active')
document
.querySelectorAll('.outer-tab-content')
.forEach((content) => {
content.classList.remove('active')
})
document
.getElementById(`${this.dataset.outerTab}-content`)
.classList.add('active')
})
})
// 添加文件上传处理
jsonFileInput.addEventListener('change', function (e) {
const file = e.target.files[0]
if (!file) return
const reader = new FileReader()
reader.onload = function (e) {
try {
const content = e.target.result
// 尝试解析JSON以验证格式
const jsonData = JSON.parse(content)
// 如果解析成功,设置到文本区域
jsonInput.value = JSON.stringify(jsonData, null, 2)
errorMsg.textContent = ''
} catch (error) {
errorMsg.textContent = '错误: 文件内容不是有效的JSON - ' + error.message
}
}
reader.onerror = function () {
errorMsg.textContent = '错误: 读取文件失败'
}
reader.readAsText(file)
})
function executeJsonPath() {
errorMsg.textContent = ''
resultOutput.textContent = ''
pathsOutput.textContent = ''
astOutput.textContent = ''
try {
const jsonData = JSON.parse(jsonInput.value)
const jsonPathExpr = jsonpathInput.value.trim()
if (!jsonPathExpr) {
throw new Error('请输入 JSONPath 表达式')
}
// 执行JSONPath查询
const result = JSONPath.JSONPath({
path: jsonPathExpr,
json: jsonData,
resultType: 'value',
flatten: true,
})
// 获取路径信息
const paths = JSONPath.JSONPath({
path: jsonPathExpr,
json: jsonData,
resultType: 'path',
})
// 获取AST信息
const ast = JSONPath.JSONPath({
path: jsonPathExpr,
json: jsonData,
resultType: 'pointer',
preventEval: true,
})
// 显示结果
if (result === undefined || result.length === 0) {
resultOutput.textContent = '没有匹配的结果'
} else {
resultOutput.textContent = JSON.stringify(result, null, 2)
pathsOutput.textContent = paths.join('\n')
astOutput.textContent = JSON.stringify(ast, null, 2)
}
} catch (error) {
errorMsg.textContent = '错误: ' + error.message
console.error(error)
}
}
// 初始执行
executeJsonPath()
})
</script>
</body>
</html>