import fs from "node:fs"; import { createRequire } from "node:module"; const require = createRequire(import.meta.url); const JSZip = require("jszip"); const workbookPath = process.argv[2] || "xxx_endpoint_bo_2026-08-04_v1.xlsm"; const fromRow = Number.parseInt(process.argv[3] || "1", 10); const toRow = Number.parseInt(process.argv[4] || String(fromRow), 10); const zip = await JSZip.loadAsync(fs.readFileSync(workbookPath)); const sharedStringsXml = await zip.file("xl/sharedStrings.xml").async("string"); const sharedStrings = [...sharedStringsXml.matchAll(//g)].map((match) => decodeXml([...match[0].matchAll(/]*>([\s\S]*?)<\/t>/g)].map((part) => part[1]).join("")), ); const sqlSheetXml = await zip.file("xl/worksheets/sheet5.xml").async("string"); for (const rowMatch of sqlSheetXml.matchAll(/]* r="(\d+)"[\s\S]*?<\/row>/g)) { const rowNumber = Number(rowMatch[1]); if (rowNumber < fromRow || rowNumber > toRow) continue; const cells = {}; for (const cellMatch of rowMatch[0].matchAll( /]* r="([A-Z]+)\d+"([^>]*)>([\s\S]*?)<\/c>/g, )) { const [, column, attributes, body] = cellMatch; const inlineString = body.match(/[\s\S]*?]*>([\s\S]*?)<\/t>[\s\S]*?<\/is>/); const rawValue = body.match(/([\s\S]*?)<\/v>/)?.[1] ?? inlineString?.[1] ?? ""; cells[column] = attributes.includes('t="s"') ? sharedStrings[Number(rawValue)] || "" : decodeXml(rawValue); } console.log(JSON.stringify({ row: rowNumber, cells }, null, 2)); } function decodeXml(value) { return String(value ?? "") .replaceAll("<", "<") .replaceAll(">", ">") .replaceAll("&", "&") .replaceAll(""", '"') .replaceAll("'", "'"); }