268 lines
8.5 KiB
Python
268 lines
8.5 KiB
Python
#!/usr/bin/env python3
|
|
# -*- coding: utf-8 -*-
|
|
|
|
from flask import Flask, request, jsonify, render_template, send_file
|
|
import json
|
|
import os
|
|
from datetime import datetime
|
|
|
|
app = Flask(__name__)
|
|
|
|
class JSONFormatter:
|
|
"""JSON格式化工具类"""
|
|
|
|
@staticmethod
|
|
def format_standard(data, indent=2):
|
|
"""标准格式化 - 带缩进的可读格式"""
|
|
return json.dumps(data, ensure_ascii=False, indent=indent)
|
|
|
|
@staticmethod
|
|
def minify(data):
|
|
"""最小化 - 压缩去除空格"""
|
|
return json.dumps(data, ensure_ascii=False, separators=(',', ':'))
|
|
|
|
@staticmethod
|
|
def one_line_per_object(data):
|
|
"""一行化 - 每个对象/元素占一行"""
|
|
if isinstance(data, list):
|
|
# 如果是数组,每个元素占一行
|
|
lines = ['[']
|
|
for i, item in enumerate(data):
|
|
comma = ',' if i < len(data) - 1 else ''
|
|
lines.append(f' {json.dumps(item, ensure_ascii=False)}{comma}')
|
|
lines.append(']')
|
|
return '\n'.join(lines)
|
|
|
|
elif isinstance(data, dict):
|
|
# 如果是对象,每个键值对占一行
|
|
lines = ['{']
|
|
keys = list(data.keys())
|
|
for i, key in enumerate(keys):
|
|
comma = ',' if i < len(keys) - 1 else ''
|
|
value_str = json.dumps(data[key], ensure_ascii=False)
|
|
lines.append(f' {json.dumps(key, ensure_ascii=False)}: {value_str}{comma}')
|
|
lines.append('}')
|
|
return '\n'.join(lines)
|
|
|
|
else:
|
|
# 基本类型直接返回
|
|
return json.dumps(data, ensure_ascii=False)
|
|
|
|
@app.route('/')
|
|
def index():
|
|
"""主页"""
|
|
return render_template('json_editor.html')
|
|
|
|
@app.route('/api/format', methods=['POST'])
|
|
def format_json():
|
|
"""JSON格式化API"""
|
|
try:
|
|
data = request.get_json()
|
|
content = data.get('content', '')
|
|
format_type = data.get('format_type', 'standard') # standard, minify, oneline
|
|
|
|
if not content.strip():
|
|
return jsonify({'success': False, 'message': '请提供JSON内容'})
|
|
|
|
# 解析JSON
|
|
try:
|
|
json_data = json.loads(content)
|
|
except json.JSONDecodeError as e:
|
|
return jsonify({'success': False, 'message': f'JSON格式错误: {str(e)}'})
|
|
|
|
# 根据类型格式化
|
|
formatter = JSONFormatter()
|
|
|
|
if format_type == 'standard':
|
|
formatted = formatter.format_standard(json_data)
|
|
message = 'JSON标准格式化完成'
|
|
elif format_type == 'minify':
|
|
formatted = formatter.minify(json_data)
|
|
message = 'JSON最小化完成'
|
|
elif format_type == 'oneline':
|
|
formatted = formatter.one_line_per_object(json_data)
|
|
message = 'JSON一行化格式完成'
|
|
else:
|
|
return jsonify({'success': False, 'message': '不支持的格式化类型'})
|
|
|
|
return jsonify({
|
|
'success': True,
|
|
'message': message,
|
|
'formatted': formatted,
|
|
'original_length': len(content),
|
|
'formatted_length': len(formatted)
|
|
})
|
|
|
|
except Exception as e:
|
|
return jsonify({'success': False, 'message': f'处理错误: {str(e)}'})
|
|
|
|
@app.route('/api/batch_add', methods=['POST'])
|
|
def batch_add_property():
|
|
"""批量添加属性API"""
|
|
try:
|
|
data = request.get_json()
|
|
content = data.get('content', '')
|
|
key_name = data.get('key_name', '')
|
|
key_value = data.get('key_value', '')
|
|
|
|
if not content.strip():
|
|
return jsonify({'success': False, 'message': '请提供JSON内容'})
|
|
|
|
if not key_name.strip():
|
|
return jsonify({'success': False, 'message': '请提供键名'})
|
|
|
|
# 解析JSON
|
|
try:
|
|
json_data = json.loads(content)
|
|
except json.JSONDecodeError as e:
|
|
return jsonify({'success': False, 'message': f'JSON格式错误: {str(e)}'})
|
|
|
|
# 智能解析键值
|
|
parsed_value = parse_value(key_value)
|
|
|
|
# 批量添加属性
|
|
count = add_property_to_all_objects(json_data, key_name, parsed_value)
|
|
|
|
# 格式化输出
|
|
formatted = JSONFormatter.format_standard(json_data)
|
|
|
|
return jsonify({
|
|
'success': True,
|
|
'message': f'成功为 {count} 个对象添加了属性 "{key_name}": {json.dumps(parsed_value, ensure_ascii=False)}',
|
|
'formatted': formatted,
|
|
'count': count
|
|
})
|
|
|
|
except Exception as e:
|
|
return jsonify({'success': False, 'message': f'处理错误: {str(e)}'})
|
|
|
|
def parse_value(value_str):
|
|
"""智能解析值的类型"""
|
|
if value_str == '':
|
|
return ''
|
|
|
|
# null
|
|
if value_str.lower() == 'null':
|
|
return None
|
|
|
|
# boolean
|
|
if value_str.lower() == 'true':
|
|
return True
|
|
if value_str.lower() == 'false':
|
|
return False
|
|
|
|
# number
|
|
try:
|
|
if '.' in value_str:
|
|
return float(value_str)
|
|
else:
|
|
return int(value_str)
|
|
except ValueError:
|
|
pass
|
|
|
|
# JSON object or array
|
|
if (value_str.startswith('{') and value_str.endswith('}')) or \
|
|
(value_str.startswith('[') and value_str.endswith(']')):
|
|
try:
|
|
return json.loads(value_str)
|
|
except json.JSONDecodeError:
|
|
pass
|
|
|
|
# string
|
|
return value_str
|
|
|
|
def add_property_to_all_objects(obj, key, value):
|
|
"""递归为所有对象添加属性"""
|
|
count = 0
|
|
|
|
def traverse(current):
|
|
nonlocal count
|
|
if isinstance(current, dict):
|
|
current[key] = value
|
|
count += 1
|
|
# 继续递归处理嵌套对象
|
|
for val in current.values():
|
|
if isinstance(val, (dict, list)) and val != current:
|
|
traverse(val)
|
|
elif isinstance(current, list):
|
|
for item in current:
|
|
traverse(item)
|
|
|
|
traverse(obj)
|
|
return count
|
|
|
|
@app.route('/api/validate', methods=['POST'])
|
|
def validate_json():
|
|
"""JSON验证API"""
|
|
try:
|
|
data = request.get_json()
|
|
content = data.get('content', '')
|
|
|
|
if not content.strip():
|
|
return jsonify({'success': False, 'message': '请提供JSON内容'})
|
|
|
|
try:
|
|
json_data = json.loads(content)
|
|
return jsonify({
|
|
'success': True,
|
|
'message': 'JSON格式正确 ✓',
|
|
'valid': True
|
|
})
|
|
except json.JSONDecodeError as e:
|
|
return jsonify({
|
|
'success': False,
|
|
'message': f'JSON格式错误: {str(e)}',
|
|
'valid': False,
|
|
'error': str(e)
|
|
})
|
|
|
|
except Exception as e:
|
|
return jsonify({'success': False, 'message': f'验证错误: {str(e)}'})
|
|
|
|
@app.route('/api/download', methods=['POST'])
|
|
def download_json():
|
|
"""下载JSON文件"""
|
|
try:
|
|
data = request.get_json()
|
|
content = data.get('content', '')
|
|
format_type = data.get('format_type', 'standard')
|
|
|
|
if not content.strip():
|
|
return jsonify({'success': False, 'message': '没有可下载的内容'})
|
|
|
|
# 验证JSON格式
|
|
try:
|
|
json_data = json.loads(content)
|
|
except json.JSONDecodeError as e:
|
|
return jsonify({'success': False, 'message': f'JSON格式错误: {str(e)}'})
|
|
|
|
# 格式化
|
|
formatter = JSONFormatter()
|
|
if format_type == 'minify':
|
|
formatted_content = formatter.minify(json_data)
|
|
elif format_type == 'oneline':
|
|
formatted_content = formatter.one_line_per_object(json_data)
|
|
else:
|
|
formatted_content = formatter.format_standard(json_data)
|
|
|
|
# 生成文件名
|
|
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
|
|
filename = f"edited_json_{format_type}_{timestamp}.json"
|
|
|
|
# 创建临时文件
|
|
temp_file = f"temp_{filename}"
|
|
with open(temp_file, 'w', encoding='utf-8') as f:
|
|
f.write(formatted_content)
|
|
|
|
return send_file(temp_file, as_attachment=True, download_name=filename)
|
|
|
|
except Exception as e:
|
|
return jsonify({'success': False, 'message': f'下载错误: {str(e)}'})
|
|
|
|
if __name__ == '__main__':
|
|
# 确保templates目录存在
|
|
os.makedirs('templates', exist_ok=True)
|
|
|
|
# 运行应用
|
|
app.run(debug=True, host='0.0.0.0', port=5000)
|