// Generated by CoffeeScript 2.4.1 (function() { var DocumentPosition, NodeType, XMLCData, XMLComment, XMLDeclaration, XMLDocType, XMLDummy, XMLElement, XMLNamedNodeMap, XMLNode, XMLNodeList, XMLProcessingInstruction, XMLRaw, XMLText, getValue, isEmpty, isFunction, isObject, hasProp = {}.hasOwnProperty, splice = [].splice; ({isObject, isFunction, isEmpty, getValue} = require('./Utility')); XMLElement = null; XMLCData = null; XMLComment = null; XMLDeclaration = null; XMLDocType = null; XMLRaw = null; XMLText = null; XMLProcessingInstruction = null; XMLDummy = null; NodeType = null; XMLNodeList = null; XMLNamedNodeMap = null; DocumentPosition = null; // Represents a generic XMl element module.exports = XMLNode = (function() { class XMLNode { // Initializes a new instance of `XMLNode` // `parent` the parent node constructor(parent1) { this.parent = parent1; if (this.parent) { this.options = this.parent.options; this.stringify = this.parent.stringify; } this.value = null; this.children = []; this.baseURI = null; // first execution, load dependencies that are otherwise // circular (so we can't load them at the top) if (!XMLElement) { XMLElement = require('./XMLElement'); XMLCData = require('./XMLCData'); XMLComment = require('./XMLComment'); XMLDeclaration = require('./XMLDeclaration'); XMLDocType = require('./XMLDocType'); XMLRaw = require('./XMLRaw'); XMLText = require('./XMLText'); XMLProcessingInstruction = require('./XMLProcessingInstruction'); XMLDummy = require('./XMLDummy'); NodeType = require('./NodeType'); XMLNodeList = require('./XMLNodeList'); XMLNamedNodeMap = require('./XMLNamedNodeMap'); DocumentPosition = require('./DocumentPosition'); } } // Sets the parent node of this node and its children recursively // `parent` the parent node setParent(parent) { var child, j, len, ref1, results; this.parent = parent; if (parent) { this.options = parent.options; this.stringify = parent.stringify; } ref1 = this.children; results = []; for (j = 0, len = ref1.length; j < len; j++) { child = ref1[j]; results.push(child.setParent(this)); } return results; } // Creates a child element node // `name` node name or an object describing the XML tree // `attributes` an object containing name/value pairs of attributes // `text` element text element(name, attributes, text) { var childNode, item, j, k, key, lastChild, len, len1, val; lastChild = null; if (attributes === null && (text == null)) { [attributes, text] = [{}, null]; } if (attributes == null) { attributes = {}; } attributes = getValue(attributes); // swap argument order: text <-> attributes if (!isObject(attributes)) { [text, attributes] = [attributes, text]; } if (name != null) { name = getValue(name); } // expand if array if (Array.isArray(name)) { for (j = 0, len = name.length; j < len; j++) { item = name[j]; lastChild = this.element(item); } // evaluate if function } else if (isFunction(name)) { lastChild = this.element(name.apply()); // expand if object } else if (isObject(name)) { for (key in name) { if (!hasProp.call(name, key)) continue; val = name[key]; if (isFunction(val)) { // evaluate if function val = val.apply(); } // assign attributes if (!this.options.ignoreDecorators && this.stringify.convertAttKey && key.indexOf(this.stringify.convertAttKey) === 0) { lastChild = this.attribute(key.substr(this.stringify.convertAttKey.length), val); // skip empty arrays } else if (!this.options.separateArrayItems && Array.isArray(val) && isEmpty(val)) { lastChild = this.dummy(); // empty objects produce one node } else if (isObject(val) && isEmpty(val)) { lastChild = this.element(key); // skip null and undefined nodes } else if (!this.options.keepNullNodes && (val == null)) { lastChild = this.dummy(); // expand list by creating child nodes } else if (!this.options.separateArrayItems && Array.isArray(val)) { for (k = 0, len1 = val.length; k < len1; k++) { item = val[k]; childNode = {}; childNode[key] = item; lastChild = this.element(childNode); } // expand child nodes under parent } else if (isObject(val)) { // if the key is #text expand child nodes under this node to support mixed content if (!this.options.ignoreDecorators && this.stringify.convertTextKey && key.indexOf(this.stringify.convertTextKey) === 0) { lastChild = this.element(val); } else { lastChild = this.element(key); lastChild.element(val); } } else { // text node lastChild = this.element(key, val); } } // skip null nodes } else if (!this.options.keepNullNodes && text === null) { lastChild = this.dummy(); } else { // text node if (!this.options.ignoreDecorators && this.stringify.convertTextKey && name.indexOf(this.stringify.convertTextKey) === 0) { lastChild = this.text(text); // cdata node } else if (!this.options.ignoreDecorators && this.stringify.convertCDataKey && name.indexOf(this.stringify.convertCDataKey) === 0) { lastChild = this.cdata(text); // comment node } else if (!this.options.ignoreDecorators && this.stringify.convertCommentKey && name.indexOf(this.stringify.convertCommentKey) === 0) { lastChild = this.comment(text); // raw text node } else if (!this.options.ignoreDecorators && this.stringify.convertRawKey && name.indexOf(this.stringify.convertRawKey) === 0) { lastChild = this.raw(text); // processing instruction } else if (!this.options.ignoreDecorators && this.stringify.convertPIKey && name.indexOf(this.stringify.convertPIKey) === 0) { lastChild = this.instruction(name.substr(this.stringify.convertPIKey.length), text); } else { // element node lastChild = this.node(name, attributes, text); } } if (lastChild == null) { throw new Error("Could not create any elements with: " + name + ". " + this.debugInfo()); } return lastChild; } // Creates a child element node before the current node // `name` node name or an object describing the XML tree // `attributes` an object containing name/value pairs of attributes // `text` element text insertBefore(name, attributes, text) { var child, i, newChild, refChild, removed; // DOM level 1 // insertBefore(newChild, refChild) inserts the child node newChild before refChild if (name != null ? name.type : void 0) { newChild = name; refChild = attributes; newChild.setParent(this); if (refChild) { // temporarily remove children starting *with* refChild i = children.indexOf(refChild); removed = children.splice(i); // add the new child children.push(newChild); // add back removed children after new child Array.prototype.push.apply(children, removed); } else { children.push(newChild); } return newChild; } else { if (this.isRoot) { throw new Error("Cannot insert elements at root level. " + this.debugInfo(name)); } // temporarily remove children starting *with* this i = this.parent.children.indexOf(this); removed = this.parent.children.splice(i); // add the new child child = this.parent.element(name, attributes, text); // add back removed children after new child Array.prototype.push.apply(this.parent.children, removed); return child; } } // Creates a child element node after the current node // `name` node name or an object describing the XML tree // `attributes` an object containing name/value pairs of attributes // `text` element text insertAfter(name, attributes, text) { var child, i, removed; if (this.isRoot) { throw new Error("Cannot insert elements at root level. " + this.debugInfo(name)); } // temporarily remove children starting *after* this i = this.parent.children.indexOf(this); removed = this.parent.children.splice(i + 1); // add the new child child = this.parent.element(name, attributes, text); // add back removed children after new child Array.prototype.push.apply(this.parent.children, removed); return child; } // Deletes a child element node remove() { var i, ref1; if (this.isRoot) { throw new Error("Cannot remove the root element. " + this.debugInfo()); } i = this.parent.children.indexOf(this); splice.apply(this.parent.children, [i, i - i + 1].concat(ref1 = [])), ref1; return this.parent; } // Creates a node // `name` name of the node // `attributes` an object containing name/value pairs of attributes // `text` element text node(name, attributes, text) { var child; if (name != null) { name = getValue(name); } attributes || (attributes = {}); attributes = getValue(attributes); // swap argument order: text <-> attributes if (!isObject(attributes)) { [text, attributes] = [attributes, text]; } child = new XMLElement(this, name, attributes); if (text != null) { child.text(text); } this.children.push(child); return child; } // Creates a text node // `value` element text text(value) { var child; if (isObject(value)) { this.element(value); } child = new XMLText(this, value); this.children.push(child); return this; } // Creates a CDATA node // `value` element text without CDATA delimiters cdata(value) { var child; child = new XMLCData(this, value); this.children.push(child); return this; } // Creates a comment node // `value` comment text comment(value) { var child; child = new XMLComment(this, value); this.children.push(child); return this; } // Creates a comment node before the current node // `value` comment text commentBefore(value) { var child, i, removed; // temporarily remove children starting *with* this i = this.parent.children.indexOf(this); removed = this.parent.children.splice(i); // add the new child child = this.parent.comment(value); // add back removed children after new child Array.prototype.push.apply(this.parent.children, removed); return this; } // Creates a comment node after the current node // `value` comment text commentAfter(value) { var child, i, removed; // temporarily remove children starting *after* this i = this.parent.children.indexOf(this); removed = this.parent.children.splice(i + 1); // add the new child child = this.parent.comment(value); // add back removed children after new child Array.prototype.push.apply(this.parent.children, removed); return this; } // Adds unescaped raw text // `value` text raw(value) { var child; child = new XMLRaw(this, value); this.children.push(child); return this; } // Adds a dummy node dummy() { var child; child = new XMLDummy(this); // Normally when a new node is created it is added to the child node collection. // However, dummy nodes are never added to the XML tree. They are created while // converting JS objects to XML nodes in order not to break the recursive function // chain. They can be thought of as invisible nodes. They can be traversed through // by using prev(), next(), up(), etc. functions but they do not exists in the tree. // @children.push child return child; } // Adds a processing instruction // `target` instruction target // `value` instruction value instruction(target, value) { var insTarget, insValue, instruction, j, len; if (target != null) { target = getValue(target); } if (value != null) { value = getValue(value); } if (Array.isArray(target)) { // expand if array for (j = 0, len = target.length; j < len; j++) { insTarget = target[j]; this.instruction(insTarget); } } else if (isObject(target)) { // expand if object for (insTarget in target) { if (!hasProp.call(target, insTarget)) continue; insValue = target[insTarget]; this.instruction(insTarget, insValue); } } else { if (isFunction(value)) { value = value.apply(); } instruction = new XMLProcessingInstruction(this, target, value); this.children.push(instruction); } return this; } // Creates a processing instruction node before the current node // `target` instruction target // `value` instruction value instructionBefore(target, value) { var child, i, removed; // temporarily remove children starting *with* this i = this.parent.children.indexOf(this); removed = this.parent.children.splice(i); // add the new child child = this.parent.instruction(target, value); // add back removed children after new child Array.prototype.push.apply(this.parent.children, removed); return this; } // Creates a processing instruction node after the current node // `target` instruction target // `value` instruction value instructionAfter(target, value) { var child, i, removed; // temporarily remove children starting *after* this i = this.parent.children.indexOf(this); removed = this.parent.children.splice(i + 1); // add the new child child = this.parent.instruction(target, value); // add back removed children after new child Array.prototype.push.apply(this.parent.children, removed); return this; } // Creates the xml declaration // `version` A version number string, e.g. 1.0 // `encoding` Encoding declaration, e.g. UTF-8 // `standalone` standalone document declaration: true or false declaration(version, encoding, standalone) { var doc, xmldec; doc = this.document(); xmldec = new XMLDeclaration(doc, version, encoding, standalone); // Replace XML declaration if exists, otherwise insert at top if (doc.children.length === 0) { doc.children.unshift(xmldec); } else if (doc.children[0].type === NodeType.Declaration) { doc.children[0] = xmldec; } else { doc.children.unshift(xmldec); } return doc.root() || doc; } // Creates the document type declaration // `pubID` the public identifier of the external subset // `sysID` the system identifier of the external subset dtd(pubID, sysID) { var child, doc, doctype, i, j, k, len, len1, ref1, ref2; doc = this.document(); doctype = new XMLDocType(doc, pubID, sysID); ref1 = doc.children; // Replace DTD if exists for (i = j = 0, len = ref1.length; j < len; i = ++j) { child = ref1[i]; if (child.type === NodeType.DocType) { doc.children[i] = doctype; return doctype; } } ref2 = doc.children; // insert before root node if the root node exists for (i = k = 0, len1 = ref2.length; k < len1; i = ++k) { child = ref2[i]; if (child.isRoot) { doc.children.splice(i, 0, doctype); return doctype; } } // otherwise append to end doc.children.push(doctype); return doctype; } // Gets the parent node up() { if (this.isRoot) { throw new Error("The root node has no parent. Use doc() if you need to get the document object."); } return this.parent; } // Gets the root node root() { var node; node = this; while (node) { if (node.type === NodeType.Document) { return node.rootObject; } else if (node.isRoot) { return node; } else { node = node.parent; } } } // Gets the node representing the XML document document() { var node; node = this; while (node) { if (node.type === NodeType.Document) { return node; } else { node = node.parent; } } } // Ends the document and converts string end(options) { return this.document().end(options); } // Gets the previous node prev() { var i; i = this.parent.children.indexOf(this); if (i < 1) { throw new Error("Already at the first node. " + this.debugInfo()); } return this.parent.children[i - 1]; } // Gets the next node next() { var i; i = this.parent.children.indexOf(this); if (i === -1 || i === this.parent.children.length - 1) { throw new Error("Already at the last node. " + this.debugInfo()); } return this.parent.children[i + 1]; } // Imports cloned root from another XML document // `doc` the XML document to insert nodes from importDocument(doc) { var child, clonedRoot, j, len, ref1; clonedRoot = doc.root().clone(); clonedRoot.parent = this; clonedRoot.isRoot = false; this.children.push(clonedRoot); // set properties if imported element becomes the root node if (this.type === NodeType.Document) { clonedRoot.isRoot = true; clonedRoot.documentObject = this; this.rootObject = clonedRoot; // set dtd name if (this.children) { ref1 = this.children; for (j = 0, len = ref1.length; j < len; j++) { child = ref1[j]; if (child.type === NodeType.DocType) { child.name = clonedRoot.name; break; } } } } return this; } // Returns debug string for this node debugInfo(name) { var ref1, ref2; name = name || this.name; if ((name == null) && !((ref1 = this.parent) != null ? ref1.name : void 0)) { return ""; } else if (name == null) { return "parent: <" + this.parent.name + ">"; } else if (!((ref2 = this.parent) != null ? ref2.name : void 0)) { return "node: <" + name + ">"; } else { return "node: <" + name + ">, parent: <" + this.parent.name + ">"; } } // Aliases ele(name, attributes, text) { return this.element(name, attributes, text); } nod(name, attributes, text) { return this.node(name, attributes, text); } txt(value) { return this.text(value); } dat(value) { return this.cdata(value); } com(value) { return this.comment(value); } ins(target, value) { return this.instruction(target, value); } doc() { return this.document(); } dec(version, encoding, standalone) { return this.declaration(version, encoding, standalone); } e(name, attributes, text) { return this.element(name, attributes, text); } n(name, attributes, text) { return this.node(name, attributes, text); } t(value) { return this.text(value); } d(value) { return this.cdata(value); } c(value) { return this.comment(value); } r(value) { return this.raw(value); } i(target, value) { return this.instruction(target, value); } u() { return this.up(); } // can be deprecated in a future release importXMLBuilder(doc) { return this.importDocument(doc); } // Adds or modifies an attribute. // `name` attribute name // `value` attribute value attribute(name, value) { throw new Error("attribute() applies to element nodes only."); } att(name, value) { return this.attribute(name, value); } a(name, value) { return this.attribute(name, value); } // Removes an attribute // `name` attribute name removeAttribute(name) { throw new Error("attribute() applies to element nodes only."); } // DOM level 1 functions to be implemented later replaceChild(newChild, oldChild) { throw new Error("This DOM method is not implemented." + this.debugInfo()); } removeChild(oldChild) { throw new Error("This DOM method is not implemented." + this.debugInfo()); } appendChild(newChild) { throw new Error("This DOM method is not implemented." + this.debugInfo()); } hasChildNodes() { return this.children.length !== 0; } cloneNode(deep) { throw new Error("This DOM method is not implemented." + this.debugInfo()); } normalize() { throw new Error("This DOM method is not implemented." + this.debugInfo()); } // DOM level 2 isSupported(feature, version) { return true; } hasAttributes() { return this.attribs.length !== 0; } // DOM level 3 functions to be implemented later compareDocumentPosition(other) { var ref, res; ref = this; if (ref === other) { return 0; } else if (this.document() !== other.document()) { res = DocumentPosition.Disconnected | DocumentPosition.ImplementationSpecific; if (Math.random() < 0.5) { res |= DocumentPosition.Preceding; } else { res |= DocumentPosition.Following; } return res; } else if (ref.isAncestor(other)) { return DocumentPosition.Contains | DocumentPosition.Preceding; } else if (ref.isDescendant(other)) { return DocumentPosition.Contains | DocumentPosition.Following; } else if (ref.isPreceding(other)) { return DocumentPosition.Preceding; } else { return DocumentPosition.Following; } } isSameNode(other) { throw new Error("This DOM method is not implemented." + this.debugInfo()); } lookupPrefix(namespaceURI) { throw new Error("This DOM method is not implemented." + this.debugInfo()); } isDefaultNamespace(namespaceURI) { throw new Error("This DOM method is not implemented." + this.debugInfo()); } lookupNamespaceURI(prefix) { throw new Error("This DOM method is not implemented." + this.debugInfo()); } isEqualNode(node) { var i, j, ref1; if (node.nodeType !== this.nodeType) { return false; } if (node.children.length !== this.children.length) { return false; } for (i = j = 0, ref1 = this.children.length - 1; (0 <= ref1 ? j <= ref1 : j >= ref1); i = 0 <= ref1 ? ++j : --j) { if (!this.children[i].isEqualNode(node.children[i])) { return false; } } return true; } getFeature(feature, version) { throw new Error("This DOM method is not implemented." + this.debugInfo()); } setUserData(key, data, handler) { throw new Error("This DOM method is not implemented." + this.debugInfo()); } getUserData(key) { throw new Error("This DOM method is not implemented." + this.debugInfo()); } // Returns true if other is an inclusive descendant of node, // and false otherwise. contains(other) { if (!other) { return false; } return other === this || this.isDescendant(other); } // An object A is called a descendant of an object B, if either A is // a child of B or A is a child of an object C that is a descendant of B. isDescendant(node) { var child, isDescendantChild, j, len, ref1; ref1 = this.children; for (j = 0, len = ref1.length; j < len; j++) { child = ref1[j]; if (node === child) { return true; } isDescendantChild = child.isDescendant(node); if (isDescendantChild) { return true; } } return false; } // An object A is called an ancestor of an object B if and only if // B is a descendant of A. isAncestor(node) { return node.isDescendant(this); } // An object A is preceding an object B if A and B are in the // same tree and A comes before B in tree order. isPreceding(node) { var nodePos, thisPos; nodePos = this.treePosition(node); thisPos = this.treePosition(this); if (nodePos === -1 || thisPos === -1) { return false; } else { return nodePos < thisPos; } } // An object A is folllowing an object B if A and B are in the // same tree and A comes after B in tree order. isFollowing(node) { var nodePos, thisPos; nodePos = this.treePosition(node); thisPos = this.treePosition(this); if (nodePos === -1 || thisPos === -1) { return false; } else { return nodePos > thisPos; } } // Returns the preorder position of the given node in the tree, or -1 // if the node is not in the tree. treePosition(node) { var found, pos; pos = 0; found = false; this.foreachTreeNode(this.document(), function(childNode) { pos++; if (!found && childNode === node) { return found = true; } }); if (found) { return pos; } else { return -1; } } // Depth-first preorder traversal through the XML tree foreachTreeNode(node, func) { var child, j, len, ref1, res; node || (node = this.document()); ref1 = node.children; for (j = 0, len = ref1.length; j < len; j++) { child = ref1[j]; if (res = func(child)) { return res; } else { res = this.foreachTreeNode(child, func); if (res) { return res; } } } } }; // DOM level 1 Object.defineProperty(XMLNode.prototype, 'nodeName', { get: function() { return this.name; } }); Object.defineProperty(XMLNode.prototype, 'nodeType', { get: function() { return this.type; } }); Object.defineProperty(XMLNode.prototype, 'nodeValue', { get: function() { return this.value; } }); Object.defineProperty(XMLNode.prototype, 'parentNode', { get: function() { return this.parent; } }); Object.defineProperty(XMLNode.prototype, 'childNodes', { get: function() { if (!this.childNodeList || !this.childNodeList.nodes) { this.childNodeList = new XMLNodeList(this.children); } return this.childNodeList; } }); Object.defineProperty(XMLNode.prototype, 'firstChild', { get: function() { return this.children[0] || null; } }); Object.defineProperty(XMLNode.prototype, 'lastChild', { get: function() { return this.children[this.children.length - 1] || null; } }); Object.defineProperty(XMLNode.prototype, 'previousSibling', { get: function() { var i; i = this.parent.children.indexOf(this); return this.parent.children[i - 1] || null; } }); Object.defineProperty(XMLNode.prototype, 'nextSibling', { get: function() { var i; i = this.parent.children.indexOf(this); return this.parent.children[i + 1] || null; } }); Object.defineProperty(XMLNode.prototype, 'ownerDocument', { get: function() { return this.document() || null; } }); // DOM level 3 Object.defineProperty(XMLNode.prototype, 'textContent', { get: function() { var child, j, len, ref1, str; if (this.nodeType === NodeType.Element || this.nodeType === NodeType.DocumentFragment) { str = ''; ref1 = this.children; for (j = 0, len = ref1.length; j < len; j++) { child = ref1[j]; if (child.textContent) { str += child.textContent; } } return str; } else { return null; } }, set: function(value) { throw new Error("This DOM method is not implemented." + this.debugInfo()); } }); return XMLNode; }).call(this); }).call(this);