00001
00002 (function() {
00003 var XMLAttribute, XMLCData, XMLComment, XMLDTDAttList, XMLDTDElement, XMLDTDEntity, XMLDTDNotation, XMLDeclaration, XMLDocType, XMLDocumentCB, XMLElement, XMLProcessingInstruction, XMLRaw, XMLStringWriter, XMLStringifier, XMLText, isFunction, isObject, isPlainObject, ref,
00004 hasProp = {}.hasOwnProperty;
00005
00006 ref = require('./Utility'), isObject = ref.isObject, isFunction = ref.isFunction, isPlainObject = ref.isPlainObject;
00007
00008 XMLElement = require('./XMLElement');
00009
00010 XMLCData = require('./XMLCData');
00011
00012 XMLComment = require('./XMLComment');
00013
00014 XMLRaw = require('./XMLRaw');
00015
00016 XMLText = require('./XMLText');
00017
00018 XMLProcessingInstruction = require('./XMLProcessingInstruction');
00019
00020 XMLDeclaration = require('./XMLDeclaration');
00021
00022 XMLDocType = require('./XMLDocType');
00023
00024 XMLDTDAttList = require('./XMLDTDAttList');
00025
00026 XMLDTDEntity = require('./XMLDTDEntity');
00027
00028 XMLDTDElement = require('./XMLDTDElement');
00029
00030 XMLDTDNotation = require('./XMLDTDNotation');
00031
00032 XMLAttribute = require('./XMLAttribute');
00033
00034 XMLStringifier = require('./XMLStringifier');
00035
00036 XMLStringWriter = require('./XMLStringWriter');
00037
00038 module.exports = XMLDocumentCB = (function() {
00039 function XMLDocumentCB(options, onData, onEnd) {
00040 var writerOptions;
00041 options || (options = {});
00042 if (!options.writer) {
00043 options.writer = new XMLStringWriter(options);
00044 } else if (isPlainObject(options.writer)) {
00045 writerOptions = options.writer;
00046 options.writer = new XMLStringWriter(writerOptions);
00047 }
00048 this.options = options;
00049 this.writer = options.writer;
00050 this.stringify = new XMLStringifier(options);
00051 this.onDataCallback = onData || function() {};
00052 this.onEndCallback = onEnd || function() {};
00053 this.currentNode = null;
00054 this.currentLevel = -1;
00055 this.openTags = {};
00056 this.documentStarted = false;
00057 this.documentCompleted = false;
00058 this.root = null;
00059 }
00060
00061 XMLDocumentCB.prototype.node = function(name, attributes, text) {
00062 var ref1;
00063 if (name == null) {
00064 throw new Error("Missing node name");
00065 }
00066 if (this.root && this.currentLevel === -1) {
00067 throw new Error("Document can only have one root node");
00068 }
00069 this.openCurrent();
00070 name = name.valueOf();
00071 if (attributes == null) {
00072 attributes = {};
00073 }
00074 attributes = attributes.valueOf();
00075 if (!isObject(attributes)) {
00076 ref1 = [attributes, text], text = ref1[0], attributes = ref1[1];
00077 }
00078 this.currentNode = new XMLElement(this, name, attributes);
00079 this.currentNode.children = false;
00080 this.currentLevel++;
00081 this.openTags[this.currentLevel] = this.currentNode;
00082 if (text != null) {
00083 this.text(text);
00084 }
00085 return this;
00086 };
00087
00088 XMLDocumentCB.prototype.element = function(name, attributes, text) {
00089 if (this.currentNode && this.currentNode instanceof XMLDocType) {
00090 return this.dtdElement.apply(this, arguments);
00091 } else {
00092 return this.node(name, attributes, text);
00093 }
00094 };
00095
00096 XMLDocumentCB.prototype.attribute = function(name, value) {
00097 var attName, attValue;
00098 if (!this.currentNode || this.currentNode.children) {
00099 throw new Error("att() can only be used immediately after an ele() call in callback mode");
00100 }
00101 if (name != null) {
00102 name = name.valueOf();
00103 }
00104 if (isObject(name)) {
00105 for (attName in name) {
00106 if (!hasProp.call(name, attName)) continue;
00107 attValue = name[attName];
00108 this.attribute(attName, attValue);
00109 }
00110 } else {
00111 if (isFunction(value)) {
00112 value = value.apply();
00113 }
00114 if (!this.options.skipNullAttributes || (value != null)) {
00115 this.currentNode.attributes[name] = new XMLAttribute(this, name, value);
00116 }
00117 }
00118 return this;
00119 };
00120
00121 XMLDocumentCB.prototype.text = function(value) {
00122 var node;
00123 this.openCurrent();
00124 node = new XMLText(this, value);
00125 this.onData(this.writer.text(node, this.currentLevel + 1));
00126 return this;
00127 };
00128
00129 XMLDocumentCB.prototype.cdata = function(value) {
00130 var node;
00131 this.openCurrent();
00132 node = new XMLCData(this, value);
00133 this.onData(this.writer.cdata(node, this.currentLevel + 1));
00134 return this;
00135 };
00136
00137 XMLDocumentCB.prototype.comment = function(value) {
00138 var node;
00139 this.openCurrent();
00140 node = new XMLComment(this, value);
00141 this.onData(this.writer.comment(node, this.currentLevel + 1));
00142 return this;
00143 };
00144
00145 XMLDocumentCB.prototype.raw = function(value) {
00146 var node;
00147 this.openCurrent();
00148 node = new XMLRaw(this, value);
00149 this.onData(this.writer.raw(node, this.currentLevel + 1));
00150 return this;
00151 };
00152
00153 XMLDocumentCB.prototype.instruction = function(target, value) {
00154 var i, insTarget, insValue, len, node;
00155 this.openCurrent();
00156 if (target != null) {
00157 target = target.valueOf();
00158 }
00159 if (value != null) {
00160 value = value.valueOf();
00161 }
00162 if (Array.isArray(target)) {
00163 for (i = 0, len = target.length; i < len; i++) {
00164 insTarget = target[i];
00165 this.instruction(insTarget);
00166 }
00167 } else if (isObject(target)) {
00168 for (insTarget in target) {
00169 if (!hasProp.call(target, insTarget)) continue;
00170 insValue = target[insTarget];
00171 this.instruction(insTarget, insValue);
00172 }
00173 } else {
00174 if (isFunction(value)) {
00175 value = value.apply();
00176 }
00177 node = new XMLProcessingInstruction(this, target, value);
00178 this.onData(this.writer.processingInstruction(node, this.currentLevel + 1));
00179 }
00180 return this;
00181 };
00182
00183 XMLDocumentCB.prototype.declaration = function(version, encoding, standalone) {
00184 var node;
00185 this.openCurrent();
00186 if (this.documentStarted) {
00187 throw new Error("declaration() must be the first node");
00188 }
00189 node = new XMLDeclaration(this, version, encoding, standalone);
00190 this.onData(this.writer.declaration(node, this.currentLevel + 1));
00191 return this;
00192 };
00193
00194 XMLDocumentCB.prototype.doctype = function(root, pubID, sysID) {
00195 this.openCurrent();
00196 if (root == null) {
00197 throw new Error("Missing root node name");
00198 }
00199 if (this.root) {
00200 throw new Error("dtd() must come before the root node");
00201 }
00202 this.currentNode = new XMLDocType(this, pubID, sysID);
00203 this.currentNode.rootNodeName = root;
00204 this.currentNode.children = false;
00205 this.currentLevel++;
00206 this.openTags[this.currentLevel] = this.currentNode;
00207 return this;
00208 };
00209
00210 XMLDocumentCB.prototype.dtdElement = function(name, value) {
00211 var node;
00212 this.openCurrent();
00213 node = new XMLDTDElement(this, name, value);
00214 this.onData(this.writer.dtdElement(node, this.currentLevel + 1));
00215 return this;
00216 };
00217
00218 XMLDocumentCB.prototype.attList = function(elementName, attributeName, attributeType, defaultValueType, defaultValue) {
00219 var node;
00220 this.openCurrent();
00221 node = new XMLDTDAttList(this, elementName, attributeName, attributeType, defaultValueType, defaultValue);
00222 this.onData(this.writer.dtdAttList(node, this.currentLevel + 1));
00223 return this;
00224 };
00225
00226 XMLDocumentCB.prototype.entity = function(name, value) {
00227 var node;
00228 this.openCurrent();
00229 node = new XMLDTDEntity(this, false, name, value);
00230 this.onData(this.writer.dtdEntity(node, this.currentLevel + 1));
00231 return this;
00232 };
00233
00234 XMLDocumentCB.prototype.pEntity = function(name, value) {
00235 var node;
00236 this.openCurrent();
00237 node = new XMLDTDEntity(this, true, name, value);
00238 this.onData(this.writer.dtdEntity(node, this.currentLevel + 1));
00239 return this;
00240 };
00241
00242 XMLDocumentCB.prototype.notation = function(name, value) {
00243 var node;
00244 this.openCurrent();
00245 node = new XMLDTDNotation(this, name, value);
00246 this.onData(this.writer.dtdNotation(node, this.currentLevel + 1));
00247 return this;
00248 };
00249
00250 XMLDocumentCB.prototype.up = function() {
00251 if (this.currentLevel < 0) {
00252 throw new Error("The document node has no parent");
00253 }
00254 if (this.currentNode) {
00255 if (this.currentNode.children) {
00256 this.closeNode(this.currentNode);
00257 } else {
00258 this.openNode(this.currentNode);
00259 }
00260 this.currentNode = null;
00261 } else {
00262 this.closeNode(this.openTags[this.currentLevel]);
00263 }
00264 delete this.openTags[this.currentLevel];
00265 this.currentLevel--;
00266 return this;
00267 };
00268
00269 XMLDocumentCB.prototype.end = function() {
00270 while (this.currentLevel >= 0) {
00271 this.up();
00272 }
00273 return this.onEnd();
00274 };
00275
00276 XMLDocumentCB.prototype.openCurrent = function() {
00277 if (this.currentNode) {
00278 this.currentNode.children = true;
00279 return this.openNode(this.currentNode);
00280 }
00281 };
00282
00283 XMLDocumentCB.prototype.openNode = function(node) {
00284 if (!node.isOpen) {
00285 if (!this.root && this.currentLevel === 0 && node instanceof XMLElement) {
00286 this.root = node;
00287 }
00288 this.onData(this.writer.openNode(node, this.currentLevel));
00289 return node.isOpen = true;
00290 }
00291 };
00292
00293 XMLDocumentCB.prototype.closeNode = function(node) {
00294 if (!node.isClosed) {
00295 this.onData(this.writer.closeNode(node, this.currentLevel));
00296 return node.isClosed = true;
00297 }
00298 };
00299
00300 XMLDocumentCB.prototype.onData = function(chunk) {
00301 this.documentStarted = true;
00302 return this.onDataCallback(chunk);
00303 };
00304
00305 XMLDocumentCB.prototype.onEnd = function() {
00306 this.documentCompleted = true;
00307 return this.onEndCallback();
00308 };
00309
00310 XMLDocumentCB.prototype.ele = function() {
00311 return this.element.apply(this, arguments);
00312 };
00313
00314 XMLDocumentCB.prototype.nod = function(name, attributes, text) {
00315 return this.node(name, attributes, text);
00316 };
00317
00318 XMLDocumentCB.prototype.txt = function(value) {
00319 return this.text(value);
00320 };
00321
00322 XMLDocumentCB.prototype.dat = function(value) {
00323 return this.cdata(value);
00324 };
00325
00326 XMLDocumentCB.prototype.com = function(value) {
00327 return this.comment(value);
00328 };
00329
00330 XMLDocumentCB.prototype.ins = function(target, value) {
00331 return this.instruction(target, value);
00332 };
00333
00334 XMLDocumentCB.prototype.dec = function(version, encoding, standalone) {
00335 return this.declaration(version, encoding, standalone);
00336 };
00337
00338 XMLDocumentCB.prototype.dtd = function(root, pubID, sysID) {
00339 return this.doctype(root, pubID, sysID);
00340 };
00341
00342 XMLDocumentCB.prototype.e = function(name, attributes, text) {
00343 return this.element(name, attributes, text);
00344 };
00345
00346 XMLDocumentCB.prototype.n = function(name, attributes, text) {
00347 return this.node(name, attributes, text);
00348 };
00349
00350 XMLDocumentCB.prototype.t = function(value) {
00351 return this.text(value);
00352 };
00353
00354 XMLDocumentCB.prototype.d = function(value) {
00355 return this.cdata(value);
00356 };
00357
00358 XMLDocumentCB.prototype.c = function(value) {
00359 return this.comment(value);
00360 };
00361
00362 XMLDocumentCB.prototype.r = function(value) {
00363 return this.raw(value);
00364 };
00365
00366 XMLDocumentCB.prototype.i = function(target, value) {
00367 return this.instruction(target, value);
00368 };
00369
00370 XMLDocumentCB.prototype.att = function() {
00371 if (this.currentNode && this.currentNode instanceof XMLDocType) {
00372 return this.attList.apply(this, arguments);
00373 } else {
00374 return this.attribute.apply(this, arguments);
00375 }
00376 };
00377
00378 XMLDocumentCB.prototype.a = function() {
00379 if (this.currentNode && this.currentNode instanceof XMLDocType) {
00380 return this.attList.apply(this, arguments);
00381 } else {
00382 return this.attribute.apply(this, arguments);
00383 }
00384 };
00385
00386 XMLDocumentCB.prototype.ent = function(name, value) {
00387 return this.entity(name, value);
00388 };
00389
00390 XMLDocumentCB.prototype.pent = function(name, value) {
00391 return this.pEntity(name, value);
00392 };
00393
00394 XMLDocumentCB.prototype.not = function(name, value) {
00395 return this.notation(name, value);
00396 };
00397
00398 return XMLDocumentCB;
00399
00400 })();
00401
00402 }).call(this);