3 var XMLAttribute, XMLCData, XMLComment, XMLDTDAttList, XMLDTDElement, XMLDTDEntity, XMLDTDNotation, XMLDeclaration, XMLDocType, XMLDocumentCB, XMLElement, XMLProcessingInstruction, XMLRaw, XMLStringWriter, XMLStringifier, XMLText, isFunction, isObject, isPlainObject, ref,
4 hasProp = {}.hasOwnProperty;
6 ref = require(
'./Utility'), isObject = ref.isObject, isFunction = ref.isFunction, isPlainObject = ref.isPlainObject;
8 XMLElement = require(
'./XMLElement');
10 XMLCData = require(
'./XMLCData');
12 XMLComment = require(
'./XMLComment');
14 XMLRaw = require(
'./XMLRaw');
16 XMLText = require(
'./XMLText');
18 XMLProcessingInstruction = require(
'./XMLProcessingInstruction');
20 XMLDeclaration = require(
'./XMLDeclaration');
22 XMLDocType = require(
'./XMLDocType');
24 XMLDTDAttList = require(
'./XMLDTDAttList');
26 XMLDTDEntity = require(
'./XMLDTDEntity');
28 XMLDTDElement = require(
'./XMLDTDElement');
30 XMLDTDNotation = require(
'./XMLDTDNotation');
32 XMLAttribute = require(
'./XMLAttribute');
34 XMLStringifier = require(
'./XMLStringifier');
36 XMLStringWriter = require(
'./XMLStringWriter');
38 module.exports = XMLDocumentCB = (
function() {
39 function XMLDocumentCB(options, onData, onEnd) {
41 options || (options = {});
42 if (!options.writer) {
43 options.writer =
new XMLStringWriter(options);
44 }
else if (isPlainObject(options.writer)) {
45 writerOptions = options.writer;
46 options.writer =
new XMLStringWriter(writerOptions);
48 this.options = options;
49 this.writer = options.writer;
50 this.stringify =
new XMLStringifier(options);
51 this.onDataCallback = onData ||
function() {};
52 this.onEndCallback = onEnd ||
function() {};
53 this.currentNode = null;
54 this.currentLevel = -1;
56 this.documentStarted =
false;
57 this.documentCompleted =
false;
61 XMLDocumentCB.prototype.node =
function(name, attributes, text) {
64 throw new Error(
"Missing node name");
66 if (this.root && this.currentLevel === -1) {
67 throw new Error(
"Document can only have one root node");
70 name = name.valueOf();
71 if (attributes == null) {
74 attributes = attributes.valueOf();
75 if (!isObject(attributes)) {
76 ref1 = [attributes, text], text = ref1[0], attributes = ref1[1];
78 this.currentNode =
new XMLElement(
this, name, attributes);
79 this.currentNode.children =
false;
81 this.openTags[this.currentLevel] = this.currentNode;
88 XMLDocumentCB.prototype.element =
function(name, attributes, text) {
89 if (this.currentNode && this.currentNode instanceof XMLDocType) {
90 return this.dtdElement.apply(
this, arguments);
92 return this.node(name, attributes, text);
96 XMLDocumentCB.prototype.attribute =
function(name, value) {
97 var attName, attValue;
98 if (!this.currentNode || this.currentNode.children) {
99 throw new Error(
"att() can only be used immediately after an ele() call in callback mode");
102 name = name.valueOf();
104 if (isObject(name)) {
105 for (attName in name) {
106 if (!hasProp.call(name, attName))
continue;
107 attValue = name[attName];
108 this.attribute(attName, attValue);
111 if (isFunction(value)) {
112 value = value.apply();
114 if (!this.options.skipNullAttributes || (value != null)) {
115 this.currentNode.attributes[name] =
new XMLAttribute(
this, name, value);
121 XMLDocumentCB.prototype.text =
function(value) {
124 node =
new XMLText(
this, value);
125 this.onData(this.writer.text(node,
this.currentLevel + 1));
129 XMLDocumentCB.prototype.cdata =
function(value) {
132 node =
new XMLCData(
this, value);
133 this.onData(this.writer.cdata(node,
this.currentLevel + 1));
137 XMLDocumentCB.prototype.comment =
function(value) {
140 node =
new XMLComment(
this, value);
141 this.onData(this.writer.comment(node,
this.currentLevel + 1));
145 XMLDocumentCB.prototype.raw =
function(value) {
148 node =
new XMLRaw(
this, value);
149 this.onData(this.writer.raw(node,
this.currentLevel + 1));
153 XMLDocumentCB.prototype.instruction =
function(target, value) {
154 var i, insTarget, insValue, len, node;
156 if (target != null) {
157 target = target.valueOf();
160 value = value.valueOf();
162 if (Array.isArray(target)) {
163 for (i = 0, len = target.length; i < len; i++) {
164 insTarget = target[i];
165 this.instruction(insTarget);
167 }
else if (isObject(target)) {
168 for (insTarget in target) {
169 if (!hasProp.call(target, insTarget))
continue;
170 insValue = target[insTarget];
171 this.instruction(insTarget, insValue);
174 if (isFunction(value)) {
175 value = value.apply();
177 node =
new XMLProcessingInstruction(
this, target, value);
178 this.onData(this.writer.processingInstruction(node,
this.currentLevel + 1));
183 XMLDocumentCB.prototype.declaration =
function(version, encoding, standalone) {
186 if (this.documentStarted) {
187 throw new Error(
"declaration() must be the first node");
189 node =
new XMLDeclaration(
this, version, encoding, standalone);
190 this.onData(this.writer.declaration(node,
this.currentLevel + 1));
194 XMLDocumentCB.prototype.doctype =
function(root, pubID, sysID) {
197 throw new Error(
"Missing root node name");
200 throw new Error(
"dtd() must come before the root node");
202 this.currentNode =
new XMLDocType(
this, pubID, sysID);
203 this.currentNode.rootNodeName = root;
204 this.currentNode.children =
false;
206 this.openTags[this.currentLevel] = this.currentNode;
210 XMLDocumentCB.prototype.dtdElement =
function(name, value) {
213 node =
new XMLDTDElement(
this, name, value);
214 this.onData(this.writer.dtdElement(node,
this.currentLevel + 1));
218 XMLDocumentCB.prototype.attList =
function(elementName, attributeName, attributeType, defaultValueType, defaultValue) {
221 node =
new XMLDTDAttList(
this, elementName, attributeName, attributeType, defaultValueType, defaultValue);
222 this.onData(this.writer.dtdAttList(node,
this.currentLevel + 1));
226 XMLDocumentCB.prototype.entity =
function(name, value) {
229 node =
new XMLDTDEntity(
this,
false, name, value);
230 this.onData(this.writer.dtdEntity(node,
this.currentLevel + 1));
234 XMLDocumentCB.prototype.pEntity =
function(name, value) {
237 node =
new XMLDTDEntity(
this,
true, name, value);
238 this.onData(this.writer.dtdEntity(node,
this.currentLevel + 1));
242 XMLDocumentCB.prototype.notation =
function(name, value) {
245 node =
new XMLDTDNotation(
this, name, value);
246 this.onData(this.writer.dtdNotation(node,
this.currentLevel + 1));
250 XMLDocumentCB.prototype.up =
function() {
251 if (this.currentLevel < 0) {
252 throw new Error(
"The document node has no parent");
254 if (this.currentNode) {
255 if (this.currentNode.children) {
256 this.closeNode(this.currentNode);
258 this.openNode(this.currentNode);
260 this.currentNode = null;
262 this.closeNode(this.openTags[this.currentLevel]);
264 delete this.openTags[this.currentLevel];
269 XMLDocumentCB.prototype.end =
function() {
270 while (this.currentLevel >= 0) {
276 XMLDocumentCB.prototype.openCurrent =
function() {
277 if (this.currentNode) {
278 this.currentNode.children =
true;
279 return this.openNode(this.currentNode);
283 XMLDocumentCB.prototype.openNode =
function(node) {
285 if (!this.root && this.currentLevel === 0 && node instanceof XMLElement) {
288 this.onData(this.writer.openNode(node,
this.currentLevel));
289 return node.isOpen =
true;
293 XMLDocumentCB.prototype.closeNode =
function(node) {
294 if (!node.isClosed) {
295 this.onData(this.writer.closeNode(node,
this.currentLevel));
296 return node.isClosed =
true;
300 XMLDocumentCB.prototype.onData =
function(chunk) {
301 this.documentStarted =
true;
302 return this.onDataCallback(chunk);
305 XMLDocumentCB.prototype.onEnd =
function() {
306 this.documentCompleted =
true;
307 return this.onEndCallback();
310 XMLDocumentCB.prototype.ele =
function() {
311 return this.element.apply(
this, arguments);
314 XMLDocumentCB.prototype.nod =
function(name, attributes, text) {
315 return this.node(name, attributes, text);
318 XMLDocumentCB.prototype.txt =
function(value) {
319 return this.text(value);
322 XMLDocumentCB.prototype.dat =
function(value) {
323 return this.cdata(value);
326 XMLDocumentCB.prototype.com =
function(value) {
327 return this.comment(value);
330 XMLDocumentCB.prototype.ins =
function(target, value) {
331 return this.instruction(target, value);
334 XMLDocumentCB.prototype.dec =
function(version, encoding, standalone) {
335 return this.declaration(version, encoding, standalone);
338 XMLDocumentCB.prototype.dtd =
function(root, pubID, sysID) {
339 return this.doctype(root, pubID, sysID);
342 XMLDocumentCB.prototype.e =
function(name, attributes, text) {
343 return this.element(name, attributes, text);
346 XMLDocumentCB.prototype.n =
function(name, attributes, text) {
347 return this.node(name, attributes, text);
350 XMLDocumentCB.prototype.t =
function(value) {
351 return this.text(value);
354 XMLDocumentCB.prototype.d =
function(value) {
355 return this.cdata(value);
358 XMLDocumentCB.prototype.c =
function(value) {
359 return this.comment(value);
362 XMLDocumentCB.prototype.r =
function(value) {
363 return this.raw(value);
366 XMLDocumentCB.prototype.i =
function(target, value) {
367 return this.instruction(target, value);
370 XMLDocumentCB.prototype.att =
function() {
371 if (this.currentNode && this.currentNode instanceof XMLDocType) {
372 return this.attList.apply(
this, arguments);
374 return this.attribute.apply(
this, arguments);
378 XMLDocumentCB.prototype.a =
function() {
379 if (this.currentNode && this.currentNode instanceof XMLDocType) {
380 return this.attList.apply(
this, arguments);
382 return this.attribute.apply(
this, arguments);
386 XMLDocumentCB.prototype.ent =
function(name, value) {
387 return this.entity(name, value);
390 XMLDocumentCB.prototype.pent =
function(name, value) {
391 return this.pEntity(name, value);
394 XMLDocumentCB.prototype.not =
function(name, value) {
395 return this.notation(name, value);
398 return XMLDocumentCB;