Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- window.parseXML = (function() {
- var xnode = function(name, attributes) {
- // Node attributes
- this.attributes = attributes || {};
- // Children nodes, initially empty
- this.children = [];
- // Node name
- this.name = name;
- },
- xtext = function(value) {
- this.value = value;
- };
- function forEachNode(node, callback) {
- // Iterate each node and execute callback
- for(var x = 0, childNode; childNode = node.children[x]; x ++) callback(childNode);
- }
- xnode['prototype'] = {
- find: function(name) {
- // All elements got by name
- var result = [];
- // Iterate each child of node
- function checkChildren(node) {
- forEachNode(node, function(childNode) {
- // Check if children have tag name
- if(childNode instanceof xnode) checkChildren(childNode);
- // Check if current node has tag name
- if(childNode.name === name) result.push(childNode);
- });
- }
- checkChildren(this);
- return result;
- }
- };
- // parseXML :: function
- return (function(Buf) {
- // XML root
- var chunk = new xnode();
- // Inner location
- var locations = [ chunk ];
- // Consume characters until callback returns a positive value
- function consumeUntil(fnc, except) {
- var string = '',
- hasEnded = false;
- var hasExc = typeof except === 'function';
- // Iterate characters
- for(; CharCode = Buf.charCodeAt(I); I ++) {
- if( hasExc ? !except() : true ) {
- // Check if function returns falsy value
- if(!fnc()) string += String.fromCharCode(CharCode)
- // Or end the loop
- ;else {
- hasEnded = true;
- break;
- }
- }
- }
- return {
- hasEnded: hasEnded,
- string: string
- };
- }
- // Check if string is space or line terminator
- function isBlankToken() {
- return CharCode === 9 || CharCode === 10 || CharCode === 13 || CharCode === 32;
- }
- // Check if string is start of a node name
- function isNodeNameStart() {
- // A - Z
- return (CharCode >= 65 && CharCode <= 90) ||
- // a - z
- (CharCode >= 97 && CharCode <= 122);
- }
- // Check if string is part of a node name
- function isNodeNamePart() {
- // A - Z
- return (CharCode >= 65 && CharCode <= 90) ||
- // a - z
- (CharCode >= 97 && CharCode <= 122) ||
- // 0 - 9
- (CharCode >= 48 && CharCode <= 57) ||
- // -
- CharCode === 45 ||
- // .
- CharCode === 46 ||
- // :
- CharCode === 58 ||
- // _
- CharCode === 95;
- }
- // Move to the next string
- function moveToNextChar() {
- I ++;
- CharCode = Buf.charCodeAt(I);
- }
- // Iterate characters
- for(var I = 0, CharCode; CharCode = Buf.charCodeAt(I); I ++) {
- // Check if string is '<'
- if(CharCode === 60) {
- // Move to the next string
- moveToNextChar();
- // Check if the next string is '/'
- if(CharCode === 47) {
- var nameSearch = consumeUntil(function() {
- return CharCode === 62;
- }, function() {
- return isBlankToken();
- });
- // Get the index of the last location
- var lastInnerIndex = locations.length - 1;
- // Check if the string has been correctly consumed (ended with '>') and check if it's not empty;
- // And check if the string is equal to the name of the location node.
- if(nameSearch.hasEnded &&
- nameSearch.string.length > 0 &&
- nameSearch.string === locations[lastInnerIndex].name) {
- // Then close the node path
- locations.splice(lastInnerIndex, 1);
- }
- }
- // Check if the string is '!'
- else if(CharCode === 33 || CharCode === 63) { // Comment; while the parser isn't update, every tag like <? is gonna be ignored.
- // Check if the comment starts with --
- if(CharCode !== 63 && Buf.substring(I + 1, I + 3) === '--') {
- I += 2;
- // Then the comment ends with -->
- consumeUntil(function() {
- return CharCode === 45 && Buf.substring(I + 1, I + 3) === '->';
- });
- I += 2;
- }
- // Else the comment ends at '>' or until the end of the XML string
- else {
- consumeUntil(function() {
- return CharCode === 62;
- });
- }
- }
- // Check if the string is start of a node name
- else if(isNodeNameStart()) {
- // The node attributes object
- var attributes = {};
- var nodeNameStart = String.fromCharCode(CharCode);
- // Move to next character to not count with the name start
- moveToNextChar();
- // Get the following string of the node name
- var nodeName = nodeNameStart + consumeUntil(function() {
- return !isNodeNamePart();
- }).string;
- // Consume node inner, or ignore the inner case there's a typo
- var reconsume = function() {
- // NOTE
- // Char 47 = /
- // Char 62 = >
- // End node as a path >
- if(CharCode === 62) {
- // Create the node element
- var node = new xnode(nodeName, attributes);
- // Push the node to the last path
- locations[locations.length - 1].children.push(node);
- // Create node path where goes the children
- locations.push(node);
- }
- // End node without path />
- else if(CharCode === 47) {
- moveToNextChar();
- // Check if next char is >
- if(CharCode === 62) {
- // Create the node element
- var node = new xnode(nodeName, attributes);
- // Push the node to the last path
- locations[locations.length - 1].children.push(node);
- }
- }
- // Search for attributes
- else {
- // Skip blank or unconsiderable characters
- var skipSearch = consumeUntil(function() {
- return !isBlankToken() || CharCode === 47 || CharCode === 62;
- });
- // Check if attribute start has BEEN declared!
- if(skipSearch.hasEnded && CharCode !== 62) {
- // Get full attribute name
- var attrName = consumeUntil(function() {
- return isBlankToken() || CharCode === 47 || CharCode === 62 || CharCode === 61;
- }).string;
- // Set the attribute value as true while not defined
- attributes[attrName] = true;
- // Skip blank characters
- consumeUntil(function() {
- return !isBlankToken();
- });
- // Check if char is assign
- if(CharCode === 61) {
- moveToNextChar();
- // Check if next character is not blank
- if(!isBlankToken() && CharCode !== 34 && CharCode !== 39) {
- // Then consume free value
- var frAttrValue = consumeUntil(function() {
- return isBlankToken() || CharCode === 47 || CharCode === 62;
- }).string;
- attributes[attrName] = frAttrValue || true;
- reconsume();
- }
- else{
- // Then skip blank characters again
- consumeUntil(function() {
- return !isBlankToken();
- });
- // Check if string is " or '
- if(CharCode === 34 || CharCode === 39) {
- // Memorize quote
- var quote = CharCode;
- // Skip the quote
- moveToNextChar();
- // Then consume characters until quote happens
- var attrValueSearch = consumeUntil(function() {
- return CharCode === quote;
- });
- // Skip the final quote, also
- moveToNextChar();
- if(attrValueSearch.hasEnded) {
- attributes[attrName] = attrValueSearch.string || true;
- reconsume()
- }
- }else reconsume();
- }
- }
- else{
- reconsume();
- }
- }
- }
- };
- reconsume();
- }
- // Else ignore the tag
- }
- else{
- var lastCharCode,
- text = consumeUntil(function() {
- return CharCode === 60;
- }, function() {
- var allowSpace = (lastCharCode === 9 || lastCharCode === 32) &&
- (CharCode === 9 || CharCode === 32) ? false : true ;
- lastCharCode = CharCode;
- return (CharCode === 10 && CharCode === 13) || !allowSpace;
- }).string;
- // Decrease index to not bug a node
- I --;
- if(text.length > 0) {
- // Create the text node
- var textNode = new xtext(text);
- // Push the text node to the last path
- locations[locations.length - 1].children.push(textNode);
- }
- }
- }
- return chunk;
- });
- })();
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement