| name | JSON验证器 |
| description | 当验证JSON文件、检查语法、调试JSON错误或格式化JSON时,在无效JSON到达下游之前捕获错误。 |
| license | MIT |
JSON验证器技能
概述
JSON无处不在 - 配置文件、API、数据存储。无效的JSON会静默破坏系统。在它们到达生产环境之前捕获错误。
核心原则: 尽早验证,经常验证。源头的无效JSON是你代码中的错误。
何时使用
始终:
- 加载配置文件
- 解析API响应
- 提交JSON数据文件之前
- 调试解析错误时
- 验证API输入
- 检查数据完整性
触发短语:
- "验证这个JSON文件"
- "JSON语法错误"
- "检查JSON格式"
- "这个JSON有效吗?"
- "JSON解析失败"
- "格式化JSON"
JSON验证功能
语法检查
- 括号匹配验证
- 引号配对检查
- 逗号位置验证
- 转义字符检查
- Unicode字符验证
结构验证
- 数据类型检查
- 必需字段验证
- 嵌套结构检查
- 数组索引验证
- 对象键名检查
语义分析
- 业务规则验证
- 数据一致性检查
- 范围验证
- 格式验证
- 关联性检查
常见JSON错误
语法错误
问题:
JSON语法不正确
错误示例:
{
"name": "John",
"age": 30, ← 末尾多余的逗号
"city": "New York"
}
解决方案:
移除最后一个属性后的逗号
{
"name": "John",
"age": 30,
"city": "New York"
}
引号错误
问题:
引号使用不正确
错误示例:
{
name: "John", ← 键名需要引号
"message": 'Hello' ← 值必须使用双引号
}
解决方案:
所有键名和字符串值都必须使用双引号
{
"name": "John",
"message": "Hello"
}
数据类型错误
问题:
数据类型不匹配
错误示例:
{
"count": "100", ← 应该是数字
"active": "true", ← 应该是布尔值
"items": null ← 不应该是null
}
解决方案:
使用正确的JSON数据类型
{
"count": 100,
"active": true,
"items": []
}
代码实现示例
JSON验证器
import json
import re
from typing import Dict, List, Any, Optional, Union
from dataclasses import dataclass
from enum import Enum
import jsonschema
class ValidationLevel(Enum):
ERROR = "error"
WARNING = "warning"
INFO = "info"
@dataclass
class ValidationResult:
"""验证结果"""
level: ValidationLevel
message: str
line: Optional[int] = None
column: Optional[int] = None
path: Optional[str] = None
suggestion: Optional[str] = None
@dataclass
class JSONDocument:
"""JSON文档"""
content: Dict[str, Any]
raw_text: str
encoding: str
metadata: Dict[str, Any]
class JSONValidator:
"""JSON验证器"""
():
.validation_rules = ._initialize_validation_rules()
.json_schemas = {}
() -> [ValidationResult]:
:
(file_path, , encoding=) f:
content = f.read()
Exception e:
[ValidationResult(
level=ValidationLevel.ERROR,
message=
)]
.validate_json_content(content, schema)
() -> [ValidationResult]:
results = []
syntax_results = ._validate_syntax(content)
results.extend(syntax_results)
(r.level == ValidationLevel.ERROR r syntax_results):
results
:
json_data = json.loads(content)
structure_results = ._validate_structure(json_data)
results.extend(structure_results)
schema:
schema_results = ._validate_schema(json_data, schema)
results.extend(schema_results)
semantic_results = ._validate_semantics(json_data)
results.extend(semantic_results)
performance_results = ._check_performance(json_data)
results.extend(performance_results)
json.JSONDecodeError e:
results.append(ValidationResult(
level=ValidationLevel.ERROR,
message=,
line=(e, , ),
column=(e, , )
))
results
() -> [ValidationResult]:
results = []
lines = content.split()
line_num, line (lines, ):
re.search(, line):
results.append(ValidationResult(
level=ValidationLevel.ERROR,
message=,
line=line_num,
column=line.find() + ,
suggestion=
))
re.search(, line):
= re.search(, line)
line.strip().startswith():
results.append(ValidationResult(
level=ValidationLevel.ERROR,
message=,
line=line_num,
column=line.find(.group()) + ,
suggestion=
))
line line.strip().startswith():
results.append(ValidationResult(
level=ValidationLevel.ERROR,
message=,
line=line_num,
column=line.find() + ,
suggestion=
))
line.strip() line.strip().startswith():
results.append(ValidationResult(
level=ValidationLevel.WARNING,
message=,
line=line_num,
column=line.find() + ,
suggestion=
))
results
() -> [ValidationResult]:
results = []
._check_data_types(json_data, , results)
max_depth = ._calculate_depth(json_data)
max_depth > :
results.append(ValidationResult(
level=ValidationLevel.WARNING,
message=,
suggestion=
))
._check_array_sizes(json_data, , results)
._check_object_keys(json_data, , results)
results
():
(data, ):
key, value data.items():
current_path = path key
(key, ):
results.append(ValidationResult(
level=ValidationLevel.ERROR,
message=,
path=current_path
))
._check_data_types(value, current_path, results)
(data, ):
i, item (data):
current_path = path
._check_data_types(item, current_path, results)
() -> :
(data, ):
data:
current_depth
(._calculate_depth(value, current_depth + ) value data.values())
(data, ):
data:
current_depth
(._calculate_depth(item, current_depth + ) item data)
:
current_depth
():
(data, ):
key, value data.items():
current_path = path key
._check_array_sizes(value, current_path, results)
(data, ):
(data) > :
results.append(ValidationResult(
level=ValidationLevel.WARNING,
message=,
path=path,
suggestion=
))
i, item (data):
current_path = path
._check_array_sizes(item, current_path, results)
():
(data, ):
keys = (data.keys())
unique_keys = (keys)
(keys) != (unique_keys):
results.append(ValidationResult(
level=ValidationLevel.WARNING,
message=,
path=path,
suggestion=
))
key keys:
re.(, key):
results.append(ValidationResult(
level=ValidationLevel.INFO,
message=,
path= path key,
suggestion=
))
key, value data.items():
current_path = path key
._check_object_keys(value, current_path, results)
(data, ):
i, item (data):
current_path = path
._check_object_keys(item, current_path, results)
() -> [ValidationResult]:
results = []
:
jsonschema.validate(json_data, schema)
jsonschema.ValidationError e:
results.append(ValidationResult(
level=ValidationLevel.ERROR,
message=,
path=.join((p) p e.absolute_path) e.absolute_path ,
suggestion=
))
jsonschema.SchemaError e:
results.append(ValidationResult(
level=ValidationLevel.ERROR,
message=,
suggestion=
))
results
() -> [ValidationResult]:
results = []
._check_null_values(json_data, , results)
._check_empty_strings(json_data, , results)
._check_numeric_ranges(json_data, , results)
._check_date_formats(json_data, , results)
results
():
(data, ):
key, value data.items():
current_path = path key
value :
results.append(ValidationResult(
level=ValidationLevel.WARNING,
message=,
path=current_path,
suggestion=
))
._check_null_values(value, current_path, results)
(data, ):
i, item (data):
current_path = path
._check_null_values(item, current_path, results)
():
(data, ):
key, value data.items():
current_path = path key
value == :
results.append(ValidationResult(
level=ValidationLevel.INFO,
message=,
path=current_path,
suggestion=
))
._check_empty_strings(value, current_path, results)
(data, ):
i, item (data):
current_path = path
._check_empty_strings(item, current_path, results)
():
(data, ):
key, value data.items():
current_path = path key
key.lower() (value, (, )):
value < value > :
results.append(ValidationResult(
level=ValidationLevel.WARNING,
message=,
path=current_path,
suggestion=
))
key.lower() (value, (, )):
value < :
results.append(ValidationResult(
level=ValidationLevel.WARNING,
message=,
path=current_path,
suggestion=
))
._check_numeric_ranges(value, current_path, results)
(data, ):
i, item (data):
current_path = path
._check_numeric_ranges(item, current_path, results)
():
date_patterns = [
,
,
,
]
(data, ):
key, value data.items():
current_path = path key
key.lower() (value, ):
(re.(pattern, value) pattern date_patterns):
results.append(ValidationResult(
level=ValidationLevel.WARNING,
message=,
path=current_path,
suggestion=
))
._check_date_formats(value, current_path, results)
(data, ):
i, item (data):
current_path = path
._check_date_formats(item, current_path, results)
() -> [ValidationResult]:
results = []
json_str = json.dumps(json_data, ensure_ascii=)
size_bytes = (json_str.encode())
size_mb = size_bytes / ( * )
size_mb > :
results.append(ValidationResult(
level=ValidationLevel.WARNING,
message=,
suggestion=
))
._check_string_lengths(json_data, , results)
results
():
(data, ):
key, value data.items():
current_path = path key
._check_string_lengths(value, current_path, results)
(data, ):
i, item (data):
current_path = path
._check_string_lengths(item, current_path, results)
(data, ):
(data) > :
results.append(ValidationResult(
level=ValidationLevel.INFO,
message=,
path=path,
suggestion=
))
() -> [, ]:
{
: ,
: ,
: ,
:
}
() -> :
results:
report = []
by_level = {
ValidationLevel.ERROR: [],
ValidationLevel.WARNING: [],
ValidationLevel.INFO: []
}
result results:
by_level[result.level].append(result)
level [ValidationLevel.ERROR, ValidationLevel.WARNING, ValidationLevel.INFO]:
by_level[level]:
level_name = level.value.upper()
report.append()
result by_level[level]:
location =
result.line:
location =
result.column:
location +=
location +=
result.path:
location =
report.append()
result.suggestion:
report.append()
report.append()
error_count = (by_level[ValidationLevel.ERROR])
warning_count = (by_level[ValidationLevel.WARNING])
info_count = (by_level[ValidationLevel.INFO])
summary =
error_count > :
summary +=
warning_count > :
summary +=
:
summary +=
report.append(summary)
.join(report)
():
validator = JSONValidator()
json_content =
results = validator.validate_json_content(json_content)
report = validator.generate_validation_report(results)
(report)
__name__ == :
main()
JSON格式化工具
import json
from typing import Dict, Any, Optional
import yaml
class JSONFormatter:
"""JSON格式化工具"""
def __init__(self):
self.indent_size = 2
self.sort_keys = False
self.ensure_ascii = False
def format_json_file(self, file_path: str, output_path: Optional[str] = None) -> bool:
"""格式化JSON文件"""
try:
with open(file_path, 'r', encoding='utf-8') as f:
data = json.load(f)
formatted_json = json.dumps(
data,
indent=self.indent_size,
sort_keys=self.sort_keys,
ensure_ascii=self.ensure_ascii
)
output_file = output_path or file_path
with open(output_file, 'w', encoding='utf-8') as f:
f.write(formatted_json)
Exception e:
()
() -> :
:
(file_path, , encoding=) f:
data = json.load(f)
minified_json = json.dumps(
data,
separators=(, ),
ensure_ascii=.ensure_ascii
)
output_file = output_path file_path
(output_file, , encoding=) f:
f.write(minified_json)
Exception e:
()
() -> :
:
(json_file, , encoding=) f:
data = json.load(f)
(yaml_file, , encoding=) f:
yaml.dump(data, f, allow_unicode=, default_flow_style=)
Exception e:
()
() -> :
:
(yaml_file, , encoding=) f:
data = yaml.safe_load(f)
(json_file, , encoding=) f:
json.dump(data, f, indent=.indent_size, ensure_ascii=.ensure_ascii)
Exception e:
()
() -> [, ]:
:
(file1, , encoding=) f:
data1 = json.load(f)
(file2, , encoding=) f:
data2 = json.load(f)
data1 == data2:
{
: ,
: []
}
:
differences = ._find_differences(data1, data2, )
{
: ,
: differences
}
Exception e:
{
: ,
: (e)
}
() -> []:
differences = []
(obj1) != (obj2):
differences.append()
(obj1, ):
keys1 = (obj1.keys())
keys2 = (obj2.keys())
keys1 != keys2:
missing_in_obj2 = keys1 - keys2
missing_in_obj1 = keys2 - keys1
key missing_in_obj2:
differences.append()
key missing_in_obj1:
differences.append()
common_keys = keys1 & keys2
key common_keys:
new_path = path key
differences.extend(._find_differences(obj1[key], obj2[key], new_path))
(obj1, ):
(obj1) != (obj2):
differences.append()
:
i, (item1, item2) ((obj1, obj2)):
new_path = path
differences.extend(._find_differences(item1, item2, new_path))
obj1 != obj2:
differences.append()
differences
():
formatter = JSONFormatter()
success = formatter.format_json_file()
success:
()
formatter.minify_json_file(, )
formatter.json_to_yaml(, )
comparison = formatter.compare_json_files(, )
comparison[]:
()
:
()
diff comparison[]:
()
__name__ == :
main()
JSON最佳实践
文件组织
- 一致格式: 使用统一的缩进和格式
- 合理结构: 避免过深的嵌套
- 命名规范: 使用清晰、一致的键名
- 文档化: 添加必要的注释和说明
数据设计
- 类型一致: 确保相同字段的数据类型一致
- 必需字段: 明确标识必需和可选字段
- 默认值: 为可选字段提供合理的默认值
- 验证规则: 定义数据验证规则
性能优化
- 文件大小: 控制JSON文件大小
- 解析效率: 避免复杂的数据结构
- 压缩传输: 使用gzip压缩传输
- 缓存策略: 实现适当的缓存机制
相关技能
- yaml-validator - YAML验证
- data-validator - 数据验证
- api-validator - API验证
- config-validator - 配置验证