Spaces:
Sleeping
Sleeping
| LOG.inform("XMLDOC.Parser loaded"); | |
| /** | |
| * XML Parser object. Returns an {@link #XMLDOC.Parser.node} which is | |
| * the root element of the parsed document. | |
| * <p/> | |
| * By default, this parser will only handle well formed XML. To | |
| * allow the parser to handle HTML, set the <tt>XMLDOC.Parser.strictMode</tt> | |
| * variable to <tt>false</tt> before calling <tt>XMLDOC.Parser.parse()</tt>. | |
| * <p/> | |
| * <i>Note: If you pass poorly formed XML, it will cause the parser to throw | |
| * an exception.</i> | |
| * | |
| * @author Brett Fattori (bfattori@fry.com) | |
| * @author $Author: micmath $ | |
| * @version $Revision: 497 $ | |
| */ | |
| XMLDOC.Parser = {}; | |
| /** | |
| * Strict mode setting. Setting this to false allows HTML-style source to | |
| * be parsed. Normally, well formed XML has defined end tags, or empty tags | |
| * are properly formed. Default: <tt>true</tt> | |
| * @type Boolean | |
| */ | |
| XMLDOC.Parser.strictMode = true; | |
| /** | |
| * A node in an XML Document. Node types are ROOT, ELEMENT, COMMENT, PI, and TEXT. | |
| * @param parent {XMLDOC.Parser.node} The parent node | |
| * @param name {String} The node name | |
| * @param type {String} One of the types | |
| */ | |
| XMLDOC.Parser.node = function(parent, name, type) | |
| { | |
| this.name = name; | |
| this.type = type || "ELEMENT"; | |
| this.parent = parent; | |
| this.charData = ""; | |
| this.attrs = {}; | |
| this.nodes = []; | |
| this.cPtr = 0; | |
| XMLDOC.Parser.node.prototype.getAttributeNames = function() { | |
| var a = []; | |
| for (var o in this.attrs) | |
| { | |
| a.push(o); | |
| } | |
| return a; | |
| }; | |
| XMLDOC.Parser.node.prototype.getAttribute = function(attr) { | |
| return this.attrs[attr]; | |
| }; | |
| XMLDOC.Parser.node.prototype.setAttribute = function(attr, val) { | |
| this.attrs[attr] = val; | |
| }; | |
| XMLDOC.Parser.node.prototype.getChild = function(idx) { | |
| return this.nodes[idx]; | |
| }; | |
| XMLDOC.Parser.node.prototype.parentNode = function() { | |
| return this.parent; | |
| }; | |
| XMLDOC.Parser.node.prototype.firstChild = function() { | |
| return this.nodes[0]; | |
| }; | |
| XMLDOC.Parser.node.prototype.lastChild = function() { | |
| return this.nodes[this.nodes.length - 1]; | |
| }; | |
| XMLDOC.Parser.node.prototype.nextSibling = function() { | |
| var p = this.parent; | |
| if (p && (p.nodes.indexOf(this) + 1 != p.nodes.length)) | |
| { | |
| return p.getChild(p.nodes.indexOf(this) + 1); | |
| } | |
| return null; | |
| }; | |
| XMLDOC.Parser.node.prototype.prevSibling = function() { | |
| var p = this.parent; | |
| if (p && (p.nodes.indexOf(this) - 1 >= 0)) | |
| { | |
| return p.getChild(p.nodes.indexOf(this) - 1); | |
| } | |
| return null; | |
| }; | |
| }; | |
| /** | |
| * Parse an XML Document from the specified source. The XML should be | |
| * well formed, unless strict mode is disabled, then the parser will | |
| * handle HTML-style XML documents. | |
| * @param src {String} The source to parse | |
| */ | |
| XMLDOC.Parser.parse = function(src) | |
| { | |
| var A = []; | |
| // Normailize whitespace | |
| A = src.split("\r\n"); | |
| src = A.join("\n"); | |
| A = src.split("\r"); | |
| src = A.join("\n"); | |
| // Remove XML and DOCTYPE specifier | |
| src.replace(/<\?XML .*\?>/i, ""); | |
| src.replace(/<!DOCTYPE .*\>/i, ""); | |
| // The document is the root node and cannot be modified or removed | |
| var doc = new XMLDOC.Parser.node(null, "ROOT", "DOCUMENT"); | |
| // Let's break it down | |
| XMLDOC.Parser.eat(doc, src); | |
| return doc; | |
| }; | |
| /** | |
| * The XML fragment processing routine. This method is private and should not be called | |
| * directly. | |
| * @param parentNode {XMLDOC.Parser.node} The node which is the parent of this fragment | |
| * @param src {String} The source within the fragment to process | |
| * @private | |
| */ | |
| XMLDOC.Parser.eat = function(parentNode, src) | |
| { | |
| // A simple tag def | |
| var reTag = new RegExp("<(!|)(\\?|--|)((.|\\s)*?)\\2>","g"); | |
| // Special tag types | |
| var reCommentTag = /<!--((.|\s)*?)-->/; | |
| var rePITag = /<\?((.|\s)*?)\?>/; | |
| // A start tag (with potential empty marker) | |
| var reStartTag = /<(.*?)( +([\w_\-]*)=(\"|')(.*)\4)*(\/)?>/; | |
| // An empty HTML style tag (not proper XML, but we'll accept it so we can process HTML) | |
| var reHTMLEmptyTag = /<(.*?)( +([\w_\-]*)=(\"|')(.*)\4)*>/; | |
| // Fully enclosing tag with nested tags | |
| var reEnclosingTag = /<(.*?)( +([\w_\-]*)=(\"|')(.*?)\4)*>((.|\s)*?)<\/\1>/; | |
| // Breaks down attributes | |
| var reAttributes = new RegExp(" +([\\w_\\-]*)=(\"|')(.*?)\\2","g"); | |
| // Find us a tag | |
| var tag; | |
| while ((tag = reTag.exec(src)) != null) | |
| { | |
| if (tag.index > 0) | |
| { | |
| // The next tag has some text before it | |
| var text = src.substring(0, tag.index).replace(/^[ \t\n]+((.|\n)*?)[ \t\n]+$/, "$1"); | |
| if (text.length > 0 && (text != "\n")) | |
| { | |
| var txtnode = new XMLDOC.Parser.node(parentNode, "", "TEXT"); | |
| txtnode.charData = text; | |
| // Append the new text node | |
| parentNode.nodes.push(txtnode); | |
| } | |
| // Reset the lastIndex of reTag | |
| reTag.lastIndex -= src.substring(0, tag.index).length; | |
| // Eat the text | |
| src = src.substring(tag.index); | |
| } | |
| if (reCommentTag.test(tag[0])) | |
| { | |
| // Is this a comment? | |
| var comment = new XMLDOC.Parser.node(parentNode, "", "COMMENT"); | |
| comment.charData = reCommentTag.exec(tag[0])[1]; | |
| // Append the comment | |
| parentNode.nodes.push(comment); | |
| // Move the lastIndex of reTag | |
| reTag.lastIndex -= tag[0].length; | |
| // Eat the tag | |
| src = src.replace(reCommentTag, ""); | |
| } | |
| else if (rePITag.test(tag[0])) | |
| { | |
| // Is this a processing instruction? | |
| var pi = new XMLDOC.Parser.node(parentNode, "", "PI"); | |
| pi.charData = rePITag.exec(tag[0])[1]; | |
| // Append the processing instruction | |
| parentNode.nodes.push(pi); | |
| // Move the lastIndex of reTag | |
| reTag.lastIndex -= tag[0].length; | |
| // Eat the tag | |
| src = src.replace(rePITag, ""); | |
| } | |
| else if (reStartTag.test(tag[0])) | |
| { | |
| // Break it down | |
| var e = reStartTag.exec(tag[0]); | |
| var elem = new XMLDOC.Parser.node(parentNode, e[1], "ELEMENT"); | |
| // Get attributes from the tag | |
| var a; | |
| while ((a = reAttributes.exec(e[2])) != null ) | |
| { | |
| elem.attrs[a[1]] = a[3]; | |
| } | |
| // Is this an empty XML-style tag? | |
| if (e[6] == "/") | |
| { | |
| // Append the empty element | |
| parentNode.nodes.push(elem); | |
| // Move the lastIndex of reTag (include the start tag length) | |
| reTag.lastIndex -= e[0].length; | |
| // Eat the tag | |
| src = src.replace(reStartTag, ""); | |
| } | |
| else | |
| { | |
| // Check for malformed XML tags | |
| var htmlParsed = false; | |
| var htmlStartTag = reHTMLEmptyTag.exec(src); | |
| // See if there isn't an end tag within this block | |
| var reHTMLEndTag = new RegExp("</" + htmlStartTag[1] + ">"); | |
| var htmlEndTag = reHTMLEndTag.exec(src); | |
| if (XMLDOC.Parser.strictMode && htmlEndTag == null) | |
| { | |
| // Poorly formed XML fails in strict mode | |
| var err = new Error("Malformed XML passed to XMLDOC.Parser... Error contains malformed 'src'"); | |
| err.src = src; | |
| throw err; | |
| } | |
| else if (htmlEndTag == null) | |
| { | |
| // This is an HTML-style empty tag, store the element for it in non-strict mode | |
| parentNode.nodes.push(elem); | |
| // Eat the tag | |
| src = src.replace(reHTMLEmptyTag, ""); | |
| htmlParsed = true; | |
| } | |
| // If we didn't parse HTML-style, it must be an enclosing tag | |
| if (!htmlParsed) | |
| { | |
| var enc = reEnclosingTag.exec(src); | |
| // Go deeper into the document | |
| XMLDOC.Parser.eat(elem, enc[6]); | |
| // Append the new element node | |
| parentNode.nodes.push(elem); | |
| // Eat the tag | |
| src = src.replace(reEnclosingTag, ""); | |
| } | |
| } | |
| // Reset the lastIndex of reTag | |
| reTag.lastIndex = 0; | |
| } | |
| } | |
| // No tag was found... append the text if there is any | |
| src = src.replace(/^[ \t\n]+((.|\n)*?)[ \t\n]+$/, "$1"); | |
| if (src.length > 0 && (src != "\n")) | |
| { | |
| var txtNode = new XMLDOC.Parser.node(parentNode, "", "TEXT"); | |
| txtNode.charData = src; | |
| // Append the new text node | |
| parentNode.nodes.push(txtNode); | |
| } | |
| }; | |