← ToolBox
/ Plist 解析器
🌙
🍎 Plist 解析器
Apple plist XML 解析:将 plist 转换为 JSON,支持 dict/array/string/integer/real/boolean/date/data。
Plist → JSON
JSON → Plist
美化
压缩
复制
清空
示例
输出
等待转换...
已复制
const SAMPLE = '\n\n
\n
\n
name
Alice
\n
age
30
\n
active
\n
tags
\n
\n
admin
\n
user
\n
\n
address
\n
\n
city
SH
\n
\n
\n
'; function plistNode(node){ switch(node.tagName){ case 'dict': { const obj = {}; let k = null; for(const c of node.children){ if(c.tagName === 'key') k = c.textContent; else if(k !== null){ obj[k] = plistNode(c); k = null; } } return obj; } case 'array': return Array.from(node.children).map(plistNode); case 'string': return node.textContent; case 'integer': return parseInt(node.textContent); case 'real': return parseFloat(node.textContent); case 'true': case 'True': return true; case 'false': case 'False': return false; case 'date': return node.textContent; case 'data': return node.textContent; default: return node.textContent; } } function toPlistNode(v, indent){ const pad = ' '.repeat(indent); if(v === null) return pad + '
'; if(typeof v === 'boolean') return pad + '<' + v + '/>'; if(typeof v === 'number') return pad + (Number.isInteger(v) ? '
' + v + '
' : '
' + v + '
'); if(typeof v === 'string') return pad + '
' + escapeXml(v) + '
'; if(Array.isArray(v)) return pad + '
\n' + v.map(x => toPlistNode(x, indent + 1)).join('\n') + '\n' + pad + '
'; if(typeof v === 'object'){ const keys = Object.keys(v); if(keys.length === 0) return pad + '
'; return pad + '
\n' + keys.map(k => pad + '
' + escapeXml(k) + '
\n' + toPlistNode(v[k], indent + 1)).join('\n') + '\n' + pad + '
'; } return pad + '
' + escapeXml(String(v)) + '
'; } function escapeXml(s){ return String(s).replace(/&/g,'&').replace(//g,'>'); } function plistToJson(){ setErr(''); try{ const doc = new DOMParser().parseFromString(document.getElementById('input').value, 'application/xml'); if(doc.getElementsByTagName('parsererror').length) throw new Error('XML 解析错误'); const plist = doc.querySelector('plist'); const root = plist.firstElementChild; setOut(JSON.stringify(plistNode(root), null, 2)); setErr('✅ 解析成功'); }catch(e){ setErr('❌ ' + e.message); } } function jsonToPlist(){ setErr(''); try{ const data = JSON.parse(document.getElementById('input').value); setOut('\n\n
\n' + toPlistNode(data, 0) + '\n
'); setErr('✅ 转换成功'); }catch(e){ setErr('❌ ' + e.message); } } function doBeautify(){ plistToJson(); } function doMinify(){ setErr(''); try{ const data = JSON.parse(document.getElementById('input').value); const out = '
' + toPlistNode(data, 0) + '
'; setOut(out); setErr('✅ 压缩成功'); }catch(e){ setErr('❌ ' + e.message); } } function loadSample(){document.getElementById('input').value = SAMPLE; plistToJson();} function setOut(s){document.getElementById('output').textContent = s;} function setErr(s){const e = document.getElementById('err'); e.textContent = s || ''; e.className = 'err' + (s && s.startsWith('✅') ? ' ok' : '');} function clearAll(){document.getElementById('input').value = ''; setOut('等待转换...'); setErr('');} function getIndent(){const v=document.getElementById('indent').value;return v==='tab'?'\t':' '.repeat(parseInt(v));} function setOut(s){document.getElementById('output').textContent=s;} function setErr(s){const e=document.getElementById('err');e.textContent=s||'';e.className='err'+(s?'':' ok');} function clearAll(){document.getElementById('input').value='';setOut('等待输入...');setErr('');} function loadSample(){document.getElementById('input').value=SAMPLE;doBeautify();}