320 lines
15 KiB
PHP
320 lines
15 KiB
PHP
<?php
|
||
$page_title = "Free Data Format Converter | JSON CSV XML | UK AI Automation";
|
||
$page_description = "Convert between JSON, CSV, and XML formats instantly. Free online tool for data transformation - no signup required.";
|
||
$canonical_url = "https://ukaiautomation.co.uk/tools/data-converter";
|
||
?>
|
||
<!DOCTYPE html>
|
||
<html lang="en">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title><?php echo htmlspecialchars($page_title); ?></title>
|
||
<meta name="description" content="<?php echo htmlspecialchars($page_description); ?>">
|
||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||
<link href="https://fonts.googleapis.com/css2?family=Roboto+Slab:wght@100;200;300;400;500;600;700;800;900&family=Lato:wght@100;200;300;400;500;600;700;800;900&display=swap" rel="stylesheet">
|
||
<link rel="canonical" href="<?php echo htmlspecialchars($canonical_url); ?>">
|
||
|
||
<meta property="og:title" content="<?php echo htmlspecialchars($page_title); ?>">
|
||
<meta property="og:description" content="<?php echo htmlspecialchars($page_description); ?>">
|
||
|
||
<link rel="stylesheet" href="../assets/css/main.css?v=20260222">
|
||
|
||
<script type="application/ld+json">
|
||
{
|
||
"@context": "https://schema.org",
|
||
"@type": "SoftwareApplication",
|
||
"name": "Data Format Converter",
|
||
"description": "Free tool to convert between JSON, CSV, and XML data formats",
|
||
"url": "https://ukaiautomation.co.uk/tools/data-converter",
|
||
"applicationCategory": "BusinessApplication",
|
||
"operatingSystem": "Web Browser",
|
||
"offers": { "@type": "Offer", "price": "0", "priceCurrency": "GBP" }
|
||
}
|
||
</script>
|
||
|
||
<style>
|
||
.converter-container { max-width: 1100px; margin: 0 auto; padding: 40px 20px; }
|
||
.converter-header { text-align: center; margin-bottom: 40px; }
|
||
.converter-header h1 { font-size: 2.2em; color: #1e1b4b; margin-bottom: 15px; }
|
||
.converter-header p { color: #666; font-size: 1.1em; }
|
||
.converter-card { background: #fff; border-radius: 12px; box-shadow: 0 4px 20px rgba(0,0,0,0.08); padding: 30px; }
|
||
.format-selector { display: flex; justify-content: center; gap: 15px; margin-bottom: 25px; flex-wrap: wrap; align-items: center; }
|
||
.format-btn { padding: 12px 24px; border: 2px solid #e0e0e0; border-radius: 8px; background: white; cursor: pointer; font-weight: 600; transition: all 0.2s; }
|
||
.format-btn:hover { border-color: #6d28d9; }
|
||
.format-btn.active { background: #6d28d9; color: white; border-color: #6d28d9; }
|
||
.arrow { font-size: 1.5em; color: #888; }
|
||
.editor-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 20px; }
|
||
@media (max-width: 768px) { .editor-grid { grid-template-columns: 1fr; } }
|
||
.editor-box { display: flex; flex-direction: column; }
|
||
.editor-box label { font-weight: 600; color: #1e1b4b; margin-bottom: 10px; display: flex; justify-content: space-between; align-items: center; }
|
||
.editor-box textarea { flex: 1; min-height: 350px; padding: 15px; border: 2px solid #e0e0e0; border-radius: 8px; font-family: 'Monaco', 'Menlo', monospace; font-size: 0.9em; resize: vertical; }
|
||
.editor-box textarea:focus { border-color: #6d28d9; outline: none; }
|
||
.btn-row { display: flex; justify-content: center; gap: 15px; margin: 25px 0; flex-wrap: wrap; }
|
||
.btn { padding: 14px 28px; border: none; border-radius: 8px; font-weight: 600; cursor: pointer; transition: all 0.2s; }
|
||
.btn-primary { background: #6d28d9; color: white; }
|
||
.btn-primary:hover { background: #148a72; }
|
||
.btn-secondary { background: #f5f5f5; color: #333; border: 2px solid #e0e0e0; }
|
||
.btn-secondary:hover { background: #e8e8e8; }
|
||
.copy-btn { padding: 6px 12px; font-size: 0.85em; background: #f0f0f0; border: none; border-radius: 4px; cursor: pointer; }
|
||
.copy-btn:hover { background: #e0e0e0; }
|
||
.error-msg { background: #ffebee; color: #c62828; padding: 12px; border-radius: 6px; margin-top: 15px; display: none; }
|
||
.success-msg { background: #e8f5e9; color: #2e7d32; padding: 12px; border-radius: 6px; margin-top: 15px; display: none; }
|
||
.breadcrumb { padding: 15px 20px; background: #f5f5f5; font-size: 0.9em; }
|
||
.breadcrumb a { color: #7c3aed; text-decoration: none; }
|
||
.breadcrumb span { color: #888; margin: 0 8px; }
|
||
.sample-data { font-size: 0.85em; color: #666; margin-top: 8px; }
|
||
.sample-data a { color: #6d28d9; cursor: pointer; text-decoration: underline; }
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<?php include($_SERVER["DOCUMENT_ROOT"] . "/includes/nav.php"); ?>
|
||
|
||
<nav class="breadcrumb">
|
||
<a href="/">Home</a> <span>›</span> <a href="/tools/">Tools</a> <span>›</span> Data Converter
|
||
</nav>
|
||
|
||
<div class="converter-container">
|
||
<div class="converter-header">
|
||
<h1>🔄 Data Format Converter</h1>
|
||
<p>Convert between JSON, CSV, and XML formats instantly. Your data stays in your browser.</p>
|
||
</div>
|
||
|
||
<div class="converter-card">
|
||
<div class="format-selector">
|
||
<div>
|
||
<strong>From:</strong>
|
||
<button class="format-btn active" data-format="json" onclick="setInputFormat('json')">JSON</button>
|
||
<button class="format-btn" data-format="csv" onclick="setInputFormat('csv')">CSV</button>
|
||
<button class="format-btn" data-format="xml" onclick="setInputFormat('xml')">XML</button>
|
||
</div>
|
||
<span class="arrow">→</span>
|
||
<div>
|
||
<strong>To:</strong>
|
||
<button class="format-btn" data-output="json" onclick="setOutputFormat('json')">JSON</button>
|
||
<button class="format-btn active" data-output="csv" onclick="setOutputFormat('csv')">CSV</button>
|
||
<button class="format-btn" data-output="xml" onclick="setOutputFormat('xml')">XML</button>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="editor-grid">
|
||
<div class="editor-box">
|
||
<label>
|
||
<span>📥 Input (<span id="inputFormatLabel">JSON</span>)</span>
|
||
<button class="copy-btn" onclick="clearInput()">Clear</button>
|
||
</label>
|
||
<textarea id="inputData" placeholder="Paste your data here..."></textarea>
|
||
<div class="sample-data">
|
||
Try sample: <a onclick="loadSample()">Load example data</a>
|
||
</div>
|
||
</div>
|
||
<div class="editor-box">
|
||
<label>
|
||
<span>📤 Output (<span id="outputFormatLabel">CSV</span>)</span>
|
||
<button class="copy-btn" onclick="copyOutput()">Copy</button>
|
||
</label>
|
||
<textarea id="outputData" readonly placeholder="Converted data will appear here..."></textarea>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="btn-row">
|
||
<button class="btn btn-primary" onclick="convert()">🔄 Convert</button>
|
||
<button class="btn btn-secondary" onclick="downloadOutput()">⬇️ Download</button>
|
||
</div>
|
||
|
||
<div id="errorMsg" class="error-msg"></div>
|
||
<div id="successMsg" class="success-msg"></div>
|
||
</div>
|
||
|
||
<div style="margin-top: 40px; padding: 30px; background: #f8f9fa; border-radius: 12px;">
|
||
<h3 style="color: #1e1b4b; margin-bottom: 15px;">💡 About This Tool</h3>
|
||
<p style="color: #666; line-height: 1.7;">
|
||
This free converter handles common data transformations needed when working with web scraped data:
|
||
</p>
|
||
<ul style="color: #666; margin-top: 15px; padding-left: 20px; line-height: 1.8;">
|
||
<li><strong>JSON → CSV</strong> — Perfect for opening scraped data in Excel or Google Sheets</li>
|
||
<li><strong>CSV → JSON</strong> — Convert spreadsheet data to API-friendly format</li>
|
||
<li><strong>XML → JSON/CSV</strong> — Transform legacy XML feeds into modern formats</li>
|
||
</ul>
|
||
<p style="color: #666; margin-top: 15px;">
|
||
<strong>Privacy:</strong> All conversions happen in your browser. Your data never leaves your device.
|
||
</p>
|
||
</div>
|
||
</div>
|
||
|
||
<?php include '../includes/footer.php'; ?>
|
||
|
||
<script>
|
||
let inputFormat = 'json';
|
||
let outputFormat = 'csv';
|
||
|
||
function setInputFormat(format) {
|
||
inputFormat = format;
|
||
document.querySelectorAll('[data-format]').forEach(b => b.classList.remove('active'));
|
||
document.querySelector(`[data-format="${format}"]`).classList.add('active');
|
||
document.getElementById('inputFormatLabel').textContent = format.toUpperCase();
|
||
}
|
||
|
||
function setOutputFormat(format) {
|
||
outputFormat = format;
|
||
document.querySelectorAll('[data-output]').forEach(b => b.classList.remove('active'));
|
||
document.querySelector(`[data-output="${format}"]`).classList.add('active');
|
||
document.getElementById('outputFormatLabel').textContent = format.toUpperCase();
|
||
}
|
||
|
||
function loadSample() {
|
||
const samples = {
|
||
json: `[
|
||
{"name": "Product A", "price": 29.99, "category": "Electronics"},
|
||
{"name": "Product B", "price": 49.99, "category": "Home"},
|
||
{"name": "Product C", "price": 19.99, "category": "Electronics"}
|
||
]`,
|
||
csv: `name,price,category
|
||
Product A,29.99,Electronics
|
||
Product B,49.99,Home
|
||
Product C,19.99,Electronics`,
|
||
xml: `<?xml version="1.0"?>
|
||
<products>
|
||
<product><name>Product A</name><price>29.99</price><category>Electronics</category></product>
|
||
<product><name>Product B</name><price>49.99</price><category>Home</category></product>
|
||
<product><name>Product C</name><price>19.99</price><category>Electronics</category></product>
|
||
</products>`
|
||
};
|
||
document.getElementById('inputData').value = samples[inputFormat];
|
||
}
|
||
|
||
function clearInput() {
|
||
document.getElementById('inputData').value = '';
|
||
document.getElementById('outputData').value = '';
|
||
hideMessages();
|
||
}
|
||
|
||
function hideMessages() {
|
||
document.getElementById('errorMsg').style.display = 'none';
|
||
document.getElementById('successMsg').style.display = 'none';
|
||
}
|
||
|
||
function showError(msg) {
|
||
hideMessages();
|
||
document.getElementById('errorMsg').textContent = '❌ ' + msg;
|
||
document.getElementById('errorMsg').style.display = 'block';
|
||
}
|
||
|
||
function showSuccess(msg) {
|
||
hideMessages();
|
||
document.getElementById('successMsg').textContent = '✅ ' + msg;
|
||
document.getElementById('successMsg').style.display = 'block';
|
||
}
|
||
|
||
function convert() {
|
||
const input = document.getElementById('inputData').value.trim();
|
||
if (!input) { showError('Please enter some data to convert'); return; }
|
||
|
||
try {
|
||
let data;
|
||
// Parse input
|
||
if (inputFormat === 'json') {
|
||
data = JSON.parse(input);
|
||
if (!Array.isArray(data)) data = [data];
|
||
} else if (inputFormat === 'csv') {
|
||
data = csvToArray(input);
|
||
} else if (inputFormat === 'xml') {
|
||
data = xmlToArray(input);
|
||
}
|
||
|
||
// Convert to output
|
||
let output;
|
||
if (outputFormat === 'json') {
|
||
output = JSON.stringify(data, null, 2);
|
||
} else if (outputFormat === 'csv') {
|
||
output = arrayToCsv(data);
|
||
} else if (outputFormat === 'xml') {
|
||
output = arrayToXml(data);
|
||
}
|
||
|
||
document.getElementById('outputData').value = output;
|
||
showSuccess(`Converted ${data.length} records from ${inputFormat.toUpperCase()} to ${outputFormat.toUpperCase()}`);
|
||
} catch (e) {
|
||
showError('Conversion failed: ' + e.message);
|
||
}
|
||
}
|
||
|
||
function csvToArray(csv) {
|
||
const lines = csv.split('\n').filter(l => l.trim());
|
||
const headers = lines[0].split(',').map(h => h.trim());
|
||
return lines.slice(1).map(line => {
|
||
const values = line.split(',');
|
||
const obj = {};
|
||
headers.forEach((h, i) => obj[h] = values[i]?.trim() || '');
|
||
return obj;
|
||
});
|
||
}
|
||
|
||
function arrayToCsv(arr) {
|
||
if (!arr.length) return '';
|
||
const headers = Object.keys(arr[0]);
|
||
const rows = arr.map(obj => headers.map(h => {
|
||
let val = obj[h] || '';
|
||
if (val.toString().includes(',')) val = `"${val}"`;
|
||
return val;
|
||
}).join(','));
|
||
return [headers.join(','), ...rows].join('\n');
|
||
}
|
||
|
||
function xmlToArray(xml) {
|
||
const parser = new DOMParser();
|
||
const doc = parser.parseFromString(xml, 'text/xml');
|
||
const items = doc.querySelectorAll(doc.documentElement.tagName + ' > *');
|
||
return Array.from(items).map(item => {
|
||
const obj = {};
|
||
Array.from(item.children).forEach(child => {
|
||
obj[child.tagName] = child.textContent;
|
||
});
|
||
return obj;
|
||
});
|
||
}
|
||
|
||
function arrayToXml(arr) {
|
||
if (!arr.length) return '<?xml version="1.0"?>\n<data></data>';
|
||
let xml = '<?xml version="1.0"?>\n<data>\n';
|
||
arr.forEach(obj => {
|
||
xml += ' <item>\n';
|
||
Object.entries(obj).forEach(([k, v]) => {
|
||
xml += ` <${k}>${escapeXml(v)}</${k}>\n`;
|
||
});
|
||
xml += ' </item>\n';
|
||
});
|
||
xml += '</data>';
|
||
return xml;
|
||
}
|
||
|
||
function escapeXml(str) {
|
||
return String(str).replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
|
||
}
|
||
|
||
function copyOutput() {
|
||
const output = document.getElementById('outputData');
|
||
output.select();
|
||
document.execCommand('copy');
|
||
showSuccess('Copied to clipboard!');
|
||
}
|
||
|
||
function downloadOutput() {
|
||
const output = document.getElementById('outputData').value;
|
||
if (!output) { showError('Nothing to download'); return; }
|
||
|
||
const ext = outputFormat === 'json' ? 'json' : outputFormat === 'csv' ? 'csv' : 'xml';
|
||
const mime = outputFormat === 'json' ? 'application/json' : outputFormat === 'csv' ? 'text/csv' : 'text/xml';
|
||
|
||
const blob = new Blob([output], { type: mime });
|
||
const url = URL.createObjectURL(blob);
|
||
const a = document.createElement('a');
|
||
a.href = url;
|
||
a.download = `converted-data.${ext}`;
|
||
a.click();
|
||
URL.revokeObjectURL(url);
|
||
}
|
||
</script>
|
||
</body>
|
||
</html>
|