-
Notifications
You must be signed in to change notification settings - Fork 6
/
xml-utils.js
78 lines (72 loc) · 2.35 KB
/
xml-utils.js
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
const util = require('util')
const xml2js = require('xml2js')
const parser = util.promisify(new xml2js.Parser({ explicitArray: true }).parseString)
const noArrayParser = util.promisify(new xml2js.Parser({ explicitArray: false }).parseString)
const renderOpts = {
indent: ' ',
emptyTag: true
}
const serializeValue = (tagname, v, indentLevel) => {
let res = ''
if (typeof (v) === 'object') {
res += '\n'
const keys = Object.keys(v)
const l = keys.length
for (let i = 0; i < l; i++) {
const serializedSubXml = sfdcXmlBuilder(keys[i], v[keys[i]], false, indentLevel)
res += serializedSubXml + (serializedSubXml ? '\n' : '')
}
} else {
v = v + ''
const l = v.length
for (let i = 0; i < l; i++) {
const c = v[i]
if (c === '&') {
res += '&'
} else if (c === '<') {
res += '<'
} else if (c === '>') {
res += '>'
} else if (c === '"') {
res += '"'
} else if (c === "'") {
res += '''
} else {
res += c
}
}
}
return res
}
const buildTag = (tagname, attributes) => {
let res = '<' + tagname
const attrs = Object.keys(attributes).map(k => `${k}="${attributes[k]}"`).join(' ')
if (attrs) res += ' ' + attrs
res += '>'
return res
}
/**
* We need a custom xml serializer because salesfore escapes perfectly valid chars in xml (such as ' or ")
* and xml2js does not handle this weirdness
*/
const sfdcXmlBuilder = (tagname, value, isRoot = true, indentLevel = '') => {
let res = isRoot ? '<?xml version="1.0" encoding="UTF-8"?>\n' : ''
if (!Array.isArray(value)) value = [value]
const l = value.length
for (let i = 0; i < l; i++) {
const isObject = typeof (value[i]) === 'object' && !Object.prototype.hasOwnProperty.call(value[i], '_')
res += indentLevel + buildTag(tagname, value[i].$ || {})
delete value[i].$
const serializedValue = serializeValue(tagname, value[i]._ || value[i], indentLevel + renderOpts.indent)
res += serializedValue
if (!serializedValue && renderOpts.emptyTag) res = res.replace(/>$/, '/>')
else res += (isObject ? indentLevel : '') + '</' + tagname + '>'
if (i < value.length - 1) res += '\n'
}
return res
}
module.exports = {
parseXml: parser,
parseXmlNoArray: noArrayParser,
buildXml: v => sfdcXmlBuilder(Object.keys(v)[0], Object.values(v)[0])
}