diff --git a/Cakefile b/Cakefile
new file mode 100644
index 0000000..db1cee0
--- /dev/null
+++ b/Cakefile
@@ -0,0 +1,8 @@
+{spawn} = require 'child_process'
+fs = require 'fs'
+
+task 'build', 'coffee -> js', ->
+ files = (file for file in fs.readdirSync '.' when file.match(/\.coffee$/))
+ proc = spawn 'coffee', ['-c'].concat files
+ proc.stderr.on 'data', (buffer) -> console.log buffer.toString()
+ proc.on 'exit', (status) -> process.exit(1) if status != 0
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..34842ac
--- /dev/null
+++ b/README.md
@@ -0,0 +1,11 @@
+This module converts streams of XML to streams of JS objects. Unlike other
+SAX modules, it doesn't give you every tag and text node seperately, but lets you
+specify tag names you want to filter for. When this module encounters a tag with
+that name, its content will be collected until the closing tag was reached, and
+then you will receive the tag with all its attributes and children in one
+object.
+
+Compiling
+=========
+To compile the `.coffee` files to Javascript, use `cake build`. You will need
+[Coffeescript](http://coffeescript.org/) for that.
diff --git a/index.coffee b/index.coffee
new file mode 100644
index 0000000..181baa4
--- /dev/null
+++ b/index.coffee
@@ -0,0 +1,26 @@
+sax = require 'sax'
+
+last = (array) -> array[array.length-1]
+
+exports.createParser = (cbError, cbFinished, wantedNodes, strict) ->
+ interestingStack = []
+ element = null
+ parser = sax.parser strict
+ parser.onerror = cbError
+ parser.onend = cbFinished
+ parser.onopentag = ({name, attributes}) ->
+ console.log " opening #{name}"
+ if wantedNodes[name]? or element?
+ parent = element
+ element = {parent, name, attributes, children: []}
+ parent?.children.push element
+ if wantedNodes[name]?
+ interestingStack.push name
+ parser.onclosetag = (name) ->
+ if name is last interestingStack
+ interestingStack.pop()
+ wantedNodes[name] element
+ element = element?.parent
+ parser.ontext = (text) ->
+ element?.children.push text
+ parser
diff --git a/index.js b/index.js
new file mode 100644
index 0000000..eefa487
--- /dev/null
+++ b/index.js
@@ -0,0 +1,46 @@
+(function() {
+ var last, sax;
+ sax = require('sax');
+ last = function(array) {
+ return array[array.length - 1];
+ };
+ exports.createParser = function(cbError, cbFinished, wantedNodes, strict) {
+ var element, interestingStack, parser;
+ interestingStack = [];
+ element = null;
+ parser = sax.parser(strict);
+ parser.onerror = cbError;
+ parser.onend = cbFinished;
+ parser.onopentag = function(_arg) {
+ var attributes, name, parent;
+ name = _arg.name, attributes = _arg.attributes;
+ console.log(" opening " + name);
+ if ((wantedNodes[name] != null) || (element != null)) {
+ parent = element;
+ element = {
+ parent: parent,
+ name: name,
+ attributes: attributes,
+ children: []
+ };
+ if (parent != null) {
+ parent.children.push(element);
+ }
+ }
+ if (wantedNodes[name] != null) {
+ return interestingStack.push(name);
+ }
+ };
+ parser.onclosetag = function(name) {
+ if (name === last(interestingStack)) {
+ interestingStack.pop();
+ wantedNodes[name](element);
+ }
+ return element = element != null ? element.parent : void 0;
+ };
+ parser.ontext = function(text) {
+ return element != null ? element.children.push(text) : void 0;
+ };
+ return parser;
+ };
+}).call(this);
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..4bcf0c8
--- /dev/null
+++ b/package.json
@@ -0,0 +1,23 @@
+{ "name": "halfstreamxml"
+, "version": "0.1.0"
+, "description": "converts a stream of XML to a stream of objects"
+, "keywords":
+ [ "XML"
+ , "stream"
+ , "SAX"
+ ]
+, "homepage": "http://github.com/thejh/node-halfstreamxml"
+, "author": "Jann Horn"
+, "main": "FIXME"
+, "repository":
+ { "type": "git"
+ , "url": "http://github.com/thejh/node-halfstreamxml.git"
+ }
+, "dependencies":
+ { "sax": "0.1.2"
+ }
+, "files":
+ { "package.json"
+ , "index.js"
+ }
+}
diff --git a/test.coffee b/test.coffee
new file mode 100644
index 0000000..296f193
--- /dev/null
+++ b/test.coffee
@@ -0,0 +1,10 @@
+halfstreamxml = require './index'
+onerror = (e) ->
+ console.error "ERROR: #{e}"
+onfinish = ->
+ console.log "DONE"
+wantednodes =
+ PERSON: (person) ->
+ console.log "received person: #{JSON.stringify person, ['name', 'attributes', 'age', 'children']}"
+parser = halfstreamxml.createParser onerror, onfinish, wantednodes, false
+parser.write('BarfooFoo Bar').close()
diff --git a/test.js b/test.js
new file mode 100644
index 0000000..320feea
--- /dev/null
+++ b/test.js
@@ -0,0 +1,17 @@
+(function() {
+ var halfstreamxml, onerror, onfinish, parser, wantednodes;
+ halfstreamxml = require('./index');
+ onerror = function(e) {
+ return console.error("ERROR: " + e);
+ };
+ onfinish = function() {
+ return console.log("DONE");
+ };
+ wantednodes = {
+ PERSON: function(person) {
+ return console.log("received person: " + (JSON.stringify(person, ['name', 'attributes', 'age', 'children'])));
+ }
+ };
+ parser = halfstreamxml.createParser(onerror, onfinish, wantednodes, false);
+ parser.write('BarfooFoo Bar').close();
+}).call(this);