Skip to content

Commit

Permalink
Merge pull request #43 from calebmer/fix/cdata-text-mix
Browse files Browse the repository at this point in the history
Support non-Element XML nodes directly.
  • Loading branch information
nfarina authored Dec 26, 2016
2 parents 521109a + 38fabed commit ff87c44
Show file tree
Hide file tree
Showing 3 changed files with 331 additions and 81 deletions.
129 changes: 93 additions & 36 deletions lib/xmldoc.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,6 @@ function XmlElement(tag) {
this.name = tag.name;
this.attr = tag.attributes;
this.val = "";
this.isValCdata = false;
this.isValComment = false;
this.children = [];
this.firstChild = null;
this.lastChild = null;
Expand All @@ -39,18 +37,24 @@ function XmlElement(tag) {
this.startTagPosition = parser.startTagPosition;
}

// SaxParser handlers

XmlElement.prototype._opentag = function(tag) {
// Private methods

var child = new XmlElement(tag);

XmlElement.prototype._addChild = function(child) {
// add to our children array
this.children.push(child);

// update first/last pointers
if (!this.firstChild) this.firstChild = child;
this.lastChild = child;
};

// SaxParser handlers

XmlElement.prototype._opentag = function(tag) {

var child = new XmlElement(tag);

this._addChild(child);

delegates.unshift(child);
};
Expand All @@ -60,18 +64,26 @@ XmlElement.prototype._closetag = function() {
};

XmlElement.prototype._text = function(text) {
this.val = text;
if (typeof this.children === 'undefined')
return

this.val += text;

this._addChild(new XmlTextNode(text));
};

XmlElement.prototype._cdata = function(cdata) {
this.val = cdata;
this.isValCdata=true;
this.val += cdata;

this._addChild(new XmlCDataNode(cdata));
};

XmlElement.prototype._comment = function(comment) {
this.val = comment;
this.isValComment=true;
}
if (typeof this.children === 'undefined')
return

this._addChild(new XmlCommentNode(comment));
};

XmlElement.prototype._error = function(err) {
throw err;
Expand All @@ -81,7 +93,8 @@ XmlElement.prototype._error = function(err) {

XmlElement.prototype.eachChild = function(iterator, context) {
for (var i=0, l=this.children.length; i<l; i++)
if (iterator.call(context, this.children[i], i, this.children) === false) return;
if (this.children[i].type === "element")
if (iterator.call(context, this.children[i], i, this.children) === false) return;
};

XmlElement.prototype.childNamed = function(name) {
Expand All @@ -105,7 +118,7 @@ XmlElement.prototype.childrenNamed = function(name) {
XmlElement.prototype.childWithAttribute = function(name,value) {
for (var i=0, l=this.children.length; i<l; i++) {
var child = this.children[i];
if ( (value && child.attr[name] === value) || (!value && child.attr[name]) )
if (child.type === "element" && ((value && child.attr[name] === value) || (!value && child.attr[name])))
return child;
}
return undefined;
Expand All @@ -116,7 +129,7 @@ XmlElement.prototype.descendantWithPath = function(path) {
var components = path.split('.');

for (var i=0, l=components.length; i<l; i++)
if (descendant)
if (descendant && descendant.type === "element")
descendant = descendant.childNamed(components[i]);
else
return undefined;
Expand Down Expand Up @@ -148,38 +161,70 @@ XmlElement.prototype.toStringWithIndent = function(indent, options) {
if (Object.prototype.hasOwnProperty.call(this.attr, name))
s += " " + name + '="' + escapeXML(this.attr[name]) + '"';

var finalVal = '';
if (this.isValCdata){
finalVal = '<![CDATA['+this.val+']]>';
} else if (preserveWhitespace) {
finalVal = escapeXML(this.val);
} else{
finalVal = escapeXML(this.val.trim());
if (this.children.length === 1 && this.children[0].type !== "element") {
s += ">" + this.children[0].toString(options) + "</" + this.name + ">";
}
if (options && options.trimmed && finalVal.length > 25)
finalVal = finalVal.substring(0,25).trim() + "…";

if (this.children.length) {
else if (this.children.length) {
s += ">" + linebreak;

var childIndent = indent + (options && options.compressed ? "" : " ");

if (finalVal.length)
s += childIndent + finalVal + linebreak;

for (var i=0, l=this.children.length; i<l; i++)
for (var i=0, l=this.children.length; i<l; i++) {
s += this.children[i].toStringWithIndent(childIndent, options) + linebreak;

}

s += indent + "</" + this.name + ">";
}
else if (finalVal.length) {
s += ">" + finalVal + "</" + this.name +">";
}
else s += "/>";

return s;
};

// Alternative XML nodes

function XmlTextNode (text) {
this.text = text;
}

XmlTextNode.prototype.toString = function(options) {
return formatText(escapeXML(this.text), options);
};

XmlTextNode.prototype.toStringWithIndent = function(indent, options) {
return indent+this.toString(options);
};

function XmlCDataNode (cdata) {
this.cdata = cdata;
}

XmlCDataNode.prototype.toString = function(options) {
return "<![CDATA["+formatText(this.cdata, options)+"]]>";
};

XmlCDataNode.prototype.toStringWithIndent = function(indent, options) {
return indent+this.toString(options);
};

function XmlCommentNode (comment) {
this.comment = comment;
}

XmlCommentNode.prototype.toString = function(options) {
return "<!--"+formatText(escapeXML(this.comment), options)+"-->";
};

XmlCommentNode.prototype.toStringWithIndent = function(indent, options) {
return indent+this.toString(options);
};

// Node type tag

XmlElement.prototype.type = "element";
XmlTextNode.prototype.type = "text";
XmlCDataNode.prototype.type = "cdata";
XmlCommentNode.prototype.type = "comment";

/*
XmlDocument is the class we expose to the user; it uses the sax parser to create a hierarchy
of XmlElements.
Expand Down Expand Up @@ -263,6 +308,18 @@ function escapeXML(value){
return value.replace(/&/g, '&amp;').replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/'/g, '&apos;').replace(/"/g, '&quot;');
}

// formats some text for debugging given a few options
function formatText(text, options) {
var finalText = text;

if (options && options.trimmed && text.length > 25)
finalText = finalText.substring(0,25).trim() + "…";
if (!(options && options.preserveWhitespace))
finalText = finalText.trim();

return finalText;
}

// Are we being used in a Node-like environment?
if (typeof module !== 'undefined' && module.exports && !global.xmldocAssumeBrowser)
module.exports.XmlDocument = XmlDocument;
Expand Down
4 changes: 4 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@
{
"name": "Nick Farina",
"email": "nfarina@gmail.com"
},
{
"name": "Caleb Meredith",
"email": "calebmeredith8@gmail.com"
}
],
"readmeFilename": "README.md",
Expand Down
Loading

0 comments on commit ff87c44

Please # to comment.