diff --git a/README.md b/README.md
new file mode 100644
index 0000000..a448150
--- /dev/null
+++ b/README.md
@@ -0,0 +1,24 @@
+# ringo-easyxml
+
+One way converter from E4X XML to JSON. Usage:
+
+ var {E4XtoJSON} = require("easyxml");
+ var xml = 'c';
+ var json = E4XtoJSON(xml);
+
+Turns child nodes with the same name into arrays so that lists are easier
+to work with.
+
+
- 1
- 2
+
+ body: {item: ["1", "2"]}
+
+Turns XML node attributes into object attributes,
+the children are placed inside a special attribute named "_":
+
+ whatever
+
+ body: {_a: "a", _: "whatever"}
+
+For other options, take a look at test/all.js.
+
diff --git a/lib/easyxml.js b/lib/easyxml.js
new file mode 100644
index 0000000..606ad41
--- /dev/null
+++ b/lib/easyxml.js
@@ -0,0 +1,72 @@
+export("E4XtoJSON");
+
+function toXML(string) {
+ if(!(string instanceof XML)) {
+ return new XML(string.replace(/^<\?xml\s+[^?]*\?>/g, "").trim());
+ }
+ return string;
+}
+
+function setOptions(options) {
+ options = options || {};
+ options.ignored = options.ignored || [];
+ options.simple = options.simple || [];
+ if(options.prefix == undefined) options.prefix = "_";
+ if(options.body == undefined) options.body = "_";
+ return options;
+}
+
+function toJSON(xml, options) {
+ var r, children = xml.*, attributes = xml.@*, length = children.length();
+ if(length == 0) {
+ r = xml.toString();
+ } else if(length == 1) {
+ var text = xml.text().toString();
+ if(text) {
+ r = text;
+ }
+ }
+ if(r == undefined) {
+ r = {};
+ for each (var child in children) {
+ var name = child.localName();
+ var json = toJSON(child, options);
+ if(!name) {
+ // handle CDATA blocks that have name == null
+ return json;
+ }
+ var value = r[name];
+ if(value) {
+ if(value.length) {
+ value.push(json);
+ } else {
+ r[name] = [value, json]
+ }
+ } else {
+ r[name] = json;
+ }
+ }
+ }
+ // handle attributes
+ var simple = options.simple.indexOf(xml.localName()) != -1;
+ if(!simple && attributes.length()) {
+ var a = {}, c = 0;
+ for each (var attribute in attributes) {
+ var name = attribute.localName();
+ if(options.ignored.indexOf(name) == -1) {
+ a[options.prefix + name] = attribute.toString();
+ c ++;
+ }
+ }
+ if(c) {
+ if(r) a[options.body] = r;
+ return a;
+ }
+ }
+
+ return r;
+}
+
+function E4XtoJSON(xml, options) {
+ return toJSON(toXML(xml), setOptions(options));
+}
\ No newline at end of file
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..c8c48cd
--- /dev/null
+++ b/package.json
@@ -0,0 +1,7 @@
+{
+ "name": "ringo-easyxml",
+ "version": "0.1.0",
+ "description": "XML (E4X) to JSON converter",
+ "keywords": ["xml", "json"],
+ "author": "Oleg Podsechin (http://github.com/olegp)"
+}
diff --git a/test/all.js b/test/all.js
new file mode 100644
index 0000000..360ca54
--- /dev/null
+++ b/test/all.js
@@ -0,0 +1,46 @@
+include('assert');
+
+var {E4XtoJSON} = require("easyxml");
+var {get} = require("ringo/httpclient");
+
+exports.setUp = function () {
+}
+
+exports.testBasic = function() {
+ var xml = 'c';
+ var json = E4XtoJSON(xml);
+ equal(json.b, "c");
+}
+
+exports.testAttribute = function() {
+ var xml = '';
+ var json = E4XtoJSON(xml);
+ equal(json.b._c, "d");
+}
+
+exports.testOptions = function() {
+ var xml = 'e';
+
+ var json1 = E4XtoJSON(xml);
+ equal(json1.b._c, "d");
+ equal(json1.b._, "e");
+
+ var json2 = E4XtoJSON(xml, {simple: ["b"]});
+ equal(json2.b, "e");
+
+ var json3 = E4XtoJSON(xml, {ignored: ["c"]});
+ equal(json3.b, "e");
+
+ var json4 = E4XtoJSON(xml, {prefix: ""});
+ equal(json4.b.c, "d");
+}
+
+exports.testCDATA = function() {
+ var xml = 'd]]>';
+ var json = E4XtoJSON(xml);
+ equal(json.b, "d");
+}
+
+if (require.main == module.id) {
+ require('test').run(exports);
+}