source: node_modules/xml/lib/xml.js@ 65b6638

main
Last change on this file since 65b6638 was d24f17c, checked in by Aleksandar Panovski <apano77@…>, 15 months ago

Initial commit

  • Property mode set to 100644
File size: 7.0 KB
Line 
1var escapeForXML = require('./escapeForXML');
2var Stream = require('stream').Stream;
3
4var DEFAULT_INDENT = ' ';
5
6function xml(input, options) {
7
8 if (typeof options !== 'object') {
9 options = {
10 indent: options
11 };
12 }
13
14 var stream = options.stream ? new Stream() : null,
15 output = "",
16 interrupted = false,
17 indent = !options.indent ? ''
18 : options.indent === true ? DEFAULT_INDENT
19 : options.indent,
20 instant = true;
21
22
23 function delay (func) {
24 if (!instant) {
25 func();
26 } else {
27 process.nextTick(func);
28 }
29 }
30
31 function append (interrupt, out) {
32 if (out !== undefined) {
33 output += out;
34 }
35 if (interrupt && !interrupted) {
36 stream = stream || new Stream();
37 interrupted = true;
38 }
39 if (interrupt && interrupted) {
40 var data = output;
41 delay(function () { stream.emit('data', data) });
42 output = "";
43 }
44 }
45
46 function add (value, last) {
47 format(append, resolve(value, indent, indent ? 1 : 0), last);
48 }
49
50 function end() {
51 if (stream) {
52 var data = output;
53 delay(function () {
54 stream.emit('data', data);
55 stream.emit('end');
56 stream.readable = false;
57 stream.emit('close');
58 });
59 }
60 }
61
62 function addXmlDeclaration(declaration) {
63 var encoding = declaration.encoding || 'UTF-8',
64 attr = { version: '1.0', encoding: encoding };
65
66 if (declaration.standalone) {
67 attr.standalone = declaration.standalone
68 }
69
70 add({'?xml': { _attr: attr } });
71 output = output.replace('/>', '?>');
72 }
73
74 // disable delay delayed
75 delay(function () { instant = false });
76
77 if (options.declaration) {
78 addXmlDeclaration(options.declaration);
79 }
80
81 if (input && input.forEach) {
82 input.forEach(function (value, i) {
83 var last;
84 if (i + 1 === input.length)
85 last = end;
86 add(value, last);
87 });
88 } else {
89 add(input, end);
90 }
91
92 if (stream) {
93 stream.readable = true;
94 return stream;
95 }
96 return output;
97}
98
99function element (/*input, …*/) {
100 var input = Array.prototype.slice.call(arguments),
101 self = {
102 _elem: resolve(input)
103 };
104
105 self.push = function (input) {
106 if (!this.append) {
107 throw new Error("not assigned to a parent!");
108 }
109 var that = this;
110 var indent = this._elem.indent;
111 format(this.append, resolve(
112 input, indent, this._elem.icount + (indent ? 1 : 0)),
113 function () { that.append(true) });
114 };
115
116 self.close = function (input) {
117 if (input !== undefined) {
118 this.push(input);
119 }
120 if (this.end) {
121 this.end();
122 }
123 };
124
125 return self;
126}
127
128function create_indent(character, count) {
129 return (new Array(count || 0).join(character || ''))
130}
131
132function resolve(data, indent, indent_count) {
133 indent_count = indent_count || 0;
134 var indent_spaces = create_indent(indent, indent_count);
135 var name;
136 var values = data;
137 var interrupt = false;
138
139 if (typeof data === 'object') {
140 var keys = Object.keys(data);
141 name = keys[0];
142 values = data[name];
143
144 if (values && values._elem) {
145 values._elem.name = name;
146 values._elem.icount = indent_count;
147 values._elem.indent = indent;
148 values._elem.indents = indent_spaces;
149 values._elem.interrupt = values;
150 return values._elem;
151 }
152 }
153
154 var attributes = [],
155 content = [];
156
157 var isStringContent;
158
159 function get_attributes(obj){
160 var keys = Object.keys(obj);
161 keys.forEach(function(key){
162 attributes.push(attribute(key, obj[key]));
163 });
164 }
165
166 switch(typeof values) {
167 case 'object':
168 if (values === null) break;
169
170 if (values._attr) {
171 get_attributes(values._attr);
172 }
173
174 if (values._cdata) {
175 content.push(
176 ('<![CDATA[' + values._cdata).replace(/\]\]>/g, ']]]]><![CDATA[>') + ']]>'
177 );
178 }
179
180 if (values.forEach) {
181 isStringContent = false;
182 content.push('');
183 values.forEach(function(value) {
184 if (typeof value == 'object') {
185 var _name = Object.keys(value)[0];
186
187 if (_name == '_attr') {
188 get_attributes(value._attr);
189 } else {
190 content.push(resolve(
191 value, indent, indent_count + 1));
192 }
193 } else {
194 //string
195 content.pop();
196 isStringContent=true;
197 content.push(escapeForXML(value));
198 }
199
200 });
201 if (!isStringContent) {
202 content.push('');
203 }
204 }
205 break;
206
207 default:
208 //string
209 content.push(escapeForXML(values));
210
211 }
212
213 return {
214 name: name,
215 interrupt: interrupt,
216 attributes: attributes,
217 content: content,
218 icount: indent_count,
219 indents: indent_spaces,
220 indent: indent
221 };
222}
223
224function format(append, elem, end) {
225
226 if (typeof elem != 'object') {
227 return append(false, elem);
228 }
229
230 var len = elem.interrupt ? 1 : elem.content.length;
231
232 function proceed () {
233 while (elem.content.length) {
234 var value = elem.content.shift();
235
236 if (value === undefined) continue;
237 if (interrupt(value)) return;
238
239 format(append, value);
240 }
241
242 append(false, (len > 1 ? elem.indents : '')
243 + (elem.name ? '</' + elem.name + '>' : '')
244 + (elem.indent && !end ? '\n' : ''));
245
246 if (end) {
247 end();
248 }
249 }
250
251 function interrupt(value) {
252 if (value.interrupt) {
253 value.interrupt.append = append;
254 value.interrupt.end = proceed;
255 value.interrupt = false;
256 append(true);
257 return true;
258 }
259 return false;
260 }
261
262 append(false, elem.indents
263 + (elem.name ? '<' + elem.name : '')
264 + (elem.attributes.length ? ' ' + elem.attributes.join(' ') : '')
265 + (len ? (elem.name ? '>' : '') : (elem.name ? '/>' : ''))
266 + (elem.indent && len > 1 ? '\n' : ''));
267
268 if (!len) {
269 return append(false, elem.indent ? '\n' : '');
270 }
271
272 if (!interrupt(elem)) {
273 proceed();
274 }
275}
276
277function attribute(key, value) {
278 return key + '=' + '"' + escapeForXML(value) + '"';
279}
280
281module.exports = xml;
282module.exports.element = module.exports.Element = element;
Note: See TracBrowser for help on using the repository browser.