Files
ukaiautomation/tools/data-converter.php
Peter Foster 15e9ba598e Cache: fix 1-year CSS cache and add version busting
- .htaccess: remove duplicate cache block that set all CSS/JS to max-age=31536000
  CSS/JS now use max-age=3600 must-revalidate (was 1 year, breaking live edits)
- index.php: bump main.min.css version v1.1.3 -> v1.1.4
- All 78 PHP files: add ?v=20260222 to main.css and cro-enhancements.css refs
  Forces browser cache bust for all pages after todays accessibility changes
2026-02-22 11:12:40 +00:00

320 lines
15 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
$page_title = "Free Data Format Converter | JSON CSV XML | UK Data Services";
$page_description = "Convert between JSON, CSV, and XML formats instantly. Free online tool for data transformation - no signup required.";
$canonical_url = "https://ukdataservices.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://ukdataservices.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: #1a1a2e; 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: #179e83; }
.format-btn.active { background: #179e83; color: white; border-color: #179e83; }
.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: #1a1a2e; 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: #179e83; 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: #179e83; 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: #144784; 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: #179e83; 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: #1a1a2e; 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, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
}
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>