@tricoteuses/assemblee
Version:
Retrieve, clean up & handle French Assemblée nationale's open data
134 lines (130 loc) • 18.4 kB
JavaScript
import fs from "fs-extra";
import path from "path";
import stream from "stream";
import StreamZip from "node-stream-zip";
import util from "util";
import { walkDir } from "../file_systems.mjs";
import { XMLParser } from "fast-xml-parser";
const pipeline = util.promisify(stream.pipeline);
// Function to fetch zip files with retry mechanism
async function fetchZipFile(url, zipFilePath, retries = 3) {
for (let attempt = 0; attempt < retries; attempt++) {
const response = await fetch(url);
if (response.ok) {
await pipeline(response.body, fs.createWriteStream(zipFilePath));
return;
} else if (attempt < retries - 1) {
console.warn(`Retrying fetch for ${url}: ${response.statusText}`);
} else {
console.error(`Failed to fetch ${url} after ${retries} attempts`);
throw new Error(`Fetch failed: ${url}`);
}
}
}
async function extractZip(zipFilePath, outputDir) {
return new Promise((resolve, reject) => {
const zip = new StreamZip({
file: zipFilePath,
storeEntries: true
});
zip.on("ready", () => {
zip.extract(null, outputDir, err => {
zip.close();
if (err) {
reject(err);
} else {
resolve();
}
});
});
});
}
function reindentJsonFiles(dataDirOrFilePath) {
if (fs.statSync(dataDirOrFilePath).isDirectory()) {
for (const dataFileSplitPath of walkDir(dataDirOrFilePath)) {
const dataFilePath = path.join(dataDirOrFilePath, ...dataFileSplitPath);
if (dataFilePath.endsWith(".json")) {
const data = JSON.parse(fs.readFileSync(dataFilePath, {
encoding: "utf-8"
}));
fs.writeFileSync(dataFilePath, JSON.stringify(data, null, 2));
}
}
} else {
const data = JSON.parse(fs.readFileSync(dataDirOrFilePath, {
encoding: "utf-8"
}));
fs.writeFileSync(dataDirOrFilePath, JSON.stringify(data, null, 2));
}
}
const xmlParser = new XMLParser({
ignoreDeclaration: true,
ignoreAttributes: false,
ignorePiTags: true,
attributeNamePrefix: "",
textNodeName: "_",
processEntities: false,
trimValues: true,
stopNodes: ["*.texte", "*.intitule"],
parseTagValue: false,
parseAttributeValue: false,
transformTagName: tagName => tagName === "Para" ? "para" : tagName
});
/**
* Processes a dataset by fetching, unzipping, and converting files from XML to JSON format.
*
* @param {any} dataset - The dataset object containing metadata and processing instructions.
* @param {string} dataDir - The directory where the dataset files will be stored.
* @param {any} options - Options to control the processing behavior, such as fetching and silent mode.
* @returns {Promise<void>} A promise that resolves when the dataset processing is complete.
*/
export async function processDataset(args) {
const {
dataset,
dataDir,
options
} = args;
const zipFilePath = path.join(dataDir, `${dataset.filename}.zip`);
const dataDirOrFilePath = path.join(dataDir, dataset.filename);
fs.removeSync(dataDirOrFilePath);
if (options.fetch) {
// Fetch & save ZIP file.
if (!options.silent) {
console.log(`Loading ${dataset.title}: ${dataset.filename}.zip`);
}
await fetchZipFile(dataset.url, zipFilePath);
}
if (!options.silent) {
console.log(`Unzipping ${dataset.title}: ${dataset.filename}.zip`);
}
await extractZip(zipFilePath, dataDir);
if (dataset.repairZip !== undefined) {
if (!options.silent) {
console.log(`Repairing ${dataset.title}: ${dataset.filename}`);
}
dataset.repairZip(dataset, dataDir);
}
// Convert xml to JSON.
if (dataset.filename.endsWith(".xml")) {
for (const dataFileSplitPath of walkDir(dataDirOrFilePath)) {
const dataFilePath = path.join(dataDirOrFilePath, ...dataFileSplitPath);
if (dataFilePath.endsWith(".xml")) {
fs.readFile(dataFilePath, function (err, data) {
if (err) return console.error(err);
let result = xmlParser.parse(data);
const newDataFilePath = dataFilePath.replace(/\.[^.]+$/, ".json");
fs.copy(dataFilePath, newDataFilePath, err => {
fs.writeFileSync(newDataFilePath, JSON.stringify(result, null, 2));
if (err) return console.error(err);
});
});
}
}
}
// Reindent JSON file.
if (!options.silent) {
console.log(`Reidenting ${dataset.title}: ${dataset.filename}`);
}
reindentJsonFiles(dataDirOrFilePath);
}
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJmcyIsInBhdGgiLCJzdHJlYW0iLCJTdHJlYW1aaXAiLCJ1dGlsIiwid2Fsa0RpciIsIlhNTFBhcnNlciIsInBpcGVsaW5lIiwicHJvbWlzaWZ5IiwiZmV0Y2haaXBGaWxlIiwidXJsIiwiemlwRmlsZVBhdGgiLCJyZXRyaWVzIiwiYXR0ZW1wdCIsInJlc3BvbnNlIiwiZmV0Y2giLCJvayIsImJvZHkiLCJjcmVhdGVXcml0ZVN0cmVhbSIsImNvbnNvbGUiLCJ3YXJuIiwic3RhdHVzVGV4dCIsImVycm9yIiwiRXJyb3IiLCJleHRyYWN0WmlwIiwib3V0cHV0RGlyIiwiUHJvbWlzZSIsInJlc29sdmUiLCJyZWplY3QiLCJ6aXAiLCJmaWxlIiwic3RvcmVFbnRyaWVzIiwib24iLCJleHRyYWN0IiwiZXJyIiwiY2xvc2UiLCJyZWluZGVudEpzb25GaWxlcyIsImRhdGFEaXJPckZpbGVQYXRoIiwic3RhdFN5bmMiLCJpc0RpcmVjdG9yeSIsImRhdGFGaWxlU3BsaXRQYXRoIiwiZGF0YUZpbGVQYXRoIiwiam9pbiIsImVuZHNXaXRoIiwiZGF0YSIsIkpTT04iLCJwYXJzZSIsInJlYWRGaWxlU3luYyIsImVuY29kaW5nIiwid3JpdGVGaWxlU3luYyIsInN0cmluZ2lmeSIsInhtbFBhcnNlciIsImlnbm9yZURlY2xhcmF0aW9uIiwiaWdub3JlQXR0cmlidXRlcyIsImlnbm9yZVBpVGFncyIsImF0dHJpYnV0ZU5hbWVQcmVmaXgiLCJ0ZXh0Tm9kZU5hbWUiLCJwcm9jZXNzRW50aXRpZXMiLCJ0cmltVmFsdWVzIiwic3RvcE5vZGVzIiwicGFyc2VUYWdWYWx1ZSIsInBhcnNlQXR0cmlidXRlVmFsdWUiLCJ0cmFuc2Zvcm1UYWdOYW1lIiwidGFnTmFtZSIsInByb2Nlc3NEYXRhc2V0IiwiYXJncyIsImRhdGFzZXQiLCJkYXRhRGlyIiwib3B0aW9ucyIsImZpbGVuYW1lIiwicmVtb3ZlU3luYyIsInNpbGVudCIsImxvZyIsInRpdGxlIiwicmVwYWlyWmlwIiwidW5kZWZpbmVkIiwicmVhZEZpbGUiLCJyZXN1bHQiLCJuZXdEYXRhRmlsZVBhdGgiLCJyZXBsYWNlIiwiY29weSJdLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9zY3JpcHRzL3Byb2Nlc3Nfb3Blbl9kYXRhc2V0LnRzIl0sInNvdXJjZXNDb250ZW50IjpbImltcG9ydCBmcyBmcm9tIFwiZnMtZXh0cmFcIlxuaW1wb3J0IHBhdGggZnJvbSBcInBhdGhcIlxuaW1wb3J0IHN0cmVhbSBmcm9tIFwic3RyZWFtXCJcbmltcG9ydCBTdHJlYW1aaXAgZnJvbSBcIm5vZGUtc3RyZWFtLXppcFwiXG5pbXBvcnQgdXRpbCBmcm9tIFwidXRpbFwiXG5cbmltcG9ydCB7IHdhbGtEaXIgfSBmcm9tIFwiLi4vZmlsZV9zeXN0ZW1zXCJcbmltcG9ydCB7IFhNTFBhcnNlciB9IGZyb20gXCJmYXN0LXhtbC1wYXJzZXJcIlxuXG5jb25zdCBwaXBlbGluZSA9IHV0aWwucHJvbWlzaWZ5KHN0cmVhbS5waXBlbGluZSlcblxuLy8gRnVuY3Rpb24gdG8gZmV0Y2ggemlwIGZpbGVzIHdpdGggcmV0cnkgbWVjaGFuaXNtXG5hc3luYyBmdW5jdGlvbiBmZXRjaFppcEZpbGUoXG4gIHVybDogc3RyaW5nLFxuICB6aXBGaWxlUGF0aDogc3RyaW5nLFxuICByZXRyaWVzID0gMyxcbik6IFByb21pc2U8dm9pZD4ge1xuICBmb3IgKGxldCBhdHRlbXB0ID0gMDsgYXR0ZW1wdCA8IHJldHJpZXM7IGF0dGVtcHQrKykge1xuICAgIGNvbnN0IHJlc3BvbnNlID0gYXdhaXQgZmV0Y2godXJsKVxuICAgIGlmIChyZXNwb25zZS5vaykge1xuICAgICAgYXdhaXQgcGlwZWxpbmUoXG4gICAgICAgIHJlc3BvbnNlLmJvZHkgYXMgdW5rbm93biBhcyBOb2RlSlMuUmVhZGFibGVTdHJlYW0sXG4gICAgICAgIGZzLmNyZWF0ZVdyaXRlU3RyZWFtKHppcEZpbGVQYXRoKSxcbiAgICAgIClcbiAgICAgIHJldHVyblxuICAgIH0gZWxzZSBpZiAoYXR0ZW1wdCA8IHJldHJpZXMgLSAxKSB7XG4gICAgICBjb25zb2xlLndhcm4oYFJldHJ5aW5nIGZldGNoIGZvciAke3VybH06ICR7cmVzcG9uc2Uuc3RhdHVzVGV4dH1gKVxuICAgIH0gZWxzZSB7XG4gICAgICBjb25zb2xlLmVycm9yKGBGYWlsZWQgdG8gZmV0Y2ggJHt1cmx9IGFmdGVyICR7cmV0cmllc30gYXR0ZW1wdHNgKVxuICAgICAgdGhyb3cgbmV3IEVycm9yKGBGZXRjaCBmYWlsZWQ6ICR7dXJsfWApXG4gICAgfVxuICB9XG59XG5cbmFzeW5jIGZ1bmN0aW9uIGV4dHJhY3RaaXAoXG4gIHppcEZpbGVQYXRoOiBzdHJpbmcsXG4gIG91dHB1dERpcjogc3RyaW5nLFxuKTogUHJvbWlzZTx2b2lkPiB7XG4gIHJldHVybiBuZXcgUHJvbWlzZTx2b2lkPigocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XG4gICAgY29uc3QgemlwID0gbmV3IFN0cmVhbVppcCh7XG4gICAgICBmaWxlOiB6aXBGaWxlUGF0aCxcbiAgICAgIHN0b3JlRW50cmllczogdHJ1ZSxcbiAgICB9KVxuXG4gICAgemlwLm9uKFwicmVhZHlcIiwgKCkgPT4ge1xuICAgICAgemlwLmV4dHJhY3QobnVsbCEsIG91dHB1dERpciwgKGVycikgPT4ge1xuICAgICAgICB6aXAuY2xvc2UoKVxuICAgICAgICBpZiAoZXJyKSB7XG4gICAgICAgICAgcmVqZWN0KGVycilcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICByZXNvbHZlKClcbiAgICAgICAgfVxuICAgICAgfSlcbiAgICB9KVxuICB9KVxufVxuXG5mdW5jdGlvbiByZWluZGVudEpzb25GaWxlcyhkYXRhRGlyT3JGaWxlUGF0aDogc3RyaW5nKTogdm9pZCB7XG4gIGlmIChmcy5zdGF0U3luYyhkYXRhRGlyT3JGaWxlUGF0aCkuaXNEaXJlY3RvcnkoKSkge1xuICAgIGZvciAoY29uc3QgZGF0YUZpbGVTcGxpdFBhdGggb2Ygd2Fsa0RpcihkYXRhRGlyT3JGaWxlUGF0aCkpIHtcbiAgICAgIGNvbnN0IGRhdGFGaWxlUGF0aCA9IHBhdGguam9pbihkYXRhRGlyT3JGaWxlUGF0aCwgLi4uZGF0YUZpbGVTcGxpdFBhdGgpXG4gICAgICBpZiAoZGF0YUZpbGVQYXRoLmVuZHNXaXRoKFwiLmpzb25cIikpIHtcbiAgICAgICAgY29uc3QgZGF0YSA9IEpTT04ucGFyc2UoXG4gICAgICAgICAgZnMucmVhZEZpbGVTeW5jKGRhdGFGaWxlUGF0aCwgeyBlbmNvZGluZzogXCJ1dGYtOFwiIH0pLFxuICAgICAgICApXG4gICAgICAgIGZzLndyaXRlRmlsZVN5bmMoZGF0YUZpbGVQYXRoLCBKU09OLnN0cmluZ2lmeShkYXRhLCBudWxsLCAyKSlcbiAgICAgIH1cbiAgICB9XG4gIH0gZWxzZSB7XG4gICAgY29uc3QgZGF0YSA9IEpTT04ucGFyc2UoXG4gICAgICBmcy5yZWFkRmlsZVN5bmMoZGF0YURpck9yRmlsZVBhdGgsIHsgZW5jb2Rpbmc6IFwidXRmLThcIiB9KSxcbiAgICApXG4gICAgZnMud3JpdGVGaWxlU3luYyhkYXRhRGlyT3JGaWxlUGF0aCwgSlNPTi5zdHJpbmdpZnkoZGF0YSwgbnVsbCwgMikpXG4gIH1cbn1cblxudHlwZSBQcm9jZXNzRGF0YXNldEFyZ3VtZW50cyA9IHtcbiAgZGF0YXNldDogYW55XG4gIGRhdGFEaXI6IHN0cmluZ1xuICBvcHRpb25zOiBhbnlcbn1cblxuY29uc3QgeG1sUGFyc2VyID0gbmV3IFhNTFBhcnNlcih7XG4gIGlnbm9yZURlY2xhcmF0aW9uOiB0cnVlLFxuICBpZ25vcmVBdHRyaWJ1dGVzOiBmYWxzZSxcbiAgaWdub3JlUGlUYWdzOiB0cnVlLFxuICBhdHRyaWJ1dGVOYW1lUHJlZml4OiBcIlwiLFxuICB0ZXh0Tm9kZU5hbWU6IFwiX1wiLFxuICBwcm9jZXNzRW50aXRpZXM6IGZhbHNlLFxuICB0cmltVmFsdWVzOiB0cnVlLFxuICBzdG9wTm9kZXM6IFtcIioudGV4dGVcIiwgXCIqLmludGl0dWxlXCJdLFxuICBwYXJzZVRhZ1ZhbHVlOiBmYWxzZSxcbiAgcGFyc2VBdHRyaWJ1dGVWYWx1ZTogZmFsc2UsXG4gIHRyYW5zZm9ybVRhZ05hbWU6ICh0YWdOYW1lOiBzdHJpbmcpID0+XG4gICAgdGFnTmFtZSA9PT0gXCJQYXJhXCIgPyBcInBhcmFcIiA6IHRhZ05hbWUsXG59KVxuXG4vKipcbiAqIFByb2Nlc3NlcyBhIGRhdGFzZXQgYnkgZmV0Y2hpbmcsIHVuemlwcGluZywgYW5kIGNvbnZlcnRpbmcgZmlsZXMgZnJvbSBYTUwgdG8gSlNPTiBmb3JtYXQuXG4gKlxuICogQHBhcmFtIHthbnl9IGRhdGFzZXQgLSBUaGUgZGF0YXNldCBvYmplY3QgY29udGFpbmluZyBtZXRhZGF0YSBhbmQgcHJvY2Vzc2luZyBpbnN0cnVjdGlvbnMuXG4gKiBAcGFyYW0ge3N0cmluZ30gZGF0YURpciAtIFRoZSBkaXJlY3Rvcnkgd2hlcmUgdGhlIGRhdGFzZXQgZmlsZXMgd2lsbCBiZSBzdG9yZWQuXG4gKiBAcGFyYW0ge2FueX0gb3B0aW9ucyAtIE9wdGlvbnMgdG8gY29udHJvbCB0aGUgcHJvY2Vzc2luZyBiZWhhdmlvciwgc3VjaCBhcyBmZXRjaGluZyBhbmQgc2lsZW50IG1vZGUuXG4gKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn0gQSBwcm9taXNlIHRoYXQgcmVzb2x2ZXMgd2hlbiB0aGUgZGF0YXNldCBwcm9jZXNzaW5nIGlzIGNvbXBsZXRlLlxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gcHJvY2Vzc0RhdGFzZXQoXG4gIGFyZ3M6IFByb2Nlc3NEYXRhc2V0QXJndW1lbnRzLFxuKTogUHJvbWlzZTx2b2lkPiB7XG4gIGNvbnN0IHsgZGF0YXNldCwgZGF0YURpciwgb3B0aW9ucyB9ID0gYXJnc1xuICBjb25zdCB6aXBGaWxlUGF0aCA9IHBhdGguam9pbihkYXRhRGlyLCBgJHtkYXRhc2V0LmZpbGVuYW1lfS56aXBgKVxuICBjb25zdCBkYXRhRGlyT3JGaWxlUGF0aCA9IHBhdGguam9pbihkYXRhRGlyLCBkYXRhc2V0LmZpbGVuYW1lKVxuICBmcy5yZW1vdmVTeW5jKGRhdGFEaXJPckZpbGVQYXRoKVxuXG4gIGlmIChvcHRpb25zLmZldGNoKSB7XG4gICAgLy8gRmV0Y2ggJiBzYXZlIFpJUCBmaWxlLlxuICAgIGlmICghb3B0aW9ucy5zaWxlbnQpIHtcbiAgICAgIGNvbnNvbGUubG9nKGBMb2FkaW5nICR7ZGF0YXNldC50aXRsZX06ICR7ZGF0YXNldC5maWxlbmFtZX0uemlwYClcbiAgICB9XG4gICAgYXdhaXQgZmV0Y2haaXBGaWxlKGRhdGFzZXQudXJsLCB6aXBGaWxlUGF0aClcbiAgfVxuICBpZiAoIW9wdGlvbnMuc2lsZW50KSB7XG4gICAgY29uc29sZS5sb2coYFVuemlwcGluZyAke2RhdGFzZXQudGl0bGV9OiAke2RhdGFzZXQuZmlsZW5hbWV9LnppcGApXG4gIH1cbiAgYXdhaXQgZXh0cmFjdFppcCh6aXBGaWxlUGF0aCwgZGF0YURpcilcblxuICBpZiAoZGF0YXNldC5yZXBhaXJaaXAgIT09IHVuZGVmaW5lZCkge1xuICAgIGlmICghb3B0aW9ucy5zaWxlbnQpIHtcbiAgICAgIGNvbnNvbGUubG9nKGBSZXBhaXJpbmcgJHtkYXRhc2V0LnRpdGxlfTogJHtkYXRhc2V0LmZpbGVuYW1lfWApXG4gICAgfVxuICAgIGRhdGFzZXQucmVwYWlyWmlwKGRhdGFzZXQsIGRhdGFEaXIpXG4gIH1cblxuICAvLyBDb252ZXJ0IHhtbCB0byBKU09OLlxuICBpZiAoZGF0YXNldC5maWxlbmFtZS5lbmRzV2l0aChcIi54bWxcIikpIHtcbiAgICBmb3IgKGNvbnN0IGRhdGFGaWxlU3BsaXRQYXRoIG9mIHdhbGtEaXIoZGF0YURpck9yRmlsZVBhdGgpKSB7XG4gICAgICBjb25zdCBkYXRhRmlsZVBhdGggPSBwYXRoLmpvaW4oZGF0YURpck9yRmlsZVBhdGgsIC4uLmRhdGFGaWxlU3BsaXRQYXRoKVxuICAgICAgaWYgKGRhdGFGaWxlUGF0aC5lbmRzV2l0aChcIi54bWxcIikpIHtcbiAgICAgICAgZnMucmVhZEZpbGUoZGF0YUZpbGVQYXRoLCBmdW5jdGlvbiAoZXJyLCBkYXRhKSB7XG4gICAgICAgICAgaWYgKGVycikgcmV0dXJuIGNvbnNvbGUuZXJyb3IoZXJyKVxuICAgICAgICAgIGxldCByZXN1bHQgPSB4bWxQYXJzZXIucGFyc2UoZGF0YSlcbiAgICAgICAgICBjb25zdCBuZXdEYXRhRmlsZVBhdGggPSBkYXRhRmlsZVBhdGgucmVwbGFjZSgvXFwuW14uXSskLywgXCIuanNvblwiKVxuICAgICAgICAgIGZzLmNvcHkoZGF0YUZpbGVQYXRoLCBuZXdEYXRhRmlsZVBhdGgsIChlcnIpID0+IHtcbiAgICAgICAgICAgIGZzLndyaXRlRmlsZVN5bmMobmV3RGF0YUZpbGVQYXRoLCBKU09OLnN0cmluZ2lmeShyZXN1bHQsIG51bGwsIDIpKVxuICAgICAgICAgICAgaWYgKGVycikgcmV0dXJuIGNvbnNvbGUuZXJyb3IoZXJyKVxuICAgICAgICAgIH0pXG4gICAgICAgIH0pXG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgLy8gUmVpbmRlbnQgSlNPTiBmaWxlLlxuICBpZiAoIW9wdGlvbnMuc2lsZW50KSB7XG4gICAgY29uc29sZS5sb2coYFJlaWRlbnRpbmcgJHtkYXRhc2V0LnRpdGxlfTogJHtkYXRhc2V0LmZpbGVuYW1lfWApXG4gIH1cbiAgcmVpbmRlbnRKc29uRmlsZXMoZGF0YURpck9yRmlsZVBhdGgpXG59XG4iXSwibWFwcGluZ3MiOiJBQUFBLE9BQU9BLEVBQUUsTUFBTSxVQUFVO0FBQ3pCLE9BQU9DLElBQUksTUFBTSxNQUFNO0FBQ3ZCLE9BQU9DLE1BQU0sTUFBTSxRQUFRO0FBQzNCLE9BQU9DLFNBQVMsTUFBTSxpQkFBaUI7QUFDdkMsT0FBT0MsSUFBSSxNQUFNLE1BQU07QUFBQSxTQUVkQyxPQUFPO0FBQ2hCLFNBQVNDLFNBQVMsUUFBUSxpQkFBaUI7QUFFM0MsTUFBTUMsUUFBUSxHQUFHSCxJQUFJLENBQUNJLFNBQVMsQ0FBQ04sTUFBTSxDQUFDSyxRQUFRLENBQUM7O0FBRWhEO0FBQ0EsZUFBZUUsWUFBWUEsQ0FDekJDLEdBQVcsRUFDWEMsV0FBbUIsRUFDbkJDLE9BQU8sR0FBRyxDQUFDLEVB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