Press "Enter" to skip to content

json数据解析助手

同事有处理json数据的需求,偶尔会希望能直观的从json数据里面提取想要的数据导出成表格,简单用AI撸了个小助手。

预览地址:JSON转表格解析助手

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>JSON转表格解析助手</title>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
            font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
        }

        body {
            background-color: #f5f7fa;
            padding: 20px;
            color: #2c3e50;
        }

        .container {
            max-width: 1400px;
            margin: 0 auto;
            background: white;
            padding: 20px;
            border-radius: 8px;
            box-shadow: 0 2px 4px rgba(0,0,0,0.1);
        }

        .header {
            text-align: center;
            margin-bottom: 30px;
            padding-bottom: 20px;
            border-bottom: 2px solid #e1e8ed;
        }

        .header h1 {
            color: #1a73e8;
            margin-bottom: 10px;
        }

        .header p {
            color: #666;
            font-size: 14px;
        }

        .input-section {
            margin-bottom: 30px;
        }

        .section-title {
            font-size: 16px;
            font-weight: 600;
            color: #1a73e8;
            margin-bottom: 15px;
        }

        .json-input {
            width: 100%;
            height: 200px;
            padding: 15px;
            border: 1px solid #ddd;
            border-radius: 6px;
            font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
            font-size: 13px;
            line-height: 1.4;
            resize: vertical;
            background-color: #f8f9fa;
        }

        .json-input:focus {
            outline: none;
            border-color: #1a73e8;
            box-shadow: 0 0 0 2px rgba(26, 115, 232, 0.2);
        }

        .controls {
            margin: 15px 0;
            display: flex;
            gap: 15px;
            align-items: center;
        }

        .btn {
            background-color: #1a73e8;
            color: white;
            border: none;
            padding: 10px 20px;
            border-radius: 6px;
            cursor: pointer;
            font-size: 14px;
            transition: background-color 0.3s;
        }

        .btn:hover {
            background-color: #1557b0;
        }

        .btn:disabled {
            background-color: #ccc;
            cursor: not-allowed;
        }

        .btn-secondary {
            background-color: #6c757d;
        }

        .btn-secondary:hover {
            background-color: #545b62;
        }

        .btn-export {
            background-color: #28a745;
        }

        .btn-export:hover {
            background-color: #218838;
        }

        .result-section {
            margin-top: 30px;
        }

        .table-container {
            max-height: 600px;
            overflow: auto;
            border: 1px solid #ddd;
            border-radius: 6px;
            background: white;
        }

        .data-table {
            width: 100%;
            border-collapse: collapse;
            font-size: 13px;
        }

        .data-table th {
            background-color: #f8f9fa;
            color: #495057;
            font-weight: 600;
            padding: 12px 8px;
            text-align: left;
            border-bottom: 2px solid #dee2e6;
            position: sticky;
            top: 0;
            z-index: 10;
        }

        .data-table td {
            padding: 10px 8px;
            border-bottom: 1px solid #dee2e6;
            vertical-align: top;
            word-break: break-word;
            max-width: 300px;
        }

        .data-table tbody tr:hover {
            background-color: #f8f9fa;
        }

        .data-table tbody tr:nth-child(even) {
            background-color: #fdfdfd;
        }

        .error-message {
            color: #dc3545;
            background-color: #f8d7da;
            border: 1px solid #f5c6cb;
            border-radius: 4px;
            padding: 12px;
            margin: 15px 0;
        }

        .success-message {
            color: #155724;
            background-color: #d4edda;
            border: 1px solid #c3e6cb;
            border-radius: 4px;
            padding: 12px;
            margin: 15px 0;
        }

        .info-message {
            color: #0c5460;
            background-color: #d1ecf1;
            border: 1px solid #bee5eb;
            border-radius: 4px;
            padding: 12px;
            margin: 15px 0;
        }

        .stats {
            margin: 15px 0;
            padding: 10px;
            background-color: #e7f3ff;
            border-radius: 4px;
            font-size: 14px;
        }

        .example-section {
            margin-top: 20px;
            padding: 15px;
            background-color: #f8f9fa;
            border-radius: 6px;
            border-left: 4px solid #1a73e8;
        }

        .example-title {
            font-weight: 600;
            margin-bottom: 10px;
            color: #1a73e8;
        }

        .example-json {
            background-color: #2d3748;
            color: #e2e8f0;
            padding: 10px;
            border-radius: 4px;
            font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
            font-size: 12px;
            overflow-x: auto;
            margin: 10px 0;
        }

        .example-btn {
            background-color: #17a2b8;
            color: white;
            border: none;
            padding: 6px 12px;
            border-radius: 4px;
            cursor: pointer;
            font-size: 12px;
            margin-right: 10px;
        }

        .example-btn:hover {
            background-color: #138496;
        }

        .virtual-fields-section {
            margin: 20px 0;
            padding: 15px;
            background-color: #f8f9fa;
            border-radius: 6px;
            border-left: 4px solid #28a745;
        }

        .virtual-field-item {
            display: flex;
            align-items: center;
            gap: 10px;
            margin-bottom: 10px;
            padding: 8px;
            background-color: white;
            border-radius: 4px;
            border: 1px solid #ddd;
        }

        .virtual-field-input {
            flex: 1;
            padding: 6px 8px;
            border: 1px solid #ccc;
            border-radius: 3px;
            font-size: 13px;
        }

        .virtual-field-input.field-name {
            max-width: 150px;
        }

        .virtual-field-input.field-expression {
            font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
        }

        .btn-small {
            padding: 4px 8px;
            font-size: 12px;
            border-radius: 3px;
        }

        .btn-danger {
            background-color: #dc3545;
            color: white;
            border: none;
            cursor: pointer;
        }

        .btn-danger:hover {
            background-color: #c82333;
        }

        .btn-success {
            background-color: #28a745;
            color: white;
            border: none;
            cursor: pointer;
        }

        .btn-success:hover {
            background-color: #218838;
        }

        .expression-help {
            font-size: 12px;
            color: #666;
            margin-top: 10px;
            padding: 8px;
            background-color: #e9ecef;
            border-radius: 3px;
        }

        .expression-help code {
            background-color: #f8f9fa;
            padding: 2px 4px;
            border-radius: 2px;
            font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
        }
    </style>
</head>
<body>
    <div class="container">
        <div class="header">
            <h1>JSON转表格解析助手</h1>
            <p>智能解析JSON数据并转换为表格展示,支持数组对象和嵌套对象中的数组数据</p>
        </div>

        <div class="input-section">
            <div class="section-title">输入JSON数据</div>
            <textarea id="jsonInput" class="json-input" placeholder="请粘贴您的JSON数据...&#10;&#10;支持两种格式:&#10;1. 直接数组格式: [{&quot;name&quot;: &quot;张三&quot;, &quot;age&quot;: 25}, {&quot;name&quot;: &quot;李四&quot;, &quot;age&quot;: 30}]&#10;2. 嵌套对象格式: {&quot;data&quot;: [{&quot;name&quot;: &quot;张三&quot;, &quot;age&quot;: 25}], &quot;total&quot;: 1}"></textarea>
            
            <div class="controls">
                <button class="btn" onclick="parseJSON()">解析JSON</button>
                <button class="btn btn-secondary" onclick="clearAll()">清空</button>
                <button class="btn btn-export" onclick="exportToCSV()" id="exportBtn" style="display: none;">导出CSV</button>
            </div>
        </div>

        <div class="virtual-fields-section">
            <div class="section-title">虚拟字段配置</div>
            <p style="margin-bottom: 15px; font-size: 14px; color: #666;">
                通过JSON路径表达式提取复杂对象或数组中的特定值,创建虚拟字段在表格中显示
            </p>
            
            <div id="virtualFieldsList">
                <!-- 虚拟字段列表将在这里动态生成 -->
            </div>
            
            <div style="margin: 15px 0; display: flex; align-items: center; gap: 15px;">
                <button class="btn btn-success btn-small" onclick="addVirtualField()">+ 添加虚拟字段</button>
                <label style="display: flex; align-items: center; gap: 5px; cursor: pointer;">
                    <input type="checkbox" id="showOnlyVirtualFields" onchange="toggleVirtualFieldsOnly()" style="cursor: pointer;">
                    <span>只显示虚拟字段</span>
                </label>
            </div>
            
            <div class="expression-help">
                <strong>表达式语法示例:</strong><br>
                <code>$.user.name</code> - 获取user对象的name属性<br>
                <code>$.tags[0]</code> - 获取tags数组的第一个元素<br>
                <code>$.items.length</code> - 获取items数组的长度<br>
                <code>$.price.toFixed(2)</code> - 调用price的toFixed方法保留2位小数<br>
                <code>$.address?.city</code> - 安全访问(如果address不存在则返回空)
            </div>
        </div>

        <div class="example-section">
            <div class="example-title">示例数据</div>
            <p style="margin-bottom: 10px;">点击下方按钮可以快速填入示例数据进行测试:</p>
            
            <div style="margin-bottom: 15px;">
                <strong>示例1 - 直接数组格式:</strong>
                <button class="example-btn" onclick="loadExample1()">使用此示例</button>
                <div class="example-json">[
  {"姓名": "张三", "年龄": 25, "部门": "技术部", "薪资": 8000},
  {"姓名": "李四", "年龄": 30, "部门": "销售部", "薪资": 7000},
  {"姓名": "王五", "年龄": 28, "部门": "技术部", "薪资": 9000}
]</div>
            </div>

            <div>
                <strong>示例2 - 嵌套对象格式:</strong>
                <button class="example-btn" onclick="loadExample2()">使用此示例</button>
                <div class="example-json">{
  "code": 200,
  "message": "success",
  "data": {
    "users": [
      {"id": 1, "name": "Alice", "email": "alice@example.com", "status": "active"},
      {"id": 2, "name": "Bob", "email": "bob@example.com", "status": "inactive"},
      {"id": 3, "name": "Charlie", "email": "charlie@example.com", "status": "active"}
    ],
    "total": 3
  }
}</div>
            </div>
        </div>

        <div class="result-section">
            <div class="section-title">解析结果</div>
            <div id="resultContainer">
                <div class="info-message">
                    请在上方输入JSON数据并点击"解析JSON"按钮开始解析
                </div>
            </div>
        </div>
    </div>

    <script>
        let currentData = null;
        let virtualFields = [];

        function parseJSON() {
            const input = document.getElementById('jsonInput').value.trim();
            const resultContainer = document.getElementById('resultContainer');
            
            if (!input) {
                resultContainer.innerHTML = '<div class="error-message">请输入JSON数据</div>';
                return;
            }

            try {
                const data = JSON.parse(input);
                const tableData = extractTableData(data);
                
                if (tableData && tableData.length > 0) {
                    currentData = tableData;
                    displayTable(tableData, resultContainer);
                    document.getElementById('exportBtn').style.display = 'inline-block';
                } else {
                    resultContainer.innerHTML = '<div class="error-message">未找到可解析的数组数据</div>';
                    document.getElementById('exportBtn').style.display = 'none';
                }
            } catch (error) {
                resultContainer.innerHTML = `<div class="error-message">JSON解析错误: ${error.message}</div>`;
                document.getElementById('exportBtn').style.display = 'none';
            }
        }

        function extractTableData(data) {
            // 情况1: 直接是数组
            if (Array.isArray(data)) {
                return data;
            }
            
            // 情况2: 对象中包含数组
            if (typeof data === 'object' && data !== null) {
                // 广度优先搜索找到第一个数组
                const queue = [data];
                const visited = new Set();
                
                while (queue.length > 0) {
                    const current = queue.shift();
                    
                    if (visited.has(current)) continue;
                    visited.add(current);
                    
                    for (const key in current) {
                        if (current.hasOwnProperty(key)) {
                            const value = current[key];
                            
                            // 找到数组且数组不为空
                            if (Array.isArray(value) && value.length > 0) {
                                // 检查数组第一个元素是否为对象
                                if (typeof value[0] === 'object' && value[0] !== null) {
                                    return value;
                                }
                            }
                            
                            // 继续搜索嵌套对象
                            if (typeof value === 'object' && value !== null && !Array.isArray(value)) {
                                queue.push(value);
                            }
                        }
                    }
                }
            }
            
            return null;
        }

                 function displayTable(data, container) {
             if (!data || data.length === 0) {
                 container.innerHTML = '<div class="error-message">没有数据可显示</div>';
                 return;
             }

             // 获取所有原始列名
             const originalColumns = new Set();
             data.forEach(item => {
                 if (typeof item === 'object' && item !== null) {
                     Object.keys(item).forEach(key => originalColumns.add(key));
                 }
             });
             
             const originalColumnArray = Array.from(originalColumns);
             
             // 添加虚拟字段列名
             const virtualColumnNames = virtualFields.map(vf => vf.name).filter(name => name.trim());
             
             // 检查是否只显示虚拟字段
             const showOnlyVirtual = document.getElementById('showOnlyVirtualFields')?.checked || false;
             const allColumns = showOnlyVirtual ? virtualColumnNames : [...originalColumnArray, ...virtualColumnNames];
             
             if (allColumns.length === 0) {
                 if (showOnlyVirtual) {
                     container.innerHTML = '<div class="error-message">没有配置虚拟字段,请先添加虚拟字段或取消"只显示虚拟字段"选项</div>';
                 } else {
                     container.innerHTML = '<div class="error-message">数据格式不正确,无法生成表格</div>';
                 }
                 return;
             }

             // 生成表格HTML
             const virtualFieldsCount = virtualFields.length;
             let statsText;
             if (showOnlyVirtual) {
                 statsText = `解析成功!找到 ${data.length} 条记录,显示 ${virtualColumnNames.length} 个虚拟字段(已隐藏 ${originalColumnArray.length} 个原始字段)`;
             } else if (virtualFieldsCount > 0) {
                 statsText = `解析成功!找到 ${data.length} 条记录,${originalColumnArray.length} 个原始字段,${virtualFieldsCount} 个虚拟字段`;
             } else {
                 statsText = `解析成功!找到 ${data.length} 条记录,${originalColumnArray.length} 个字段`;
             }
                 
             let tableHTML = `
                 <div class="stats">
                     ${statsText}
                 </div>
                 <div class="table-container">
                     <table class="data-table">
                         <thead>
                             <tr>
                                 ${allColumns.map(col => {
                                     const isVirtual = virtualColumnNames.includes(col);
                                     return `<th ${isVirtual ? 'style="background-color: #e8f5e8; color: #2d7a2d;"' : ''}>${escapeHtml(col)}${isVirtual ? ' 🔧' : ''}</th>`;
                                 }).join('')}
                             </tr>
                         </thead>
                         <tbody>
             `;

             data.forEach((item, index) => {
                 tableHTML += '<tr>';
                 
                 if (showOnlyVirtual) {
                     // 只显示虚拟字段
                     virtualFields.forEach(vf => {
                         if (vf.name.trim()) {
                             const virtualValue = evaluateExpression(vf.expression, item);
                             tableHTML += `<td style="background-color: #f8fff8;">${escapeHtml(String(virtualValue))}</td>`;
                         }
                     });
                 } else {
                     // 显示原始字段
                     originalColumnArray.forEach(col => {
                         let cellValue = item[col];
                         if (cellValue === null || cellValue === undefined) {
                             cellValue = '';
                         } else if (typeof cellValue === 'object') {
                             cellValue = JSON.stringify(cellValue);
                         } else {
                             cellValue = String(cellValue);
                         }
                         tableHTML += `<td>${escapeHtml(cellValue)}</td>`;
                     });
                     
                     // 显示虚拟字段
                     virtualFields.forEach(vf => {
                         if (vf.name.trim()) {
                             const virtualValue = evaluateExpression(vf.expression, item);
                             tableHTML += `<td style="background-color: #f8fff8;">${escapeHtml(String(virtualValue))}</td>`;
                         }
                     });
                 }
                 
                 tableHTML += '</tr>';
             });

             tableHTML += `
                         </tbody>
                     </table>
                 </div>
             `;

             container.innerHTML = tableHTML;
         }

        function escapeHtml(text) {
            const div = document.createElement('div');
            div.textContent = text;
            return div.innerHTML;
        }

                 function clearAll() {
             document.getElementById('jsonInput').value = '';
             document.getElementById('resultContainer').innerHTML = '<div class="info-message">请在上方输入JSON数据并点击"解析JSON"按钮开始解析</div>';
             document.getElementById('exportBtn').style.display = 'none';
             document.getElementById('showOnlyVirtualFields').checked = false;
             currentData = null;
             virtualFields = [];
             renderVirtualFields();
         }

        function exportToCSV() {
            if (!currentData || currentData.length === 0) {
                alert('没有数据可导出');
                return;
            }

                         // 获取所有原始列名
             const originalColumns = new Set();
             currentData.forEach(item => {
                 if (typeof item === 'object' && item !== null) {
                     Object.keys(item).forEach(key => originalColumns.add(key));
                 }
             });
             
             const originalColumnArray = Array.from(originalColumns);
             
             // 添加虚拟字段列名
             const virtualColumnNames = virtualFields.map(vf => vf.name).filter(name => name.trim());
             
             // 检查是否只显示虚拟字段
             const showOnlyVirtual = document.getElementById('showOnlyVirtualFields')?.checked || false;
             const allColumns = showOnlyVirtual ? virtualColumnNames : [...originalColumnArray, ...virtualColumnNames];
            
                         // 生成CSV内容
             let csvContent = allColumns.join(',') + '\n';
             
             currentData.forEach(item => {
                 const row = allColumns.map(col => {
                     let value;
                     
                     // 检查是否为虚拟字段
                     if (virtualColumnNames.includes(col)) {
                         const virtualField = virtualFields.find(vf => vf.name === col);
                         value = virtualField ? evaluateExpression(virtualField.expression, item) : '';
                     } else {
                         value = item[col];
                     }
                     
                     if (value === null || value === undefined) {
                         value = '';
                     } else if (typeof value === 'object') {
                         value = JSON.stringify(value);
                     } else {
                         value = String(value);
                     }
                     
                     // 处理包含逗号、引号或换行符的值
                     if (value.includes(',') || value.includes('"') || value.includes('\n')) {
                         value = '"' + value.replace(/"/g, '""') + '"';
                     }
                     
                     return value;
                 }).join(',');
                 
                 csvContent += row + '\n';
             });

            // 创建并下载文件
            const blob = new Blob(['\uFEFF' + csvContent], { type: 'text/csv;charset=utf-8;' });
            const url = URL.createObjectURL(blob);
            const link = document.createElement('a');
            link.setAttribute('href', url);
            
            const now = new Date();
            const fileName = `json_data_${now.getFullYear()}${(now.getMonth()+1).toString().padStart(2, '0')}${now.getDate().toString().padStart(2, '0')}_${now.getHours().toString().padStart(2, '0')}${now.getMinutes().toString().padStart(2, '0')}.csv`;
            
            link.setAttribute('download', fileName);
            link.style.display = 'none';
            document.body.appendChild(link);
            link.click();
            document.body.removeChild(link);
        }

        function loadExample1() {
            const example1 = `[
  {"姓名": "张三", "年龄": 25, "部门": "技术部", "薪资": 8000},
  {"姓名": "李四", "年龄": 30, "部门": "销售部", "薪资": 7000},
  {"姓名": "王五", "年龄": 28, "部门": "技术部", "薪资": 9000}
]`;
            document.getElementById('jsonInput').value = example1;
        }

                 function loadExample2() {
             const example2 = `{
   "code": 200,
   "message": "success",
   "data": {
     "users": [
       {
         "id": 1, 
         "profile": {"name": "Alice", "age": 28}, 
         "contact": {"email": "alice@example.com", "phone": "123-456-7890"}, 
         "tags": ["developer", "team-lead"],
         "score": 95.5,
         "address": {"city": "北京", "district": "朝阳区"}
       },
       {
         "id": 2, 
         "profile": {"name": "Bob", "age": 32}, 
         "contact": {"email": "bob@example.com"}, 
         "tags": ["designer"],
         "score": 87.2,
         "address": {"city": "上海", "district": "浦东新区"}
       },
       {
         "id": 3, 
         "profile": {"name": "Charlie", "age": 25}, 
         "contact": {"email": "charlie@example.com", "phone": "098-765-4321"}, 
         "tags": ["developer", "junior"],
         "score": 92.8
       }
     ],
     "total": 3
   }
 }`;
             document.getElementById('jsonInput').value = example2;
             
             // 添加一些示例虚拟字段
             virtualFields = [
                 {id: Date.now() + 1, name: "姓名", expression: "$.profile.name"},
                 {id: Date.now() + 2, name: "年龄", expression: "$.profile.age"},
                 {id: Date.now() + 3, name: "邮箱", expression: "$.contact.email"},
                 {id: Date.now() + 4, name: "主要标签", expression: "$.tags[0]"},
                 {id: Date.now() + 5, name: "分数(保留1位小数)", expression: "$.score.toFixed(1)"},
                 {id: Date.now() + 6, name: "城市", expression: "$.address?.city"}
             ];
             renderVirtualFields();
         }

                 // 虚拟字段管理功能
         function addVirtualField() {
             const fieldId = Date.now();
             virtualFields.push({
                 id: fieldId,
                 name: '',
                 expression: ''
             });
             renderVirtualFields();
         }

         function removeVirtualField(fieldId) {
             virtualFields = virtualFields.filter(vf => vf.id !== fieldId);
             renderVirtualFields();
             // 如果有数据,重新渲染表格
             if (currentData) {
                 displayTable(currentData, document.getElementById('resultContainer'));
             }
         }

         function updateVirtualField(fieldId, property, value) {
             const field = virtualFields.find(vf => vf.id === fieldId);
             if (field) {
                 field[property] = value;
                 // 如果有数据且字段名不为空,自动重新渲染表格
                 if (currentData && field.name.trim() && field.expression.trim()) {
                     displayTable(currentData, document.getElementById('resultContainer'));
                 }
             }
         }

         function renderVirtualFields() {
             const container = document.getElementById('virtualFieldsList');
             if (virtualFields.length === 0) {
                 container.innerHTML = '<div style="color: #666; font-style: italic;">暂无虚拟字段,点击下方按钮添加</div>';
                 return;
             }

             container.innerHTML = virtualFields.map(vf => `
                 <div class="virtual-field-item">
                     <input type="text" class="virtual-field-input field-name" 
                            placeholder="字段名称" 
                            value="${escapeHtml(vf.name)}"
                            oninput="updateVirtualField(${vf.id}, 'name', this.value)">
                     <input type="text" class="virtual-field-input field-expression" 
                            placeholder="JSON路径表达式,如:$.user.name" 
                            value="${escapeHtml(vf.expression)}"
                            oninput="updateVirtualField(${vf.id}, 'expression', this.value)">
                     <button class="btn btn-danger btn-small" onclick="removeVirtualField(${vf.id})">删除</button>
                 </div>
             `).join('');
         }

         // JSON路径表达式评估器
         function evaluateExpression(expression, data) {
             try {
                 if (!expression || !expression.trim()) {
                     return '';
                 }

                 // 简单的JSON路径表达式解析
                 let result = data;
                 let path = expression.trim();

                 // 移除开头的$符号
                 if (path.startsWith('$.')) {
                     path = path.substring(2);
                 } else if (path.startsWith('$')) {
                     path = path.substring(1);
                 }

                 if (!path) {
                     return data;
                 }

                 // 分割路径
                 const parts = path.split('.');
                 
                 for (let i = 0; i < parts.length; i++) {
                     let part = parts[i];
                     
                     if (!part) continue;
                     
                     // 处理数组索引,如 tags[0]
                     const arrayMatch = part.match(/^(.+)\[(\d+)\]$/);
                     if (arrayMatch) {
                         const [, arrayName, index] = arrayMatch;
                         result = result?.[arrayName];
                         if (Array.isArray(result) && index < result.length) {
                             result = result[parseInt(index)];
                         } else {
                             return '';
                         }
                     }
                     // 处理方法调用,如 length, toFixed(2)
                     else if (part.includes('(') && part.includes(')')) {
                         const methodMatch = part.match(/^(.+)\((.*)\)$/);
                         if (methodMatch) {
                             const [, methodName, argsStr] = methodMatch;
                             
                             if (methodName === 'length' && Array.isArray(result)) {
                                 result = result.length;
                             } else if (methodName === 'toFixed' && typeof result === 'number') {
                                 const digits = parseInt(argsStr) || 0;
                                 result = result.toFixed(digits);
                             } else if (methodName === 'toString') {
                                 result = String(result);
                             } else if (methodName === 'join' && Array.isArray(result)) {
                                 const separator = argsStr.replace(/['"]/g, '') || ',';
                                 result = result.join(separator);
                             } else {
                                 // 尝试调用其他方法
                                 if (result && typeof result[methodName] === 'function') {
                                     const args = argsStr ? argsStr.split(',').map(arg => {
                                         arg = arg.trim();
                                         if (arg.startsWith('"') && arg.endsWith('"')) {
                                             return arg.slice(1, -1);
                                         }
                                         if (arg.startsWith("'") && arg.endsWith("'")) {
                                             return arg.slice(1, -1);
                                         }
                                         return isNaN(arg) ? arg : Number(arg);
                                     }) : [];
                                     result = result[methodName](...args);
                                 } else {
                                     return '';
                                 }
                             }
                         }
                     }
                     // 处理安全访问,如 address?.city
                     else if (part.includes('?')) {
                         const [safeProp] = part.split('?');
                         result = result?.[safeProp];
                     }
                     // 普通属性访问
                     else {
                         result = result?.[part];
                     }
                     
                     if (result === undefined || result === null) {
                         return '';
                     }
                 }

                 return result;
             } catch (error) {
                 console.warn('表达式评估错误:', expression, error);
                 return '';
             }
         }

         // 切换虚拟字段显示模式
         function toggleVirtualFieldsOnly() {
             if (currentData) {
                 displayTable(currentData, document.getElementById('resultContainer'));
             }
         }

         // 页面加载时的初始化
         document.addEventListener('DOMContentLoaded', function() {
             renderVirtualFields();
         });
    </script>
</body>
</html> 
发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注