Bin
2025-12-16 9e0b2ba2c317b1a86212f24cbae3195ad1f3dbfa
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
const xml2js = require("xml2js");
const builder = require("xmlbuilder");
const OPTIONS = {
  headless: true,
  explicitChildren: true,
  preserveChildrenOrder: true,
  charsAsChildren: true,
};
 
function parseXml(doc) {
  let document;
  const parser = new xml2js.Parser(OPTIONS);
 
  parser.parseString(doc, (err, result) => {
    document = result;
  });
  return document;
}
function renderXml(doc) {
  const rootName = Object.keys(doc)[0];
  const xml = builder.create(rootName, null, null, { headless: true });
  const renderChildren = (nodes, xml) => {
    nodes.forEach((node) => {
      const elem = xml.ele(node["#name"]);
 
      if (node.$) Object.keys(node.$).forEach((key) => elem.att(key, node.$[key]));
      if (node.$$) renderChildren(node.$$, elem);
    });
  };
 
  renderChildren(doc[rootName].$$, xml);
  return xml.end({ pretty: true });
}
 
function countRegionsInResult(result) {
  return result.reduce(
    (res, r) => {
      if ((!res.ids[r.id] && Object.keys(r.value).length > 1) || !!r.value.points) {
        res.count++;
        res.ids[r.id] = true;
      }
      return res;
    },
    { count: 0, ids: {} },
  ).count;
}
 
function xmlForEachNode(tree, cb) {
  function forEachNode(node) {
    cb(node);
    if (node.$$) {
      node.$$.forEach((childNode) => forEachNode(childNode));
    }
  }
  forEachNode(Object.values(tree)[0]);
}
 
function xmlFilterNodes(tree, cb) {
  function filterChildren(node) {
    cb(node);
    if (node.$$) {
      node.$$ = node.$$.filter((childNode) => {
        if (!cb(childNode)) return false;
        filterChildren(childNode);
        return true;
      });
    }
  }
  const rootNode = Object.values(tree)[0];
 
  if (cb(rootNode)) {
    filterChildren(rootNode);
  }
  return {};
}
 
function xmlTreeHasTag(tree, tagName) {
  return xmlFindBy(tree, (node) => node["#name"] === tagName);
}
 
function xmlFindBy(tree, cb) {
  function findBy(node) {
    if (cb(node)) return node;
    return !!node.$$ && node.$$.find((childNode) => findBy(childNode));
  }
  const rootNode = Object.values(tree)[0];
 
  return findBy(rootNode);
}
 
module.exports = {
  parseXml,
  renderXml,
  xmlForEachNode,
  xmlFindBy,
  xmlTreeHasTag,
  xmlFilterNodes,
  countRegionsInResult,
};