Skip to content

Commit

Permalink
streaming api
Browse files Browse the repository at this point in the history
  • Loading branch information
dodo committed Apr 30, 2011
1 parent d8dba2d commit 9b94dba
Showing 1 changed file with 143 additions and 30 deletions.
173 changes: 143 additions & 30 deletions lib/xml.js
@@ -1,20 +1,102 @@
var util = require('./util');
var Stream = require('stream').Stream;

var DEFAULT_INDENT = ' ';

function xml (input, indent) {
var output = [];
function xml (input, indent, use_stream) {
var stream;
var output = "";
var interupted = false;

indent = !indent ? '' : indent === true ? DEFAULT_INDENT : indent;

if (use_stream)
stream = new Stream();

var instant = true,
delay = function (func) {
if (!instant) {
func();
} else {
process.nextTick(func);
}
};
// disable delay delayed
delay(function () { instant = false });

var append = function (interupt, out) {
if (out !== undefined) {
output += out;
}
if (interupt && !interupted) {
stream = stream || new Stream();
interupted = true;
}
if (interupt && interupted) {
var data = output;
delay(function () { stream.emit('data', data) });
output = "";
}
};

var add = function (value, last) {
format(append, resolve(value, indent, indent ? 1 : 0), last);
};

var end = function () {
if (stream) {
var data = output;
delay(function () { stream.emit('data', data) });

stream.emit('end');
stream.readable = false;
stream.emit('close');
}
};

if (input && input.forEach) {
input.forEach(function(value){
output.push(format(resolve(value, indent, indent ? 1 : 0)));
input.forEach(function (value, i) {
var last;
if (i + 1 == input.length)
last = end;
add(value, last);
});
} else {
output.push(format(resolve(input, indent, indent ? 1 : 0)));
add(input, end);
}

if (stream) {
stream.readable = true;
return stream;
}
return output.join(indent ? '\n' : '');
return output;
}

function element (/*input, …*/) {
var input = Array.prototype.slice.call(arguments);
var self = { _elem:resolve(input) };

self.push = function (input) {
if (!this.append) {
throw new Error("not assigned to a parent!");
}
var that = this;
var indent = this._elem.indent;
format(this.append, resolve(
input, indent, this._elem.icount + (indent ? 1 : 0)),
function () { that.append(true) });
};

self.close = function (input) {
if (input !== undefined) {
this.push(input);
}
if (this.end) {
this.end();
}
};

return self;
}

function create_indent(character, count) {
Expand All @@ -26,11 +108,21 @@ function resolve(data, indent, indent_count) {
var indent_spaces = create_indent(indent, indent_count);
var name;
var values = data;
var interupt = false;

if (typeof data == 'object') {
var keys = Object.keys(data);
name = keys[0];
values = data[name];

if (values._elem) {
values._elem.name = name;
values._elem.icount = indent_count;
values._elem.indent = indent;
values._elem.indents = indent_spaces;
values._elem.interupt = values;
return values._elem;
}
}

var attributes = [],
Expand All @@ -41,7 +133,6 @@ function resolve(data, indent, indent_count) {
keys.forEach(function(key){
attributes.push(attribute(key, obj[key]));
});

}

switch(typeof values) {
Expand All @@ -65,11 +156,13 @@ function resolve(data, indent, indent_count) {
if (_name == '_attr') {
get_attributes(value._attr);
} else {
content.push(resolve(value, indent, indent_count + 1));
content.push(resolve(
value, indent, indent_count + 1));
}
} else {
//string
content.push(create_indent(indent, indent_count + 1) + util.xml_safe(value));
content.push(create_indent(
indent, indent_count + 1) + util.xml_safe(value));
}

});
Expand All @@ -84,40 +177,60 @@ function resolve(data, indent, indent_count) {
}

return { name: name,
interupt: interupt,
attributes: attributes,
content: content,
icount: indent_count,
indents: indent_spaces,
indent: indent };
}

function format(elem) {
if (typeof elem != 'object')
return elem;
function format(append, elem, end) {
if (typeof elem != 'object') {
return append(false, elem);
}

var len = elem.content.length;
var output = elem.indents
var len = elem.interupt ? 1 : elem.content.length;
append(false, elem.indents
+ (elem.name ? '<' + elem.name : '')
+ (elem.attributes.length ? ' ' + elem.attributes.join(' ') : '')
+ (len ? (elem.name ? '>' : '') : (elem.name ? '/>' : ''));

if (!len)
return output;

var first = true;
while (elem.content.length) {
var value = elem.content.shift();
if (value === undefined)
continue;
output += (elem.indent && !first ? '\n' : '') + format(value);
first = false;
}

return output + (len > 1 ? elem.indents : '')
+ (elem.name ? '</' + elem.name + '>' : '');
+ (len ? (elem.name ? '>' : '') : (elem.name ? '/>' : ''))
+ (elem.indent && len > 1 ? '\n' : ''));

if (!len) return append(false, elem.indent ? '\n' : '');

var interupt, proceed = function () {
while (elem.content.length) {
var value = elem.content.shift();

if (value === undefined) continue;
if (interupt(value)) return;

format(append, value);
}
append(false, (len > 1 ? elem.indents : '')
+ (elem.name ? '</' + elem.name + '>' : '')
+ (elem.indent && !end ? '\n' : ''));
if (end) end();
};

interupt = function (value) {
if (value.interupt) {
value.interupt.append = append;
value.interupt.end = proceed;
value.interupt = false;
append(true);
return true;
}
return false;
};

if (!interupt(elem)) proceed();
}

function attribute(key, value) {
return key + '=' + '"' + util.xml_safe(value) + '"';
}

xml.Element = element;
module.exports = xml;

0 comments on commit 9b94dba

Please sign in to comment.