pax_global_header 0000666 0000000 0000000 00000000064 11733163136 0014516 g ustar 00root root 0000000 0000000 52 comment=f68025ee9134e7b4ccb440772f55146ea3470483
astro-ltx-f68025e/ 0000775 0000000 0000000 00000000000 11733163136 0014014 5 ustar 00root root 0000000 0000000 astro-ltx-f68025e/.travis.yml 0000664 0000000 0000000 00000000053 11733163136 0016123 0 ustar 00root root 0000000 0000000 language: node_js
node_js:
- 0.4
- 0.6
astro-ltx-f68025e/LICENSE 0000664 0000000 0000000 00000002041 11733163136 0015016 0 ustar 00root root 0000000 0000000 Copyright (c) 2010 Stephan Maka
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
astro-ltx-f68025e/README.markdown 0000664 0000000 0000000 00000005656 11733163136 0016531 0 ustar 00root root 0000000 0000000 # Less-Than XML
* *Element:* any XML Element
* Text nodes are Strings
* Runs on node.js and browserify
## Parsing
### DOM
Parse a little document at once:
el = ltx.parse("")
Push parser:
p = new ltx.Parser();
p.on('tree', function(tree) {
proceed(null, tree);
});
p.on('error', function(error) {
proceed(error);
});
### SAX
ltx implements multiple SAX backends:
* *node-expat*: libexpat binding
* *ltx*: fast native-JavaScript parser without error handling
* *saxjs*: native-JavaScript parser
If present, they are available through
`ltx.availableSaxParsers`. Mostly, you'll want to do:
parser = new ltx.bestSaxParser();
Refer to `lib/parse.js` for the interface.
## Element traversal
* `is(name, xmlns?)`: check
* `getName()`: name without ns prefix
* `getNS()`: element's xmlns, respects prefixes and searches upwards
* `findNS(prefix?)`: search for xmlns of a prefix upwards
* `getChild(name, xmlns?)`: find first child
* `getChildren(name, xmlns?)`: find all children
* `getChildByAttr(attr, value, xmlns?)`: find first child by a specific attribute
* `getChildrenByAttr(attr, value, xmlns?)`: find all children by a specific attribute
* `getText()`: appends all text nodes recursively
* `getChildText(name)`: a child's text contents
* `root()`: uppermost parent in the tree
* `up()`: parent or self
## Element attributes
* `attrs` is an object of the Element's attributes
* `name` contains optional prefix, colon, name
* `parent` points to its parent, this should always be consistent with
children
* `children` is an Array of Strings and Elements
## Modifying XML Elements
* `new Element(name, attrs?)`: constructor
* `remove(child)`: remove child by reference
* `remove(name, xmlns)`: remove child by tag name and xmlns
* `attr(attrName, value?)`: modify or get an attribute's value
* `text(value?)`: modify or get the inner text
* `clone()`: clones an element that is detached from the document
## Building XML Elements
el = new ltx.Element('root').
c('children');
el.c('child', { age: 5 }).t('Hello').up()
.c('child', { age: 7 }).t('Hello').up()
.c('child', { age: 99 }).t('Hello').up()
console.log("Serialized document:", el.root().toString());
This resembles Strophejs a bit.
strophejs' XML Builder is very convenient for producing XMPP
stanzas. node-xmpp includes it in a much more primitive way: the
`c()`, `cnode()` and `t()` methods can be called on any *Element*
object, returning the child element.
This can be confusing: in the end, you will hold the last-added child
until you use `up()`, a getter for the parent. `Connection.send()`
first invokes `tree()` to retrieve the uppermost parent, the XMPP
stanza, before sending it out the wire.
## Destructive manipulation
Please always make sure `parent` and `children` are consistent. Don't
append children of other parents to your own element. We're not
adoption-safe!
## TODO
* More documentation
* More tests (Using [Vows](http://vowsjs.org/))
astro-ltx-f68025e/benchmark/ 0000775 0000000 0000000 00000000000 11733163136 0015746 5 ustar 00root root 0000000 0000000 astro-ltx-f68025e/benchmark/.gitignore 0000664 0000000 0000000 00000000011 11733163136 0017726 0 ustar 00root root 0000000 0000000 index.js
astro-ltx-f68025e/benchmark/benchmark.js 0000664 0000000 0000000 00000007015 11733163136 0020241 0 ustar 00root root 0000000 0000000 if (process.title === 'browser') {
var ltx = require("ltx");
var strophe = require('Strophe.js');
var requestAnimationFrame = require('request-animation-frame').requestAnimationFrame;
} else {
var path = "../lib/index";
var ltx = require(path);
}
var util = require('util');
function now() {
return new Date().getTime();
}
function Test() {
this.timings = {};
}
Test.prototype = {
record: function(name, fun) {
var t1 = now();
var res = fun();
var t2 = now();
if (!this.timings.hasOwnProperty(name))
this.timings[name] = { i: 0, t: 0 };
this.timings[name].i++;
this.timings[name].t += t2 - t1;
},
report: function() {
if (process.title === 'browser') {
var s = [];
var html = "
" + this.name + "
";
for(var k in this.timings) {
var t = this.timings[k].t / this.timings[k].i;
html += "- " + k + "
- " + t + " ms
";
}
html += "
\n";
return html;
} else {
var s = this.name + "\t";
for(k in this.timings) {
var t = this.timings[k].t / this.timings[k].i;
s += k + ": " + t + " ms\t";
}
return s;
}
}
};
function LtxTest(saxParser) {
Test.call(this);
this.saxParser = saxParser;
this.name = "LTX/" + saxParser.name;
}
util.inherits(LtxTest, Test);
LtxTest.prototype.parse = function(s) {
return ltx.parse(s, this.saxParser);
};
LtxTest.prototype.serialize = function(el) {
return el.toString();
};
LtxTest.prototype.traverse = function(node) {
while(node.children && node.children[0])
node = node.children[0];
};
function StropheTest() {
Test.call(this);
this.serialize = Strophe.serialize;
}
util.inherits(StropheTest, Test);
StropheTest.prototype.name = "Strophe.js";
StropheTest.prototype.parse = function(s) {
return Strophe.xmlHtmlNode(s).firstChild;
};
StropheTest.prototype.traverse = function(node) {
while(node.firstChild)
node = node.firstChild;
};
var tests = ltx.availableSaxParsers.map(function(saxParser) {
return new LtxTest(saxParser);
});
if (process.title === 'browser')
tests.push(new StropheTest());
var messages = [
"",
"",
"fnordfnord"
];
messages[3] = "";
for(var i = 0; i < 10; i++) {
messages[3] += "fnord fnord fnord";
}
for(var i = 0; i < 10; i++) {
messages[3] += "fnordfnordfnordfnord";
}
messages[3] += "";
var iteration = 0;
function runTests() {
iteration++;
tests.forEach(function(test) {
for(var j = 0; j < messages.length; j++) {
var parsed, serialized;
test.record('parse' + j, function() {
parsed = test.parse(messages[j]);
});
test.record('serialize' + j, function() {
serialized = test.serialize(parsed);
});
test.record('traverse' + j, function() {
test.traverse(parsed);
});
}
});
if (process.title === 'browser') {
document.body.innerHTML = "\n" +
"Iteration " + iteration + "\n";
tests.forEach(function(test) {
document.body.innerHTML += test.report() + "
";
});
requestAnimationFrame(runTests);
} else {
console.log("Iteration " + iteration);
tests.forEach(function(test) {
console.log(test.report());
});
process.nextTick(runTests);
}
}
setTimeout(function() {
runTests();
}, 1000);
astro-ltx-f68025e/benchmark/build.js 0000664 0000000 0000000 00000000554 11733163136 0017407 0 ustar 00root root 0000000 0000000 var browserify = require('browserify');
var path = require('path');
var b = browserify({
debug: true
});
var root = path.join(__dirname, "..");
b.require("./lib/index-browserify.js",
{ root: root, basedir: root });
b.alias("ltx", "./lib/index-browserify.js");
b.addEntry('benchmark.js');
var fs = require('fs');
fs.writeFileSync('index.js', b.bundle());
astro-ltx-f68025e/benchmark/index.html 0000664 0000000 0000000 00000000153 11733163136 0017742 0 ustar 00root root 0000000 0000000
astro-ltx-f68025e/index.js 0000664 0000000 0000000 00000000054 11733163136 0015460 0 ustar 00root root 0000000 0000000 module.exports = require('./lib/index.js');
astro-ltx-f68025e/lib/ 0000775 0000000 0000000 00000000000 11733163136 0014562 5 ustar 00root root 0000000 0000000 astro-ltx-f68025e/lib/element.js 0000664 0000000 0000000 00000015207 11733163136 0016556 0 ustar 00root root 0000000 0000000 /**
* This cheap replica of DOM/Builder puts me to shame :-)
*
* Attributes are in the element.attrs object. Children is a list of
* either other Elements or Strings for text content.
**/
function Element(name, attrs) {
this.name = name;
this.parent = null;
this.attrs = attrs || {};
this.children = [];
}
/*** Accessors ***/
/**
* if (element.is('message', 'jabber:client')) ...
**/
Element.prototype.is = function(name, xmlns) {
return this.getName() == name &&
(!xmlns || this.getNS() == xmlns);
};
/* without prefix */
Element.prototype.getName = function() {
if (this.name.indexOf(":") >= 0)
return this.name.substr(this.name.indexOf(":") + 1);
else
return this.name;
};
/**
* retrieves the namespace of the current element, upwards recursively
**/
Element.prototype.getNS = function() {
if (this.name.indexOf(":") >= 0) {
var prefix = this.name.substr(0, this.name.indexOf(":"));
return this.findNS(prefix);
} else {
return this.findNS();
}
};
/**
* find the namespace to the given prefix, upwards recursively
**/
Element.prototype.findNS = function(prefix) {
if (!prefix) {
/* default namespace */
if (this.attrs.xmlns)
return this.attrs.xmlns;
else if (this.parent)
return this.parent.findNS();
} else {
/* prefixed namespace */
var attr = 'xmlns:' + prefix;
if (this.attrs[attr])
return this.attrs[attr];
else if (this.parent)
return this.parent.findNS(prefix);
}
};
/**
* xmlns can be null
**/
Element.prototype.getChild = function(name, xmlns) {
return this.getChildren(name, xmlns)[0];
};
/**
* xmlns can be null
**/
Element.prototype.getChildren = function(name, xmlns) {
var result = [];
for(var i = 0; i < this.children.length; i++) {
var child = this.children[i];
if (child.getName &&
child.getName() == name &&
(!xmlns || child.getNS() == xmlns))
result.push(child);
}
return result;
};
/**
* xmlns can be null
**/
Element.prototype.getChildByAttr = function(attr, val, xmlns) {
return this.getChildrenByAttr(attr, val, xmlns)[0];
};
/**
* xmlns can be null
**/
Element.prototype.getChildrenByAttr = function(attr, val, xmlns) {
var result = [];
for(var i = 0; i < this.children.length; i++) {
var child = this.children[i];
if (child.attrs &&
child.attrs[attr] == val &&
(!xmlns || child.getNS() == xmlns))
result.push(child);
}
return result;
};
Element.prototype.getText = function() {
var text = "";
for(var i = 0; i < this.children.length; i++) {
var child = this.children[i];
if (typeof child == 'string')
text += child;
}
return text;
};
Element.prototype.getChildText = function(name) {
var text = null;
for(var i = 0; i < this.children.length; i++) {
var child = this.children[i];
if (!text && child.name == name) {
text = child.getText();
}
}
return text;
};
/*** Builder ***/
/** returns uppermost parent */
Element.prototype.root = function() {
if (this.parent)
return this.parent.root();
else
return this;
};
Element.prototype.tree = Element.prototype.root;
/** just parent or itself */
Element.prototype.up = function() {
if (this.parent)
return this.parent;
else
return this;
};
/** create child node and return it */
Element.prototype.c = function(name, attrs) {
return this.cnode(new Element(name, attrs));
};
Element.prototype.cnode = function(child) {
this.children.push(child);
child.parent = this;
return child;
};
/** add text node and return element */
Element.prototype.t = function(text) {
this.children.push(text);
return this;
};
/*** Manipulation ***/
/**
* Either:
* el.remove(childEl);
* el.remove('author', 'urn:...');
*/
Element.prototype.remove = function(el, xmlns) {
var filter;
if (typeof el === 'string') {
/* 1st parameter is tag name */
filter = function(child) {
return !(child.is &&
child.is(el, xmlns));
};
} else {
/* 1st parameter is element */
filter = function(child) {
return child !== el;
};
}
this.children = this.children.filter(filter);
return this;
};
/**
* To use in case you want the same XML data for separate uses.
* Please refrain from this practise unless you know what you are
* doing. Building XML with ltx is easy!
*/
Element.prototype.clone = function() {
var clone = new Element(this.name, {});
for(var k in this.attrs) {
if (this.attrs.hasOwnProperty(k))
clone.attrs[k] = this.attrs[k];
}
for(var i = 0; i < this.children.length; i++) {
var child = this.children[i];
clone.cnode(child.clone ? child.clone() : child);
}
return clone;
};
Element.prototype.text = function(val) {
if(val && this.children.length == 1){
this.children[0] = val;
return this;
}
return this.getText();
};
Element.prototype.attr = function(attr, val) {
if(val){
if(!this.attrs){
this.attrs = {};
}
this.attrs[attr] = val;
return this;
}
return this.attrs[attr];
};
/*** Serialization ***/
Element.prototype.toString = function() {
var s = "";
this.write(function(c) {
s += c;
});
return s;
};
Element.prototype.write = function(writer) {
writer("<");
writer(this.name);
for(var k in this.attrs) {
var v = this.attrs[k];
if (v || v === '' || v === 0) {
writer(" ");
writer(k);
writer("=\"");
if (typeof v != 'string')
v = v.toString();
writer(escapeXml(v));
writer("\"");
}
}
if (this.children.length == 0) {
writer("/>");
} else {
writer(">");
for(var i = 0; i < this.children.length; i++) {
var child = this.children[i];
/* Skip null/undefined */
if (child || child === 0) {
if (child.write)
child.write(writer);
else if (typeof child === 'string')
writer(escapeXmlText(child));
else if (child.toString)
writer(escapeXmlText(child.toString()));
}
}
writer("");
writer(this.name);
writer(">");
}
};
function escapeXml(s) {
return s.
replace(/\&/g, '&').
replace(//g, '>').
replace(/"/g, '"').
replace(/'/g, ''');
}
function escapeXmlText(s) {
return s.
replace(/\&/g, '&').
replace(//g, '>');
}
exports.Element = Element;
exports.escapeXml = escapeXml;
astro-ltx-f68025e/lib/index-browserify.js 0000664 0000000 0000000 00000000252 11733163136 0020417 0 ustar 00root root 0000000 0000000 /* Cause browserify to bundle SAX parsers: */
//require('./sax_easysax');
//require('./sax_saxjs');
require('./sax_ltx');
/* SHIM */
module.exports = require('./index'); astro-ltx-f68025e/lib/index.js 0000664 0000000 0000000 00000000662 11733163136 0016233 0 ustar 00root root 0000000 0000000 var element = require('./element');
var parse = require('./parse');
/**
* The only (relevant) data structure
*/
exports.Element = element.Element;
/**
* Helper
*/
exports.escapeXml = element.escapeXml;
/**
* DOM parser interface
*/
exports.parse = parse.parse;
exports.Parser = parse.Parser;
/**
* SAX parser interface
*/
exports.availableSaxParsers = parse.availableSaxParsers;
exports.bestSaxParser = parse.bestSaxParser;
astro-ltx-f68025e/lib/parse.js 0000664 0000000 0000000 00000004422 11733163136 0016234 0 ustar 00root root 0000000 0000000 var events = require('events');
var util = require('util');
exports.availableSaxParsers = [];
exports.bestSaxParser = null;
['./sax_expat.js', './sax_ltx.js', /*'./sax_easysax.js', './sax_node-xml.js',*/ './sax_saxjs.js'].forEach(function(modName) {
var mod;
try {
mod = require(modName);
} catch (e) {
/* Silently missing libraries drop; for debug:
console.error(e.stack || e);
*/
}
if (mod) {
exports.availableSaxParsers.push(mod);
if (!exports.bestSaxParser)
exports.bestSaxParser = mod;
}
});
var element = require('./element');
exports.Parser = function(saxParser) {
events.EventEmitter.call(this);
var that = this;
var parserMod = saxParser || exports.bestSaxParser;
if (!parserMod)
throw new Error("No SAX parser available");
this.parser = new parserMod();
var el;
this.parser.addListener('startElement', function(name, attrs) {
var child = new element.Element(name, attrs);
if (!el) {
el = child;
} else {
el = el.cnode(child);
}
});
this.parser.addListener('endElement', function(name) {
if (!el) {
/* Err */
} else if (el && name == el.name) {
if (el.parent)
el = el.parent;
else if (!that.tree) {
that.tree = el;
el = undefined;
}
}
});
this.parser.addListener('text', function(str) {
if (el)
el.t(str);
});
this.parser.addListener('error', function(e) {
that.error = e;
that.emit('error', e);
});
};
util.inherits(exports.Parser, events.EventEmitter);
exports.Parser.prototype.write = function(data) {
this.parser.write(data);
};
exports.Parser.prototype.end = function(data) {
this.parser.end(data);
if (!this.error) {
if (this.tree)
this.emit('tree', this.tree);
else
this.emit('error', new Error('Incomplete document'));
}
};
exports.parse = function(data, saxParser) {
var p = new exports.Parser(saxParser);
var result = null, error = null;
p.on('tree', function(tree) {
result = tree;
});
p.on('error', function(e) {
error = e;
});
p.write(data);
p.end();
if (error)
throw error;
else
return result;
};
astro-ltx-f68025e/lib/sax_easysax.js 0000664 0000000 0000000 00000002311 11733163136 0017445 0 ustar 00root root 0000000 0000000 var util = require('util');
var events = require('events');
var Easysax = require('easysax');
/**
* FIXME: This SAX parser cannot be pushed to!
*/
var SaxEasysax = module.exports = function SaxEasysax() {
events.EventEmitter.call(this);
this.parser = new Easysax();
var that = this;
this.parser.on('startNode', function(name, attr, uq, str, tagend) {
attr = attr();
for(var k in attr)
if (attr.hasOwnProperty(k)) {
attr[k] = uq(attr[k]);
}
that.emit('startElement', name, attr);
});
this.parser.on('endNode', function(name, uq, str, tagstart) {
that.emit('endElement', name);
});
this.parser.on('textNode', function(str, uq) {
that.emit('text', uq(str));
});
this.parser.on('cdata', function(str) {
that.emit('text', str);
});
this.parser.on('error', function(e) {
that.emit('error', e);
});
// TODO: other events, esp. entityDecl (billion laughs!)
};
util.inherits(SaxEasysax, events.EventEmitter);
SaxEasysax.prototype.write = function(data) {
if (typeof data !== 'string')
data = data.toString();
this.parser.parse(data);
};
SaxEasysax.prototype.end = function(data) {
if (data)
this.write(data);
};
astro-ltx-f68025e/lib/sax_expat.js 0000664 0000000 0000000 00000002172 11733163136 0017116 0 ustar 00root root 0000000 0000000 var util = require('util');
var events = require('events');
var expat = require('node-expat');
var SaxExpat = module.exports = function SaxExpat() {
events.EventEmitter.call(this);
this.parser = new expat.Parser('UTF-8');
var that = this;
this.parser.on('startElement', function(name, attrs) {
that.emit('startElement', name, attrs);
});
this.parser.on('endElement', function(name) {
that.emit('endElement', name);
});
this.parser.on('text', function(str) {
that.emit('text', str);
});
// TODO: other events, esp. entityDecl (billion laughs!)
};
util.inherits(SaxExpat, events.EventEmitter);
SaxExpat.prototype.write = function(data) {
if (!this.parser.parse(data, false)) {
this.emit('error', new Error(this.parser.getError()));
// Premature error thrown,
// disable all functionality:
this.write = function() { };
this.end = function() { };
}
};
SaxExpat.prototype.end = function(data) {
if (!this.parser.parse('', true))
this.emit('error', new Error(this.parser.getError()));
else
this.emit('end');
};
astro-ltx-f68025e/lib/sax_ltx.js 0000664 0000000 0000000 00000007102 11733163136 0016602 0 ustar 00root root 0000000 0000000 var util = require('util');
var events = require('events');
const STATE_TEXT = 0,
STATE_IGNORE_TAG = 1,
STATE_TAG_NAME = 2,
STATE_TAG = 3,
STATE_ATTR_NAME = 4,
STATE_ATTR_EQ = 5,
STATE_ATTR_QUOT = 6,
STATE_ATTR_VALUE = 7;
var RE_TAG_NAME = /^[^\s\/>]+$/,
RE_ATTR_NAME = /^[^\s=]+$/;
var SaxLtx = module.exports = function SaxLtx() {
events.EventEmitter.call(this);
var state = STATE_TEXT, remainder;
var tagName, attrs, endTag, selfClosing, attrQuote;
var recordStart = 0;
this.write = function(data) {
if (typeof data !== 'string')
data = data.toString();
var pos = 0;
/* Anything from previous write()? */
if (remainder) {
data = remainder + data;
pos += remainder.length;
delete remainder;
}
function endRecording() {
if (typeof recordStart === 'number') {
var recorded = data.slice(recordStart, pos);
recordStart = undefined;
return recorded;
}
}
for(; pos < data.length; pos++) {
var c = data.charCodeAt(pos);
//console.log("state", state, "c", c, data[pos]);
switch(state) {
case STATE_TEXT:
if (c === 60 /* < */) {
var text = endRecording();
if (text)
this.emit('text', unescapeXml(text));
state = STATE_TAG_NAME;
recordStart = pos + 1;
attrs = {};
}
break;
case STATE_TAG_NAME:
if (c === 47 /* / */ && recordStart === pos) {
recordStart = pos + 1;
endTag = true;
} else if (c === 33 /* ! */ || c === 63 /* ? */) {
recordStart = undefined;
state = STATE_IGNORE_TAG;
} else if (c <= 32 || c === 47 /* / */ || c === 62 /* > */) {
tagName = endRecording();
pos--;
state = STATE_TAG;
}
break;
case STATE_IGNORE_TAG:
if (c === 62 /* > */) {
state = STATE_TEXT;
}
break;
case STATE_TAG:
if (c === 62 /* > */) {
if (!endTag) {
this.emit('startElement', tagName, attrs);
if (selfClosing)
this.emit('endElement', tagName);
} else
this.emit('endElement', tagName);
tagName = undefined;
attrs = undefined;
endTag = undefined;
selfClosing = undefined;
state = STATE_TEXT;
recordStart = pos + 1;
} else if (c === 47 /* / */) {
selfClosing = true;
} else if (c > 32) {
recordStart = pos;
state = STATE_ATTR_NAME;
}
break;
case STATE_ATTR_NAME:
if (c <= 32 || c === 61 /* = */) {
attrName = endRecording();
pos--;
state = STATE_ATTR_EQ;
}
break;
case STATE_ATTR_EQ:
if (c === 61 /* = */) {
state = STATE_ATTR_QUOT;
}
break;
case STATE_ATTR_QUOT:
if (c === 34 /* " */ || c === 39 /* ' */) {
attrQuote = c;
state = STATE_ATTR_VALUE;
recordStart = pos + 1;
}
break;
case STATE_ATTR_VALUE:
if (c === attrQuote) {
var value = unescapeXml(endRecording());
attrs[attrName] = value;
attrName = undefined;
state = STATE_TAG;
}
break;
}
}
if (typeof recordStart === 'number' &&
recordStart <= data.length) {
remainder = data.slice(recordStart);
recordStart = 0;
}
};
/*var origEmit = this.emit;
this.emit = function() {
console.log('ltx', arguments);
origEmit.apply(this, arguments);
};*/
};
util.inherits(SaxLtx, events.EventEmitter);
SaxLtx.prototype.end = function(data) {
if (data)
this.write(data);
/* Uh, yeah */
this.write = function() {
};
};
function unescapeXml(s) {
return s.
replace(/\&/g, '&').
replace(/\</g, '<').
replace(/\>/g, '>').
replace(/\"/g, '"').
replace(/\'/g, '\'');
}
astro-ltx-f68025e/lib/sax_node-xml.js 0000664 0000000 0000000 00000003255 11733163136 0017523 0 ustar 00root root 0000000 0000000 var util = require('util');
var events = require('events');
var xml = require('node-xml');
/**
* This cannot be used as long as node-xml starts parsing only after
* setTimeout(f, 0);
*/
var SaxNodeXML = module.exports = function SaxNodeXML() {
events.EventEmitter.call(this);
var that = this;
this.parser = new xml.SaxParser(function(handler) {
handler.onStartElementNS(function(elem, attrs, prefix, uri, namespaces) {
var i, attrsHash = {};
if (prefix)
elem = prefix + ":" + elem;
for(i = 0; i < attrs.length; i++) {
var attr = attrs[i];
attrsHash[attr[0]] = unescapeXml(attr[1]);
}
for(i = 0; i < namespaces.length; i++) {
var namespace = namespaces[i];
var k = !namespace[0] ? "xmlns" : "xmlns:" + namespace[0];
attrsHash[k] = unescapeXml(namespace[1]);
}
that.emit('startElement', elem, attrsHash);
});
handler.onEndElementNS(function(elem, prefix, uri) {
if (prefix)
elem = prefix + ":" + elem;
that.emit('endElement', elem);
});
handler.onCharacters(function(str) {
that.emit('text', str);
});
handler.onCdata(function(str) {
that.emit('text', str);
});
handler.onError(function(e) {
that.emit('error', e);
});
// TODO: other events, esp. entityDecl (billion laughs!)
});
};
util.inherits(SaxNodeXML, events.EventEmitter);
SaxNodeXML.prototype.write = function(data) {
this.parser.parseString(data);
};
SaxNodeXML.prototype.end = function(data) {
if (data)
this.write(data);
};
function unescapeXml(s) {
return s.
replace(/\&/g, '&').
replace(/\</g, '<').
replace(/\>/g, '>').
replace(/\"/g, '"').
replace(/\'/g, '\'');
}
astro-ltx-f68025e/lib/sax_saxjs.js 0000664 0000000 0000000 00000002001 11733163136 0017114 0 ustar 00root root 0000000 0000000 var util = require('util');
var events = require('events');
var sax = require('sax');
var SaxSaxjs = module.exports = function SaxSaxjs() {
events.EventEmitter.call(this);
this.parser = sax.parser(true);
var that = this;
this.parser.onopentag = function(a) {
that.emit('startElement', a.name, a.attributes);
};
this.parser.onclosetag = function(name) {
that.emit('endElement', name);
};
this.parser.ontext = function(str) {
that.emit('text', str);
};
this.parser.onend = function() {
that.emit('end');
};
this.parser.onerror = function(e) {
that.emit('error', e);
};
// TODO: other events, esp. entityDecl (billion laughs!)
};
util.inherits(SaxSaxjs, events.EventEmitter);
SaxSaxjs.prototype.write = function(data) {
if (typeof data !== 'string')
data = data.toString();
this.parser.write(data);
};
SaxSaxjs.prototype.end = function(data) {
if (data)
this.parser.write(data);
this.parser.close();
};
astro-ltx-f68025e/package.json 0000664 0000000 0000000 00000001652 11733163136 0016306 0 ustar 00root root 0000000 0000000 { "name": "ltx"
,"version": "0.2.0"
,"main": "./lib/index"
,"browserify": "./lib/index-browserify.js"
,"description": ""
,"author": "Stephan Maka"
,"dependencies": {"node-expat": ">=1.2.0"
,"sax": ">=0.3.5"
}
,"repositories": [{"type": "git"
,"path": "http://github.com/astro/ltx.git"
}]
,"homepage": "http://github.com/astro/ltx"
,"bugs": "http://github.com/astro/ltx/issues"
,"maintainers": [{"name": "Astro"
,"email": "astro@spaceboyz.net"
,"web": "http://spaceboyz.net/~astro/"
}]
,"contributors": ["Stephan Maka", "Will Fife", "Markus Kohlhase"]
,"licenses": [{"type": "MIT"}]
,"engine": "node"
,"devDependencies": {"vows": ">=0.5.12"
,"easysax": ">=0.1.7"
,"node-xml": ">=1.0.1"
,"Strophe.js": "https://github.com/metajack/strophejs/tarball/master"
,"request-animation-frame": ">=0.1.0"
,"browserify": ">=1.10.4"
}
,"scripts": {"test":"vows --spec"}
}
astro-ltx-f68025e/test/ 0000775 0000000 0000000 00000000000 11733163136 0014773 5 ustar 00root root 0000000 0000000 astro-ltx-f68025e/test/element-test.js 0000664 0000000 0000000 00000010314 11733163136 0017736 0 ustar 00root root 0000000 0000000 var vows = require('vows'),
assert = require('assert'),
ltx = require('./../lib/index');
vows.describe('ltx').addBatch({
'serialization': {
'serialize an element': function() {
var e = new ltx.Element('e');
assert.equal(e.toString(), '');
},
'serialize an element with attributes': function() {
var e = new ltx.Element('e',
{ a1: 'foo' });
assert.equal(e.toString(), '');
},
'serialize an element with attributes to entities': function() {
var e = new ltx.Element('e',
{ a1: '"well"' });
assert.equal(e.toString(), '');
},
'serialize an element with text': function() {
var e = new ltx.Element('e').t('bar').root();
assert.equal(e.toString(), 'bar');
},
'serialize an element with text to entities': function() {
var e = new ltx.Element('e').t('1 < 2').root();
assert.equal(e.toString(), '1 < 2');
},
'serialize an element with a number attribute': function() {
var e = new ltx.Element('e', { a: 23 });
assert.equal(e.toString(), '');
},
'serialize an element with number contents': function() {
var e = new ltx.Element('e');
e.c('foo').t(23);
e.c('bar').t(0);
assert.equal(e.toString(), '230');
},
'serialize with undefined attribute': function() {
var e = new ltx.Element('e', { foo: undefined });
assert.equal(e.toString(), '');
},
'serialize with null attribute': function() {
var e = new ltx.Element('e', { foo: null });
assert.equal(e.toString(), '');
},
'serialize with number attribute': function() {
var e = new ltx.Element('e', { foo: 23, bar: 0 });
var s = e.toString();
assert.ok(s.match(/foo="23"/));
assert.ok(s.match(/bar="0"/));
},
'serialize with undefined child': function() {
var e = new ltx.Element('e');
e.children = [undefined];
assert.equal(e.toString(), '');
},
'serialize with null child': function() {
var e = new ltx.Element('e');
e.children = [null];
assert.equal(e.toString(), '');
}
},
'remove': {
'by element': function() {
var el = new ltx.Element('e').
c('c').c('x').up().up().
c('c2').up().
c('c').up();
el.remove(el.getChild('c'));
assert.equal(el.getChildren('c').length, 1);
assert.equal(el.getChildren('c2').length, 1);
},
'by name': function() {
var el = new ltx.Element('e').
c('c').up().
c('c2').up().
c('c').up();
el.remove('c');
assert.equal(el.getChildren('c').length, 0);
assert.equal(el.getChildren('c2').length, 1);
}
},
'clone': {
'clones': function() {
var orig = new ltx.Element('msg', { type: 'get' }).
c('content').t('foo').root();
var clone = orig.clone();
assert.equal(clone.name, orig.name);
assert.equal(clone.attrs.type, orig.attrs.type);
assert.equal(clone.attrs.to, orig.attrs.to);
assert.equal(clone.children.length, orig.children.length);
assert.equal(clone.getChildText('content'), orig.getChildText('content'));
assert.equal(orig.getChild('content').up(), orig);
assert.equal(clone.getChild('content').up(), clone);
},
'mod attr': function() {
var orig = new ltx.Element('msg', { type: 'get' });
var clone = orig.clone();
clone.attrs.type += '-result';
assert.equal(orig.attrs.type, 'get');
assert.equal(clone.attrs.type, 'get-result');
},
'rm attr': function() {
var orig = new ltx.Element('msg', { from: 'me' });
var clone = orig.clone();
delete clone.attrs.from;
clone.attrs.to = 'you';
assert.equal(orig.attrs.from, 'me');
assert.equal(orig.attrs.to, undefined);
assert.equal(clone.attrs.from, undefined);
assert.equal(clone.attrs.to, 'you');
},
'mod child': function() {
var orig = new ltx.Element('msg', { type: 'get' }).
c('content').t('foo').root();
var clone = orig.clone();
clone.getChild('content').
t('bar').
name = 'description';
assert.equal(orig.children[0].name, 'content');
assert.equal(orig.getChildText('content'), 'foo');
assert.equal(clone.children[0].name, 'description');
assert.equal(clone.getChildText('description'), 'foobar');
}
}
}).export(module);
astro-ltx-f68025e/test/parse-test.js 0000664 0000000 0000000 00000007721 11733163136 0017427 0 ustar 00root root 0000000 0000000 var vows = require('vows'),
assert = require('assert'),
ltx = require('./../lib/index');
ltx.availableSaxParsers.forEach(function(saxParser) {
var parse = function(s) {
return ltx.parse(s, saxParser);
};
vows.describe('ltx with ' + saxParser.name).addBatch({
'DOM parsing': {
'simple document': function() {
var el = parse('');
assert.equal(el.name, 'root');
assert.equal(0, el.children.length);
},
'text with commas': function() {
var el = parse("sa'sa'1'sasa");
assert.equal("sa'sa'1'sasa", el.getText());
},
'text with entities': function() {
var el = parse("<>&"'");
assert.equal("<>&\"'", el.getText());
},
'attribute with entities': function() {
var el = parse("");
assert.equal("<>&\"'", el.attrs.title);
},
'erroneous document raises error': function() {
assert.throws(function() {
parse('');
});
},
'incomplete document raises error': function() {
assert.throws(function() {
parse('');
});
},
'namespace declaration': function() {
var el = parse("");
assert.equal(el.name, 'root');
assert.equal(el.attrs.xmlns, 'https://github.com/astro/ltx');
assert.ok(el.is('root', 'https://github.com/astro/ltx'));
},
'namespace declaration with prefix': function() {
var el = parse("");
assert.equal(el.name, 'x:root');
assert.equal(el.getName(), 'root');
assert.ok(el.is('root', 'https://github.com/astro/ltx'));
},
'buffer': function() {
var buf = new Buffer('');
var el = parse(buf);
assert.equal(el.name, 'root');
assert.equal(0, el.children.length);
},
'utf-8 text': function() {
var el = parse('Möwe');
assert.equal(el.name, 'text');
assert.equal(el.getText(), "Möwe");
},
'iso8859-1 text': function() {
var el = parse('M\xF6we');
assert.equal(el.name, 'text');
assert.equal(el.getText(), "Möwe");
}
},
'SAX parsing': {
'XMPP stream': function() {
var parser = new saxParser();
var events = [];
parser.on('startElement', function(name) {
events.push({ start: name });
});
parser.on('endElement', function(name) {
events.push({ end: name });
});
parser.on('text', function(s) {
events.push({ text: s });
});
parser.write("<");
assert.equal(events.length, 1);
parser.write("stream:features>PLAINDIGEST-MD5");
assert.ok(events.length >= 9);
parser.write("mechanism>SCRAM-SHA-1");
assert.equal(events.length, 15);
parser.write("");
assert.equal(events.length, 18);
}
}
}).export(module);
});