2026-02-05 04:11:15 +00:00
|
|
|
|
<?php
|
2026-03-21 09:48:46 +00:00
|
|
|
|
$page_title = "Free Data Format Converter | JSON CSV XML | UK AI Automation";
|
2026-02-05 04:11:15 +00:00
|
|
|
|
$page_description = "Convert between JSON, CSV, and XML formats instantly. Free online tool for data transformation - no signup required.";
|
2026-03-21 09:48:46 +00:00
|
|
|
|
$canonical_url = "https://ukaiautomation.co.uk/tools/data-converter";
|
2026-02-05 04:11:15 +00:00
|
|
|
|
?>
|
|
|
|
|
|
<!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); ?>">
|
Fix navbar across all pages: add nav include, fonts, active state, spacing, stats, error pages
- Add nav.php include to 5 missing pages (cost-calculator, thank-you, 403, 404, 500)
- Add ErrorDocument directives to .htaccess for custom 403/404/500 pages
- Fix bogus accuracy stats (homepage, web-scraping, location pages)
- Fix invisible CTA buttons on property and financial service pages
- Add Google Fonts (Roboto Slab + Lato) to all pages missing it (tools, blog articles, error pages)
- Add active nav link highlighting (teal underline for current page)
- Improve footer contrast to WCAG AA, equal-height cards, mobile text scaling
- Consistent navbar-to-content spacing across all pages
- Bump cache version to v1.1.3
2026-02-11 07:15:11 +00:00
|
|
|
|
<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); ?>">
|
2026-02-05 04:11:15 +00:00
|
|
|
|
|
|
|
|
|
|
<meta property="og:title" content="<?php echo htmlspecialchars($page_title); ?>">
|
|
|
|
|
|
<meta property="og:description" content="<?php echo htmlspecialchars($page_description); ?>">
|
|
|
|
|
|
|
2026-02-22 11:11:56 +00:00
|
|
|
|
<link rel="stylesheet" href="../assets/css/main.css?v=20260222">
|
2026-02-05 04:11:15 +00:00
|
|
|
|
|
|
|
|
|
|
<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",
|
2026-03-21 09:48:46 +00:00
|
|
|
|
"url": "https://ukaiautomation.co.uk/tools/data-converter",
|
2026-02-05 04:11:15 +00:00
|
|
|
|
"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; }
|
2026-03-21 09:48:46 +00:00
|
|
|
|
.converter-header h1 { font-size: 2.2em; color: #1e1b4b; margin-bottom: 15px; }
|
2026-02-05 04:11:15 +00:00
|
|
|
|
.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; }
|
2026-03-21 09:48:46 +00:00
|
|
|
|
.format-btn:hover { border-color: #6d28d9; }
|
|
|
|
|
|
.format-btn.active { background: #6d28d9; color: white; border-color: #6d28d9; }
|
2026-02-05 04:11:15 +00:00
|
|
|
|
.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; }
|
2026-03-21 09:48:46 +00:00
|
|
|
|
.editor-box label { font-weight: 600; color: #1e1b4b; margin-bottom: 10px; display: flex; justify-content: space-between; align-items: center; }
|
2026-02-05 04:11:15 +00:00
|
|
|
|
.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; }
|
2026-03-21 09:48:46 +00:00
|
|
|
|
.editor-box textarea:focus { border-color: #6d28d9; outline: none; }
|
2026-02-05 04:11:15 +00:00
|
|
|
|
.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; }
|
2026-03-21 09:48:46 +00:00
|
|
|
|
.btn-primary { background: #6d28d9; color: white; }
|
2026-02-05 04:11:15 +00:00
|
|
|
|
.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; }
|
2026-03-21 09:48:46 +00:00
|
|
|
|
.breadcrumb a { color: #7c3aed; text-decoration: none; }
|
2026-02-05 04:11:15 +00:00
|
|
|
|
.breadcrumb span { color: #888; margin: 0 8px; }
|
|
|
|
|
|
.sample-data { font-size: 0.85em; color: #666; margin-top: 8px; }
|
2026-03-21 09:48:46 +00:00
|
|
|
|
.sample-data a { color: #6d28d9; cursor: pointer; text-decoration: underline; }
|
2026-02-05 04:11:15 +00:00
|
|
|
|
</style>
|
|
|
|
|
|
</head>
|
|
|
|
|
|
<body>
|
2026-02-10 22:24:40 +00:00
|
|
|
|
<?php include($_SERVER["DOCUMENT_ROOT"] . "/includes/nav.php"); ?>
|
2026-02-05 04:11:15 +00:00
|
|
|
|
|
|
|
|
|
|
<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;">
|
2026-03-21 09:48:46 +00:00
|
|
|
|
<h3 style="color: #1e1b4b; margin-bottom: 15px;">💡 About This Tool</h3>
|
2026-02-05 04:11:15 +00:00
|
|
|
|
<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>
|