Browse Source

Search for awarded construction work.

No details yet.
Herby Vojčík 4 years ago
parent
commit
d15b9ea7f4
3 changed files with 116 additions and 1 deletions
  1. 47 0
      lib/read.js
  2. 2 1
      package.json
  3. 67 0
      search.js

+ 47 - 0
lib/read.js

@@ -0,0 +1,47 @@
+import {parseString} from 'xml2js';
+import {promises} from 'fs';
+
+const {readdir, readFile} = promises;
+
+export async function* eachVestnik (prefix) {
+    const xmlFileNames = (await readdir(prefix)).filter(each => each.endsWith('.xml'));
+    for (let xmlFileName of xmlFileNames) {
+        const contents = await readFile(`${prefix}/${xmlFileName}`, {encoding: 'utf8'});
+        const object = await new Promise((resolve, reject) =>
+            parseString(contents, (err, result) => err ? reject(err) : resolve(result)));
+        yield object.vestnik;
+    }
+}
+
+export function* eachItem (vestnik) {
+    for (let obsah of vestnik.obsah)
+        for (let oznamenia_vo of obsah.oznamenia_vo) {
+            yield* eachItemInTree(oznamenia_vo);
+        }
+}
+
+function* eachItemInTree (folder) {
+    for (let subFolder of folder.folder || []) yield* eachItemInTree(subFolder);
+    yield* folder.item;
+}
+
+export function* eachFormElement (item) {
+    for (let content of item.content)
+        for (let form of content.ZovoForm || [])
+            yield* eachFormElementInTree(form);
+}
+
+const DIVE_TAGS = {Part: true, Repeater: true, RepeatingPart: true};
+const IGNORE_TAGS = {SubTitle: true, $: true, _: true};
+
+function* eachFormElementInTree (form) {
+    for (let tag of Object.keys(form)) {
+        if (IGNORE_TAGS[tag]) continue;
+        for (let value of form[tag]) {
+            let shouldCancel = false;
+            const cancel = () => shouldCancel = true;
+            yield {tag, value, cancel};
+            if (DIVE_TAGS[tag] && !shouldCancel) yield* eachFormElementInTree(value);
+        }
+    }
+}

+ 2 - 1
package.json

@@ -17,7 +17,8 @@
   "author": "Herby Vojčík <herby@mailbox.sk>",
   "license": "MIT",
   "dependencies": {
-    "isomorphic-fetch": "^2.2.1"
+    "isomorphic-fetch": "^2.2.1",
+    "xml2js": "^0.4.19"
   },
   "devDependencies": {
     "@babel/core": "^7.4.5",

+ 67 - 0
search.js

@@ -0,0 +1,67 @@
+// node --require regenerator-runtime/runtime --require ./babel-local search.js ..\out result.csv
+
+import {promises} from 'fs';
+import {resolve} from 'path';
+import {eachFormElement, eachItem, eachVestnik} from './lib/read';
+
+const {writeFile, truncate} = promises;
+
+async function work (prefix, outfile) {
+    console.info(`Input directory: ${prefix}`);
+    await truncate(outfile);
+    console.info(`Output file: ${outfile}`);
+    for await (let vestnik of eachVestnik(prefix)) {
+        for (let item of eachItem(vestnik)) {
+            const zakazka = item.zakazka[0].$;
+            const id = zakazka.id || '';
+            const url = zakazka.url || "about:blank";
+            if (hasCpv("45", item)) {
+                const v = oddiel_V(item);
+                if (v) {
+                    const pocetPonuk = -1;
+                    const predpokladanaCena = '?';
+                    const konecnaCena = '?';
+                    const vitazIco = 0;
+                    const out = async () => await writeFile(
+                        outfile,
+                        poorMansCsv([id, url, pocetPonuk, predpokladanaCena, konecnaCena, vitazIco]) + "\r\n",
+                        {flag: "a"}
+                    );
+
+                    out();
+                }
+            }
+        }
+    }
+}
+
+function poorMansCsv (items) {
+    return JSON.stringify(items).slice(1, -1);
+}
+
+function hasCpv (prefix, item) {
+    for (let {tag, value, cancel} of eachFormElement(item)) {
+        if (tag === "Part") {
+            const match = value.$.Title && value.$.Title.match(/^ODDIEL\s+(\w+):/);
+            if (match && match[1] !== "II") cancel();
+        }
+        if (tag === "Cpv" && value.$.Code.startsWith(prefix)) return true;
+        if (tag === "SelectList" && value.$.Type === "CPV" && value.SelectListValue && value.SelectListValue[0].$.Title.startsWith(prefix)) return true;
+    }
+    return false;
+}
+
+function oddiel_V (item) {
+    for (let {tag, value, cancel} of eachFormElement(item)) {
+        if (tag === "Part") {
+            const match = value.$.Title && value.$.Title.match(/^ODDIEL\s+(\w+):/);
+            if (match)
+                if (match[1] === "V") return value; else cancel();
+        }
+    }
+
+    return null;
+}
+
+work(resolve(process.argv[2] || ''), resolve(process.argv[3] || 'result.csv'))
+    .catch(error => console.error(error));