Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Adding the event handlers to the sax stream for reading objects.

Any objects read from the sax stream that match the element should be emitted as events.
  • Loading branch information...
commit 4de7222a22ac606f741fbd6d3a9c92656f6e88a9 1 parent 0ee5c6e
@Zoramite Zoramite authored
Showing with 121 additions and 7 deletions.
  1. +121 −7 lib/xml2object.js
View
128 lib/xml2object.js
@@ -3,22 +3,136 @@
*
* https://github.com/emberfeather/node-xml2object
*/
-emitter = requires('events').EventEmitter;
+var emitter = require('events').EventEmitter;
var fs = require('fs');
var sax = require('sax');
var util = require('util');
-var xml2object = module.exports.xml2object = function(xmlFile, elements) {
- this.xmlFile = xmlFile;
- this.elements = elements || [];
-
+var xml2object = module.exports = function(xmlFile, elements) {
+ elements = elements || [];
+
this._hasStarted = false;
- this.fileStream = fs.createReadStream(this.xmlFile);
+ var self = this;
+ var currentObject;
+ var inObject = false;
+ var inObjectName;
+ var ancestors = [];
+
+ this.fileStream = fs.createReadStream(xmlFile);
this.saxStream = sax.createStream(true);
+
+ this.saxStream.on("opentag", function (args) {
+ if(!inObject) {
+ // If we are not in an object and not tracking the element
+ // then we don't need to do anything
+ if (elements.indexOf(args.name) < 0) {
+ return;
+ }
+
+ // Start tracking a new object
+ inObject = true;
+ inObjectName = args.name;
+
+ currentObject = {};
+ }
+
+ if (!(args.name in currentObject)) {
+ currentObject[args.name] = args.attributes;
+ } else if (!util.isArray(currentObject[args.name])) {
+ // Put the existing object in an array.
+ var newArray = [currentObject[args.name]];
+
+ // Add the new object to the array.
+ newArray.push(args.attributes);
+
+ // Point to the new array.
+ currentObject[args.name] = newArray;
+ } else {
+ // An array already exists, push the attributes on to it.
+ currentObject[args.name].push(args.attributes);
+ }
+
+ // Store the current (old) parent.
+ ancestors.push(currentObject);
+
+ // We are now working with this object, so it becomes the current parent.
+ if (currentObject[args.name] instanceof Array) {
+ // If it is an array, get the last element of the array.
+ currentObject = currentObject[args.name][currentObject[args.name].length - 1];
+ } else {
+ // Otherwise, use the object itself.
+ currentObject = currentObject[args.name];
+ }
+ });
+
+ this.saxStream.on("text", function (data) {
+ if(!inObject) {
+ return;
+ }
+
+ data = data.trim();
+
+ if (!data.length) {
+ return;
+ }
+
+ currentObject['$t'] = (currentObject['$t'] || "") + data;
+ });
+
+ this.saxStream.on("closetag", function (name) {
+ if(!inObject) {
+ return;
+ }
+
+ if(inObject && inObjectName === name) {
+ // Finished building the object
+ self.emit('object', name, currentObject);
+
+ inObject = false;
+ ancestors = [];
+
+ return;
+ }
+
+ if(ancestors.length) {
+ var ancestor = ancestors.pop();
+ var keys = Object.keys(currentObject);
+
+ if (keys.length == 1 && '$t' in currentObject) {
+ // Convert the text only objects into just the text
+ if (ancestor[name] instanceof Array) {
+ ancestor[name].push(ancestor[name].pop()['$t']);
+ } else {
+ ancestor[name] = currentObject['$t'];
+ }
+ } else if (!keys.length) {
+ // Remove empty keys
+ delete ancestor[name];
+ }
+
+ currentObject = ancestor;
+ } else {
+ currentObject = {};
+ }
+ });
+
+ // Rebroadcast the error and keep going
+ this.saxStream.on("error", function (e) {
+ this.emit('error', e);
+
+ // clear the error and resume
+ this._parser.error = null;
+ this._parser.resume();
+ });
+
+ // Rebroadcast the end of the file read
+ this.fileStream.on("end", function() {
+ self.emit("end");
+ });
};
-util.inherits(xml2object, events.EventEmitter);
+util.inherits(xml2object, emitter);
xml2object.prototype.start = function() {
// Can only start once
Please sign in to comment.
Something went wrong with that request. Please try again.