Skip to content

Instantly share code, notes, and snippets.

@yetti
Created May 4, 2025 08:57
Show Gist options
  • Save yetti/d047c6e265863fabda551cffd83aa573 to your computer and use it in GitHub Desktop.
Save yetti/d047c6e265863fabda551cffd83aa573 to your computer and use it in GitHub Desktop.
Object -> CSV or CSV -> Object
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Hash to CSV Converter</title>
<!-- Add PapaParse CDN -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/PapaParse/5.3.2/papaparse.min.js"></script>
<style>
body {
font-family: Arial, sans-serif;
max-width: 800px;
margin: 0 auto;
padding: 20px;
}
textarea {
width: 100%;
height: 200px;
margin-bottom: 15px;
font-family: monospace;
}
button {
padding: 8px 16px;
background-color: #4caf50;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
margin-right: 10px;
}
button:hover {
background-color: #45a049;
}
pre {
background-color: #f5f5f5;
padding: 10px;
overflow: auto;
border: 1px solid #ddd;
}
.file-input-container {
margin-top: 20px;
margin-bottom: 20px;
}
</style>
</head>
<body>
<h1>Hash to CSV Converter</h1>
<h2>Input JavaScript Object</h2>
<textarea id="hashInput">
{
"person1": { "name": "John", "age": 30, "city": "New York" },
"person2": { "name": "Jane", "age": 25, "city": "Boston" },
"person3": { "name": "Bob", "age": 35, "city": "Chicago" }
}</textarea
>
<div>
<button onclick="convertAndDownload()">Convert to CSV & Download</button>
</div>
<h2>Preview</h2>
<pre id="preview"></pre>
<h2>Load CSV Back to Object</h2>
<div class="file-input-container">
<input type="file" id="csvFileInput" accept=".csv" />
<button onclick="loadCSVFile()">Load CSV to Object</button>
</div>
<h3>Converted Object</h3>
<pre id="objectPreview"></pre>
<script>
// Convert JavaScript object to CSV string using PapaParse
function objectToCSV(obj) {
// Check if input is empty or invalid
if (!obj || Object.keys(obj).length === 0) {
return "";
}
// Get all possible keys from all nested objects
const allKeys = new Set();
Object.values(obj).forEach((item) => {
if (typeof item === "object" && item !== null) {
Object.keys(item).forEach((key) => allKeys.add(key));
}
});
const headers = ["id", ...Array.from(allKeys)];
// Create array of row data for PapaParse
const rows = [];
// Add header row
rows.push(headers);
// Add data rows
Object.entries(obj).forEach(([key, value]) => {
const row = new Array(headers.length).fill("");
row[0] = key; // Set ID
if (value && typeof value === "object") {
Object.entries(value).forEach(([propKey, propValue]) => {
const headerIndex = headers.indexOf(propKey);
if (headerIndex > 0) {
row[headerIndex] = propValue;
}
});
}
rows.push(row);
});
// Use PapaParse to generate CSV
const csvContent = Papa.unparse(rows, {
quotes: true, // Use quotes around fields that need them
quoteChar: '"',
delimiter: ",",
header: false, // Already included headers in our data
newline: "\n",
});
return csvContent;
}
function convertAndDownload() {
try {
// Get the input
const input = document.getElementById("hashInput").value.trim();
// Safely evaluate the JavaScript object
let data;
if (input.startsWith("{") && input.endsWith("}")) {
// Use a safer approach than Function constructor
try {
data = JSON.parse(input);
} catch (jsonError) {
// If JSON.parse fails, try evaluating as a JavaScript object
try {
// Use Function but with extra validation
if (!/[<>]|script|on\w+=|document\./.test(input)) {
data = Function("return " + input)();
} else {
throw new Error("Input contains potentially unsafe code");
}
} catch (evalError) {
throw new Error(
"Invalid JavaScript object: " + evalError.message
);
}
}
} else {
throw new Error("Input must be a valid JavaScript object");
}
// Convert to CSV using PapaParse
const csvContent = objectToCSV(data);
// Show preview
document.getElementById("preview").textContent = csvContent;
// Create download link
const blob = new Blob([csvContent], {
type: "text/csv;charset=utf-8;",
});
const url = URL.createObjectURL(blob);
const link = document.createElement("a");
link.setAttribute("href", url);
link.setAttribute("download", "data.csv");
link.style.display = "none";
// Add to document, click and remove
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
} catch (error) {
alert("Error: " + error.message);
console.error(error);
}
}
// Convert CSV string back to JavaScript object using PapaParse
function loadCSVFile() {
const fileInput = document.getElementById("csvFileInput");
const file = fileInput.files[0];
if (!file) {
alert("Please select a CSV file first.");
return;
}
Papa.parse(file, {
complete: function (results) {
try {
if (results.errors.length > 0) {
console.warn("CSV parsing had errors:", results.errors);
}
const data = results.data;
// First row should be headers
if (data.length < 2) {
throw new Error(
"CSV file must have headers and at least one data row"
);
}
const headers = data[0];
const idIndex = headers.findIndex(
(header) => header.toLowerCase() === "id"
);
if (idIndex === -1) {
throw new Error('CSV must contain "id" column');
}
// Convert CSV data to object
const reconstructedObject = {};
// Process each row (skip header row)
for (let i = 1; i < data.length; i++) {
const row = data[i];
// Skip empty rows
if (row.length <= 1 && (row[0] === "" || row[0] === undefined))
continue;
const id = row[idIndex];
if (!id) continue; // Skip rows without ID
reconstructedObject[id] = {};
// Add all properties from the row
for (let j = 0; j < headers.length; j++) {
if (j !== idIndex && headers[j] && row[j] !== "") {
let value = row[j];
// Try to convert numeric strings to numbers
if (value && /^-?\d+(\.\d+)?$/.test(value)) {
value = parseFloat(value);
}
reconstructedObject[id][headers[j]] = value;
}
}
}
// Display the resulting object
document.getElementById("objectPreview").textContent =
JSON.stringify(reconstructedObject, null, 2);
// Optionally, populate the input textarea
document.getElementById("hashInput").value = JSON.stringify(
reconstructedObject,
null,
2
);
} catch (error) {
alert("Error processing CSV: " + error.message);
console.error(error);
}
},
error: function (error) {
alert("Error reading CSV file: " + error.message);
console.error(error);
},
});
}
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment