topical media & game development

talk show tell print

professional-ria-03-xmlsax.js / js



  // =========================================================================
  //
  // xmlsax.js - an XML SAX parser in JavaScript.
  //
  // version 3.1
  //
  // =========================================================================
  //
  // Copyright (C) 2001 - 2002 David Joham (djoham@yahoo.com) and Scott Severtson
  //
  // This library is free software; you can redistribute it and/or
  // modify it under the terms of the GNU Lesser General Public
  // License as published by the Free Software Foundation; either
  // version 2.1 of the License, or (at your option) any later version.
  
  // This library is distributed in the hope that it will be useful,
  // but WITHOUT ANY WARRANTY; without even the implied warranty of
  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  // Lesser General Public License for more details.
  
  // You should have received a copy of the GNU Lesser General Public
  // License along with this library; if not, write to the Free Software
  // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  //
  //
  // Visit the XML for <SCRIPT> home page at http://xmljs.sourceforge.net
  //
  
  // CONSTANTS
  
  // =========================================================================
  // =========================================================================
  // =========================================================================
  var whitespace = "\n\r\t ";
  
  
************************************************************************************************************* XMLP is a pull-based parser. The calling application passes in a XML string to the constructor, then repeatedly calls .next() to parse the next segment. .next() returns a flag indicating what type of segment was found, and stores data temporarily in couple member variables (name, content, array of attributes), which can be accessed by several .get____() methods.

  Basically, XMLP is the lowest common denominator parser - an very simple
  API which other wrappers can be built against.
  *****************************************************************************************************************/
  
  XMLP = function(strXML) {
      
***************************************************************************************************************** function: this is the constructor to the XMLP Object

      Author:   Scott Severtson
  
      Description:
          Instantiates and initializes the object
      *********************************************************************************************************************/
      // Normalize line breaks
      strXML = SAXStrings.replace(strXML, null, null, "\r\n", "\n");
      strXML = SAXStrings.replace(strXML, null, null, "\r", "\n");
  
      this.m_xml = strXML;
      this.m_iP = 0;
      this.m_iState = XMLP._STATE_PROLOG;
      this.m_stack = new Stack();
      this._clearAttributes();
  
  }  // end XMLP constructor
  
  // CONSTANTS    (these must be below the constructor)
  
  // =========================================================================
  // =========================================================================
  // =========================================================================
  
  XMLP._NONE    = 0;
  XMLP._ELM_B   = 1;
  XMLP._ELM_E   = 2;
  XMLP._ELM_EMP = 3;
  XMLP._ATT     = 4;
  XMLP._TEXT    = 5;
  XMLP._ENTITY  = 6;
  XMLP._PI      = 7;
  XMLP._CDATA   = 8;
  XMLP._COMMENT = 9;
  XMLP._DTD     = 10;
  XMLP._ERROR   = 11;
  
  XMLP._CONT_XML = 0;
  XMLP._CONT_ALT = 1;
  
  XMLP._ATT_NAME = 0;
  XMLP._ATT_VAL  = 1;
  
  XMLP._STATE_PROLOG = 1;
  XMLP._STATE_DOCUMENT = 2;
  XMLP._STATE_MISC = 3;
  
  XMLP._errs = new Array();
  XMLP._errs[XMLP.ERR_CLOSE_PI       = 0 ] = "PI: missing closing sequence";
  XMLP._errs[XMLP.ERR_CLOSE_DTD      = 1 ] = "DTD: missing closing sequence";
  XMLP._errs[XMLP.ERR_CLOSE_COMMENT  = 2 ] = "Comment: missing closing sequence";
  XMLP._errs[XMLP.ERR_CLOSE_CDATA    = 3 ] = "CDATA: missing closing sequence";
  XMLP._errs[XMLP.ERR_CLOSE_ELM      = 4 ] = "Element: missing closing sequence";
  XMLP._errs[XMLP.ERR_CLOSE_ENTITY   = 5 ] = "Entity: missing closing sequence";
  XMLP._errs[XMLP.ERR_PI_TARGET      = 6 ] = "PI: target is required";
  XMLP._errs[XMLP.ERR_ELM_EMPTY      = 7 ] = "Element: cannot be both empty and closing";
  XMLP._errs[XMLP.ERR_ELM_NAME       = 8 ] = "Element: name must immediatly follow \"<\"";
  XMLP._errs[XMLP.ERR_ELM_LT_NAME    = 9 ] = "Element: \"<\" not allowed in element names";
  XMLP._errs[XMLP.ERR_ATT_VALUES     = 10] = "Attribute: values are required and must be in quotes";
  XMLP._errs[XMLP.ERR_ATT_LT_NAME    = 11] = "Element: \"<\" not allowed in attribute names";
  XMLP._errs[XMLP.ERR_ATT_LT_VALUE   = 12] = "Attribute: \"<\" not allowed in attribute values";
  XMLP._errs[XMLP.ERR_ATT_DUP        = 13] = "Attribute: duplicate attributes not allowed";
  XMLP._errs[XMLP.ERR_ENTITY_UNKNOWN = 14] = "Entity: unknown entity";
  XMLP._errs[XMLP.ERR_INFINITELOOP   = 15] = "Infininte loop";
  XMLP._errs[XMLP.ERR_DOC_STRUCTURE  = 16] = "Document: only comments, processing instructions, or whitespace allowed outside of document element";
  XMLP._errs[XMLP.ERR_ELM_NESTING    = 17] = "Element: must be nested correctly";
  
  // =========================================================================
  // =========================================================================
  // =========================================================================
  
  XMLP.prototype._addAttribute = function(name, value) {
      
***************************************************************************************************************** function: _addAttribute

      Author:   Scott Severtson
      *********************************************************************************************************************/
      this.m_atts[this.m_atts.length] = new Array(name, value);
  }  // end function _addAttribute
  
  XMLP.prototype._checkStructure = function(iEvent) {
      
***************************************************************************************************************** function: _checkStructure

      Author:   Scott Severtson
      *********************************************************************************************************************/
    
          if(XMLP._STATE_PROLOG == this.m_iState) {
                  if((XMLP._TEXT == iEvent) || (XMLP._ENTITY == iEvent)) {
              if(SAXStrings.indexOfNonWhitespace(this.getContent(), this.getContentBegin(), this.getContentEnd()) != -1) {
                                  return this._setErr(XMLP.ERR_DOC_STRUCTURE);
              }
          }
  
          if((XMLP._ELM_B == iEvent) || (XMLP._ELM_EMP == iEvent)) {
              this.m_iState = XMLP._STATE_DOCUMENT;
              // Don't return - fall through to next state
          }
      }
      if(XMLP._STATE_DOCUMENT == this.m_iState) {
          if((XMLP._ELM_B == iEvent) || (XMLP._ELM_EMP == iEvent)) {
              this.m_stack.push(this.getName());
          }
  
          if((XMLP._ELM_E == iEvent) || (XMLP._ELM_EMP == iEvent)) {
              var strTop = this.m_stack.pop();
              if((strTop == null) || (strTop != this.getName())) {
                  return this._setErr(XMLP.ERR_ELM_NESTING);
              }
          }
  
          if(this.m_stack.count() == 0) {
              this.m_iState = XMLP._STATE_MISC;
              return iEvent;
          }
      }
      if(XMLP._STATE_MISC == this.m_iState) {
                  if((XMLP._ELM_B == iEvent) || (XMLP._ELM_E == iEvent) || (XMLP._ELM_EMP == iEvent) || (XMLP.EVT_DTD == iEvent)) {
                          return this._setErr(XMLP.ERR_DOC_STRUCTURE);
          }
  
          if((XMLP._TEXT == iEvent) || (XMLP._ENTITY == iEvent)) {
                          if(SAXStrings.indexOfNonWhitespace(this.getContent(), this.getContentBegin(), this.getContentEnd()) != -1) {
                                  return this._setErr(XMLP.ERR_DOC_STRUCTURE);
              }
          }
      }
  
      return iEvent;
  
  }  // end function _checkStructure
  
  XMLP.prototype._clearAttributes = function() {
      
***************************************************************************************************************** function: _clearAttributes

      Author:   Scott Severtson
      *********************************************************************************************************************/
      this.m_atts = new Array();
  }  // end function _clearAttributes
  
  XMLP.prototype._findAttributeIndex = function(name) {
      
***************************************************************************************************************** function: findAttributeIndex

      Author:   Scott Severtson
      *********************************************************************************************************************/
      for(var i = 0; i < this.m_atts.length; i++) {
          if(this.m_atts[i][XMLP._ATT_NAME] == name) {
              return i;
          }
      }
      return -1;
  
  }  // end function _findAttributeIndex
  
  XMLP.prototype.getAttributeCount = function() {
      
***************************************************************************************************************** function: getAttributeCount

      Author:   Scott Severtson
      *********************************************************************************************************************/
  
      return this.m_atts ? this.m_atts.length : 0;
  
  }  // end function getAttributeCount()
  
  XMLP.prototype.getAttributeName = function(index) {
      
***************************************************************************************************************** function: getAttributeName

      Author:   Scott Severtson
      *********************************************************************************************************************/
  
      return ((index < 0) || (index >= this.m_atts.length)) ? null : this.m_atts[index][XMLP._ATT_NAME];
  
  }  //end function getAttributeName
  
  XMLP.prototype.getAttributeValue = function(index) {
      
***************************************************************************************************************** function: getAttributeValue

      Author:   Scott Severtson
      *********************************************************************************************************************/
  
      return ((index < 0) || (index >= this.m_atts.length)) ? null : __unescapeString(this.m_atts[index][XMLP._ATT_VAL]);
  
  } // end function getAttributeValue
  
  XMLP.prototype.getAttributeValueByName = function(name) {
      
***************************************************************************************************************** function: getAttributeValueByName

      Author:   Scott Severtson
      *********************************************************************************************************************/
  
      return this.getAttributeValue(this._findAttributeIndex(name));
  
  }  // end function getAttributeValueByName
  
  XMLP.prototype.getColumnNumber = function() {
      
***************************************************************************************************************** function: getColumnNumber

      Author:   Scott Severtson
      *********************************************************************************************************************/
  
      return SAXStrings.getColumnNumber(this.m_xml, this.m_iP);
  
  }  // end function getColumnNumber
  
  XMLP.prototype.getContent = function() {
      
***************************************************************************************************************** function: getContent

      Author:   Scott Severtson
      *********************************************************************************************************************/
  
      return (this.m_cSrc == XMLP._CONT_XML) ? this.m_xml : this.m_cAlt;
  
  }  //end function getContent
  
  XMLP.prototype.getContentBegin = function() {
      
***************************************************************************************************************** function: getContentBegin

      Author:   Scott Severtson
      *********************************************************************************************************************/
  
      return this.m_cB;
  
  }  //end function getContentBegin
  
  XMLP.prototype.getContentEnd = function() {
      
***************************************************************************************************************** function: getContentEnd

      Author:   Scott Severtson
      *********************************************************************************************************************/
  
      return this.m_cE;
  
  }  // end function getContentEnd
  
  XMLP.prototype.getLineNumber = function() {
      
***************************************************************************************************************** function: getLineNumber

      Author:   Scott Severtson
      *********************************************************************************************************************/
  
      return SAXStrings.getLineNumber(this.m_xml, this.m_iP);
  
  }  // end function getLineNumber
  
  XMLP.prototype.getName = function() {
      
***************************************************************************************************************** function: getName

      Author:   Scott Severtson
      *********************************************************************************************************************/
  
      return this.m_name;
  
  }  // end function getName()
  
  XMLP.prototype.next = function() {
      
***************************************************************************************************************** function: next

      Author:   Scott Severtson
      *********************************************************************************************************************/
  
      return this._checkStructure(this._parse());
  
  }  // end function next()
  
  XMLP.prototype._parse = function() {
      
***************************************************************************************************************** function: _parse

      Author:   Scott Severtson
      *********************************************************************************************************************/
  
          if(this.m_iP == this.m_xml.length) {
          return XMLP._NONE;
      }
  
      if(this.m_iP == this.m_xml.indexOf("<?",        this.m_iP)) {
          return this._parsePI     (this.m_iP + 2);
      }
      else if(this.m_iP == this.m_xml.indexOf("<!DOCTYPE", this.m_iP)) {
          return this._parseDTD    (this.m_iP + 9);
      }
      else if(this.m_iP == this.m_xml.indexOf("<!--",      this.m_iP)) {
          return this._parseComment(this.m_iP + 4);
      }
      else if(this.m_iP == this.m_xml.indexOf("<![CDATA[", this.m_iP)) {
          return this._parseCDATA  (this.m_iP + 9);
      }
      else if(this.m_iP == this.m_xml.indexOf("<",         this.m_iP)) {
          return this._parseElement(this.m_iP + 1);
      }
      else if(this.m_iP == this.m_xml.indexOf("&",         this.m_iP)) {
          return this._parseEntity (this.m_iP + 1);
      }
      else{
          return this._parseText   (this.m_iP);
      }
          
  
  }  // end function _parse
  
  XMLP.prototype._parseAttribute = function(iB, iE) {
      
***************************************************************************************************************** function: _parseAttribute

      Author:   Scott Severtson
      *********************************************************************************************************************/
      var iNB, iNE, iEq, iVB, iVE;
      var cQuote, strN, strV;
  
          this.m_cAlt = ""; //resets the value so we don't use an old one by accident (see testAttribute7 in the test suite)
      
          iNB = SAXStrings.indexOfNonWhitespace(this.m_xml, iB, iE);
      if((iNB == -1) ||(iNB >= iE)) {
          return iNB;
      }
  
      iEq = this.m_xml.indexOf("=", iNB);
      if((iEq == -1) || (iEq > iE)) {
          return this._setErr(XMLP.ERR_ATT_VALUES);
      }
  
      iNE = SAXStrings.lastIndexOfNonWhitespace(this.m_xml, iNB, iEq);
  
      iVB = SAXStrings.indexOfNonWhitespace(this.m_xml, iEq + 1, iE);
      if((iVB == -1) ||(iVB > iE)) {
          return this._setErr(XMLP.ERR_ATT_VALUES);
      }
  
      cQuote = this.m_xml.charAt(iVB);
      if(SAXStrings.QUOTES.indexOf(cQuote) == -1) {
          return this._setErr(XMLP.ERR_ATT_VALUES);
      }
  
      iVE = this.m_xml.indexOf(cQuote, iVB + 1);
      if((iVE == -1) ||(iVE > iE)) {
          return this._setErr(XMLP.ERR_ATT_VALUES);
      }
  
      strN = this.m_xml.substring(iNB, iNE + 1);
      strV = this.m_xml.substring(iVB + 1, iVE);
  
      if(strN.indexOf("<") != -1) {
          return this._setErr(XMLP.ERR_ATT_LT_NAME);
      }
  
      if(strV.indexOf("<") != -1) {
          return this._setErr(XMLP.ERR_ATT_LT_VALUE);
      }
  
      strV = SAXStrings.replace(strV, null, null, "\n", " ");
      strV = SAXStrings.replace(strV, null, null, "\t", " ");
          iRet = this._replaceEntities(strV);
      if(iRet == XMLP._ERROR) {
          return iRet;
      }
  
      strV = this.m_cAlt;
  
      if(this._findAttributeIndex(strN) == -1) {
          this._addAttribute(strN, strV);
      }
      else {
          return this._setErr(XMLP.ERR_ATT_DUP);
      }
  
      this.m_iP = iVE + 2;
  
      return XMLP._ATT;
  
  }  // end function _parseAttribute
  
  XMLP.prototype._parseCDATA = function(iB) {
      
***************************************************************************************************************** function: _parseCDATA

      Author:   Scott Severtson
      *********************************************************************************************************************/
      var iE = this.m_xml.indexOf("]]>", iB);
      if (iE == -1) {
          return this._setErr(XMLP.ERR_CLOSE_CDATA);
      }
  
      this._setContent(XMLP._CONT_XML, iB, iE);
  
      this.m_iP = iE + 3;
  
      return XMLP._CDATA;
  
  }  // end function _parseCDATA
  
  XMLP.prototype._parseComment = function(iB) {
      
***************************************************************************************************************** function: _parseComment

      Author:   Scott Severtson
      *********************************************************************************************************************/
      var iE = this.m_xml.indexOf("-" + "->", iB);
      if (iE == -1) {
          return this._setErr(XMLP.ERR_CLOSE_COMMENT);
      }
  
      this._setContent(XMLP._CONT_XML, iB, iE);
  
      this.m_iP = iE + 3;
  
      return XMLP._COMMENT;
  
  }  // end function _parseComment
  
  XMLP.prototype._parseDTD = function(iB) {
      
***************************************************************************************************************** function: _parseDTD

      Author:   Scott Severtson
      *********************************************************************************************************************/
  
      // Eat DTD
  
      var iE, strClose, iInt, iLast;
  
      iE = this.m_xml.indexOf(">", iB);
      if(iE == -1) {
          return this._setErr(XMLP.ERR_CLOSE_DTD);
      }
  
      iInt = this.m_xml.indexOf("[", iB);
      strClose = ((iInt != -1) && (iInt < iE)) ? "]>" : ">";
  
      while(true) {
          // DEBUG: Remove
          if(iE == iLast) {
              return this._setErr(XMLP.ERR_INFINITELOOP);
          }
  
          iLast = iE;
          // DEBUG: Remove End
  
          iE = this.m_xml.indexOf(strClose, iB);
          if(iE == -1) {
              return this._setErr(XMLP.ERR_CLOSE_DTD);
          }
  
          // Make sure it is not the end of a CDATA section
          if (this.m_xml.substring(iE - 1, iE + 2) != "]]>") {
              break;
          }
      }
  
      this.m_iP = iE + strClose.length;
  
      return XMLP._DTD;
  
  }  // end function _parseDTD
  
  XMLP.prototype._parseElement = function(iB) {
      
***************************************************************************************************************** function: _parseElement

      Author:   Scott Severtson
      *********************************************************************************************************************/
      var iE, iDE, iNE, iRet;
      var iType, strN, iLast;
  
      iDE = iE = this.m_xml.indexOf(">", iB);
      if(iE == -1) {
          return this._setErr(XMLP.ERR_CLOSE_ELM);
      }
  
      if(this.m_xml.charAt(iB) == "/") {
          iType = XMLP._ELM_E;
          iB++;
      } else {
          iType = XMLP._ELM_B;
      }
  
      if(this.m_xml.charAt(iE - 1) == "/") {
          if(iType == XMLP._ELM_E) {
              return this._setErr(XMLP.ERR_ELM_EMPTY);
          }
          iType = XMLP._ELM_EMP;
          iDE--;
      }
  
      iDE = SAXStrings.lastIndexOfNonWhitespace(this.m_xml, iB, iDE);
  
      //djohack
      //hack to allow for elements with single character names to be recognized
  
      if (iE - iB != 1 ) {
          if(SAXStrings.indexOfNonWhitespace(this.m_xml, iB, iDE) != iB) {
              return this._setErr(XMLP.ERR_ELM_NAME);
          }
      }
      // end hack -- original code below
  
      /*
      if(SAXStrings.indexOfNonWhitespace(this.m_xml, iB, iDE) != iB)
          return this._setErr(XMLP.ERR_ELM_NAME);
      */
      this._clearAttributes();
  
      iNE = SAXStrings.indexOfWhitespace(this.m_xml, iB, iDE);
      if(iNE == -1) {
          iNE = iDE + 1;
      }
      else {
          this.m_iP = iNE;
          while(this.m_iP < iDE) {
              // DEBUG: Remove
              if(this.m_iP == iLast) return this._setErr(XMLP.ERR_INFINITELOOP);
              iLast = this.m_iP;
              // DEBUG: Remove End
  
              iRet = this._parseAttribute(this.m_iP, iDE);
              if(iRet == XMLP._ERROR) return iRet;
          }
      }
  
      strN = this.m_xml.substring(iB, iNE);
  
      if(strN.indexOf("<") != -1) {
          return this._setErr(XMLP.ERR_ELM_LT_NAME);
      }
  
      this.m_name = strN;
      this.m_iP = iE + 1;
  
      return iType;
  
  }  // end function _parseElement
  
  XMLP.prototype._parseEntity = function(iB) {
      
***************************************************************************************************************** function: _parseEntity

      Author:   Scott Severtson
      *********************************************************************************************************************/
      var iE = this.m_xml.indexOf(";", iB);
      if(iE == -1) {
          return this._setErr(XMLP.ERR_CLOSE_ENTITY);
      }
  
      this.m_iP = iE + 1;
  
      return this._replaceEntity(this.m_xml, iB, iE);
  
  }  // end function _parseEntity
  
  XMLP.prototype._parsePI = function(iB) {
      
***************************************************************************************************************** function: _parsePI

      Author:   Scott Severtson
      *********************************************************************************************************************/
  
      var iE, iTB, iTE, iCB, iCE;
  
      iE = this.m_xml.indexOf("?>", iB);
      if(iE   == -1) {
          return this._setErr(XMLP.ERR_CLOSE_PI);
      }
  
      iTB = SAXStrings.indexOfNonWhitespace(this.m_xml, iB, iE);
      if(iTB == -1) {
          return this._setErr(XMLP.ERR_PI_TARGET);
      }
  
      iTE = SAXStrings.indexOfWhitespace(this.m_xml, iTB, iE);
      if(iTE  == -1) {
          iTE = iE;
      }
  
      iCB = SAXStrings.indexOfNonWhitespace(this.m_xml, iTE, iE);
      if(iCB == -1) {
          iCB = iE;
      }
  
      iCE = SAXStrings.lastIndexOfNonWhitespace(this.m_xml, iCB, iE);
      if(iCE  == -1) {
          iCE = iE - 1;
      }
  
      this.m_name = this.m_xml.substring(iTB, iTE);
      this._setContent(XMLP._CONT_XML, iCB, iCE + 1);
      this.m_iP = iE + 2;
  
      return XMLP._PI;
  
  }  // end function _parsePI
  
  XMLP.prototype._parseText = function(iB) {
      
***************************************************************************************************************** function: _parseText

      Author:   Scott Severtson
      *********************************************************************************************************************/
      var iE, iEE;
  
      iE = this.m_xml.indexOf("<", iB);
      if(iE == -1) {
          iE = this.m_xml.length;
      }
  
      iEE = this.m_xml.indexOf("&", iB);
      if((iEE != -1) && (iEE <= iE)) {
          iE = iEE;
      }
  
      this._setContent(XMLP._CONT_XML, iB, iE);
  
      this.m_iP = iE;
  
      return XMLP._TEXT;
  
  } // end function _parseText
  
  XMLP.prototype._replaceEntities = function(strD, iB, iE) {
      
***************************************************************************************************************** function: _replaceEntities

      Author:   Scott Severtson
      *********************************************************************************************************************/
      if(SAXStrings.isEmpty(strD)) return "";
      iB = iB || 0;
      iE = iE || strD.length;
  
      var iEB, iEE, strRet = "";
  
      iEB = strD.indexOf("&", iB);
      iEE = iB;
  
      while((iEB > 0) && (iEB < iE)) {
          strRet += strD.substring(iEE, iEB);
  
          iEE = strD.indexOf(";", iEB) + 1;
  
          if((iEE == 0) || (iEE > iE)) {
              return this._setErr(XMLP.ERR_CLOSE_ENTITY);
          }
  
          iRet = this._replaceEntity(strD, iEB + 1, iEE - 1);
          if(iRet == XMLP._ERROR) {
              return iRet;
          }
  
          strRet += this.m_cAlt;
  
          iEB = strD.indexOf("&", iEE);
      }
  
      if(iEE != iE) {
          strRet += strD.substring(iEE, iE);
      }
  
      this._setContent(XMLP._CONT_ALT, strRet);
  
      return XMLP._ENTITY;
  
  }  // end function _replaceEntities
  
  XMLP.prototype._replaceEntity = function(strD, iB, iE) {
      
***************************************************************************************************************** function: _replaceEntity

      Author:   Scott Severtson
      *********************************************************************************************************************/
      if(SAXStrings.isEmpty(strD)) return -1;
      iB = iB || 0;
      iE = iE || strD.length;
  
      switch(strD.substring(iB, iE)) {
          case "amp":  strEnt = "&";  break;
          case "lt":   strEnt = "<";  break;
          case "gt":   strEnt = ">";  break;
          case "apos": strEnt = "'";  break;
          case "quot": strEnt = "\""; break;
          default:
              if(strD.charAt(iB) == "#") {
                  strEnt = String.fromCharCode(parseInt(strD.substring(iB + 1, iE)));
              } else {
                  return this._setErr(XMLP.ERR_ENTITY_UNKNOWN);
              }
          break;
      }
      this._setContent(XMLP._CONT_ALT, strEnt);
  
      return XMLP._ENTITY;
  }  // end function _replaceEntity
  
  XMLP.prototype._setContent = function(iSrc) {
      
***************************************************************************************************************** function: _setContent

      Author:   Scott Severtson
      *********************************************************************************************************************/
      var args = arguments;
  
      if(XMLP._CONT_XML == iSrc) {
          this.m_cAlt = null;
          this.m_cB = args[1];
          this.m_cE = args[2];
      } else {
          this.m_cAlt = args[1];
          this.m_cB = 0;
          this.m_cE = args[1].length;
      }
      this.m_cSrc = iSrc;
  
  }  // end function _setContent
  
  XMLP.prototype._setErr = function(iErr) {
      
***************************************************************************************************************** function: _setErr

      Author:   Scott Severtson
      *********************************************************************************************************************/
      var strErr = XMLP._errs[iErr];
  
      this.m_cAlt = strErr;
      this.m_cB = 0;
      this.m_cE = strErr.length;
      this.m_cSrc = XMLP._CONT_ALT;
  
      return XMLP._ERROR;
  
  }  // end function _setErr
  
  
************************************************************************************************************* SAXDriver is an object that basically wraps an XMLP instance, and provides an event-based interface for parsing. This is the object users interact with when coding with XML for <SCRIPT> ***************************************************************************************************************

  
  
  SAXDriver = function() {
      
***************************************************************************************************************** function: SAXDriver

      Author:   Scott Severtson
  
      Description:
          This is the constructor for the SAXDriver Object
      *********************************************************************************************************************/
      this.m_hndDoc = null;
      this.m_hndErr = null;
      this.m_hndLex = null;
  }
  
  // CONSTANTS    (these must be below the constructor)
  
  // =========================================================================
  // =========================================================================
  // =========================================================================
  SAXDriver.DOC_B = 1;
  SAXDriver.DOC_E = 2;
  SAXDriver.ELM_B = 3;
  SAXDriver.ELM_E = 4;
  SAXDriver.CHARS = 5;
  SAXDriver.PI    = 6;
  SAXDriver.CD_B  = 7;
  SAXDriver.CD_E  = 8;
  SAXDriver.CMNT  = 9;
  SAXDriver.DTD_B = 10;
  SAXDriver.DTD_E = 11;
  // =========================================================================
  // =========================================================================
  // =========================================================================
  
  SAXDriver.prototype.parse = function(strD) {
      
***************************************************************************************************************** function: parse

      Author:   Scott Severtson
      *********************************************************************************************************************/
      var parser = new XMLP(strD);
  
      if(this.m_hndDoc && this.m_hndDoc.setDocumentLocator) {
          this.m_hndDoc.setDocumentLocator(this);
      }
  
      this.m_parser = parser;
      this.m_bErr = false;
  
      if(!this.m_bErr) {
          this._fireEvent(SAXDriver.DOC_B);
      }
      this._parseLoop();
      if(!this.m_bErr) {
          this._fireEvent(SAXDriver.DOC_E);
      }
  
      this.m_xml = null;
      this.m_iP = 0;
  
  }  // end function parse
  
  SAXDriver.prototype.setDocumentHandler = function(hnd) {
      
***************************************************************************************************************** function: setDocumentHandler

      Author:   Scott Severtson
      *********************************************************************************************************************/
  
      this.m_hndDoc = hnd;
  
  }   // end function setDocumentHandler
  
  SAXDriver.prototype.setErrorHandler = function(hnd) {
      
***************************************************************************************************************** function: setErrorHandler

      Author:   Scott Severtson
      *********************************************************************************************************************/
  
      this.m_hndErr = hnd;
  
  }  // end function setErrorHandler
  
  SAXDriver.prototype.setLexicalHandler = function(hnd) {
      
***************************************************************************************************************** function: setLexicalHandler

      Author:   Scott Severtson
      *********************************************************************************************************************/
  
      this.m_hndLex = hnd;
  
  }  // end function setLexicalHandler
  
      
***************************************************************************************************************** LOCATOR/PARSE EXCEPTION INTERFACE *******************************************************************************************************************

  
  
  SAXDriver.prototype.getColumnNumber = function() {
      
***************************************************************************************************************** function: getSystemId

      Author:   Scott Severtson
      *********************************************************************************************************************/
  
      return this.m_parser.getColumnNumber();
  
  }  // end function getColumnNumber
  
  SAXDriver.prototype.getLineNumber = function() {
      
***************************************************************************************************************** function: getLineNumber

      Author:   Scott Severtson
      *********************************************************************************************************************/
  
      return this.m_parser.getLineNumber();
  
  }  // end function getLineNumber
  
  SAXDriver.prototype.getMessage = function() {
      
***************************************************************************************************************** function: getMessage

      Author:   Scott Severtson
      *********************************************************************************************************************/
  
      return this.m_strErrMsg;
  
  }  // end function getMessage
  
  SAXDriver.prototype.getPublicId = function() {
      
***************************************************************************************************************** function: getPublicID

      Author:   Scott Severtson
      *********************************************************************************************************************/
  
      return null;
  
  }  // end function getPublicID
  
  SAXDriver.prototype.getSystemId = function() {
      
***************************************************************************************************************** function: getSystemId

      Author:   Scott Severtson
      *********************************************************************************************************************/
  
      return null;
  
  }  // end function getSystemId
  
      
***************************************************************************************************************** Attribute List Interface *******************************************************************************************************************

  
  
  SAXDriver.prototype.getLength = function() {
      
***************************************************************************************************************** function: getLength

      Author:   Scott Severtson
      *********************************************************************************************************************/
  
      return this.m_parser.getAttributeCount();
  
  }  // end function getAttributeCount
  
  SAXDriver.prototype.getName = function(index) {
      
***************************************************************************************************************** function: getName

      Author:   Scott Severtson
      *********************************************************************************************************************/
  
      return this.m_parser.getAttributeName(index);
  
  } // end function getAttributeName
  
  SAXDriver.prototype.getValue = function(index) {
      
***************************************************************************************************************** function: getValue

      Author:   Scott Severtson
      *********************************************************************************************************************/
  
      return this.m_parser.getAttributeValue(index);
  
  }  // end function getAttributeValue
  
  SAXDriver.prototype.getValueByName = function(name) {
      
***************************************************************************************************************** function: getValueByName

      Author:   Scott Severtson
      *********************************************************************************************************************/
  
      return this.m_parser.getAttributeValueByName(name);
  
  } // end function getAttributeValueByName
  
      
***************************************************************************************************************** Private functions *******************************************************************************************************************

  
  
  SAXDriver.prototype._fireError = function(strMsg) {
      
***************************************************************************************************************** function: _fireError

      Author:   Scott Severtson
      *********************************************************************************************************************/
      this.m_strErrMsg = strMsg;
      this.m_bErr = true;
  
      if(this.m_hndErr && this.m_hndErr.fatalError) {
          this.m_hndErr.fatalError(this);
      }
  
  }   // end function _fireError
  
  SAXDriver.prototype._fireEvent = function(iEvt) {
      
***************************************************************************************************************** function: _fireEvent

      Author:   Scott Severtson
      *********************************************************************************************************************/
      var hnd, func, args = arguments, iLen = args.length - 1;
  
      if(this.m_bErr) return;
  
      if(SAXDriver.DOC_B == iEvt) {
          func = "startDocument";         hnd = this.m_hndDoc;
      }
      else if (SAXDriver.DOC_E == iEvt) {
          func = "endDocument";           hnd = this.m_hndDoc;
      }
      else if (SAXDriver.ELM_B == iEvt) {
          func = "startElement";          hnd = this.m_hndDoc;
      }
      else if (SAXDriver.ELM_E == iEvt) {
          func = "endElement";            hnd = this.m_hndDoc;
      }
      else if (SAXDriver.CHARS == iEvt) {
          func = "characters";            hnd = this.m_hndDoc;
      }
      else if (SAXDriver.PI    == iEvt) {
          func = "processingInstruction"; hnd = this.m_hndDoc;
      }
      else if (SAXDriver.CD_B  == iEvt) {
          func = "startCDATA";            hnd = this.m_hndLex;
      }
      else if (SAXDriver.CD_E  == iEvt) {
          func = "endCDATA";              hnd = this.m_hndLex;
      }
      else if (SAXDriver.CMNT  == iEvt) {
          func = "comment";               hnd = this.m_hndLex;
      }
  
      if(hnd && hnd[func]) {
          if(0 == iLen) {
              hnd[func]();
          }
          else if (1 == iLen) {
              hnd[func](args[1]);
          }
          else if (2 == iLen) {
              hnd[func](args[1], args[2]);
          }
          else if (3 == iLen) {
              hnd[func](args[1], args[2], args[3]);
          }
      }
  
  }  // end function _fireEvent
  
  SAXDriver.prototype._parseLoop = function(parser) {
      
***************************************************************************************************************** function: _parseLoop

      Author:   Scott Severtson
      *********************************************************************************************************************/
      var iEvent, parser;
  
      parser = this.m_parser;
      while(!this.m_bErr) {
          iEvent = parser.next();
  
          if(iEvent == XMLP._ELM_B) {
              this._fireEvent(SAXDriver.ELM_B, parser.getName(), this);
          }
          else if(iEvent == XMLP._ELM_E) {
              this._fireEvent(SAXDriver.ELM_E, parser.getName());
          }
          else if(iEvent == XMLP._ELM_EMP) {
              this._fireEvent(SAXDriver.ELM_B, parser.getName(), this);
              this._fireEvent(SAXDriver.ELM_E, parser.getName());
          }
          else if(iEvent == XMLP._TEXT) {
              this._fireEvent(SAXDriver.CHARS, parser.getContent(), parser.getContentBegin(), parser.getContentEnd() - parser.getContentBegin());
          }
          else if(iEvent == XMLP._ENTITY) {
              this._fireEvent(SAXDriver.CHARS, parser.getContent(), parser.getContentBegin(), parser.getContentEnd() - parser.getContentBegin());
          }
          else if(iEvent == XMLP._PI) {
              this._fireEvent(SAXDriver.PI, parser.getName(), parser.getContent().substring(parser.getContentBegin(), parser.getContentEnd()));
          }
          else if(iEvent == XMLP._CDATA) {
              this._fireEvent(SAXDriver.CD_B);
              this._fireEvent(SAXDriver.CHARS, parser.getContent(), parser.getContentBegin(), parser.getContentEnd() - parser.getContentBegin());
              this._fireEvent(SAXDriver.CD_E);
          }
          else if(iEvent == XMLP._COMMENT) {
              this._fireEvent(SAXDriver.CMNT, parser.getContent(), parser.getContentBegin(), parser.getContentEnd() - parser.getContentBegin());
          }
          else if(iEvent == XMLP._DTD) {
          }
          else if(iEvent == XMLP._ERROR) {
              this._fireError(parser.getContent());
          }
          else if(iEvent == XMLP._NONE) {
              return;
          }
      }
  
  }  // end function _parseLoop
  
  
************************************************************************************************************* SAXStrings: a useful object containing string manipulation functions ***************************************************************************************************************

  
  
  SAXStrings = function() {
      
***************************************************************************************************************** function: SAXStrings

      Author:   Scott Severtson
  
      Description:
          This is the constructor of the SAXStrings object
      *********************************************************************************************************************/
  }  // end function SAXStrings
  
  // CONSTANTS    (these must be below the constructor)
  
  // =========================================================================
  // =========================================================================
  // =========================================================================
  SAXStrings.WHITESPACE = " \t\n\r";
  SAXStrings.QUOTES = "\"'";
  // =========================================================================
  // =========================================================================
  // =========================================================================
  
  SAXStrings.getColumnNumber = function(strD, iP) {
      
***************************************************************************************************************** function: replace

      Author:   Scott Severtson
      *********************************************************************************************************************/
      if(SAXStrings.isEmpty(strD)) {
          return -1;
      }
      iP = iP || strD.length;
  
      var arrD = strD.substring(0, iP).split("\n");
      var strLine = arrD[arrD.length - 1];
      arrD.length--;
      var iLinePos = arrD.join("\n").length;
  
      return iP - iLinePos;
  
  }  // end function getColumnNumber
  
  SAXStrings.getLineNumber = function(strD, iP) {
      
***************************************************************************************************************** function: getLineNumber

      Author:   Scott Severtson
      *********************************************************************************************************************/
      if(SAXStrings.isEmpty(strD)) {
          return -1;
      }
      iP = iP || strD.length;
  
      return strD.substring(0, iP).split("\n").length
  }  // end function getLineNumber
  
  SAXStrings.indexOfNonWhitespace = function(strD, iB, iE) {
      
***************************************************************************************************************** function: indexOfNonWhitespace

      Author:   Scott Severtson
      *********************************************************************************************************************/
      if(SAXStrings.isEmpty(strD)) {
          return -1;
      }
      iB = iB || 0;
      iE = iE || strD.length;
  
      for(var i = iB; i < iE; i++){
          if(SAXStrings.WHITESPACE.indexOf(strD.charAt(i)) == -1) {
              return i;
          }
      }
      return -1;
  
  }  // end function indexOfNonWhitespace
  
  SAXStrings.indexOfWhitespace = function(strD, iB, iE) {
      
***************************************************************************************************************** function: indexOfWhitespace

      Author:   Scott Severtson
      *********************************************************************************************************************/
      if(SAXStrings.isEmpty(strD)) {
          return -1;
      }
      iB = iB || 0;
      iE = iE || strD.length;
  
      for(var i = iB; i < iE; i++) {
          if(SAXStrings.WHITESPACE.indexOf(strD.charAt(i)) != -1) {
              return i;
          }
      }
      return -1;
  }  // end function indexOfWhitespace
  
  SAXStrings.isEmpty = function(strD) {
      
***************************************************************************************************************** function: isEmpty

      Author:   Scott Severtson
      *********************************************************************************************************************/
  
      return (strD == null) || (strD.length == 0);
  
  }  // end function isEmpty
  
  SAXStrings.lastIndexOfNonWhitespace = function(strD, iB, iE) {
      
***************************************************************************************************************** function: lastIndexOfNonWhiteSpace

      Author:   Scott Severtson
      *********************************************************************************************************************/
      if(SAXStrings.isEmpty(strD)) {
          return -1;
      }
      iB = iB || 0;
      iE = iE || strD.length;
  
      for(var i = iE - 1; i >= iB; i--){
          if(SAXStrings.WHITESPACE.indexOf(strD.charAt(i)) == -1){
              return i;
          }
      }
      return -1;
  }  // end function lastIndexOfNonWhitespace
  
  SAXStrings.replace = function(strD, iB, iE, strF, strR) {
      
***************************************************************************************************************** function: replace

      Author:   Scott Severtson
      *********************************************************************************************************************/
      if(SAXStrings.isEmpty(strD)) {
          return "";
      }
      iB = iB || 0;
      iE = iE || strD.length;
  
      return strD.substring(iB, iE).split(strF).join(strR);
  
  }  // end function replace
  
  
************************************************************************************************************* Stack: A simple stack class, used for verifying document structure. ***************************************************************************************************************

  
  
  Stack = function() {
      
***************************************************************************************************************** function: Stack

      Author:   Scott Severtson
  
      Description:
          Constructor of the Stack Object
      *********************************************************************************************************************/
      this.m_arr = new Array();
  
  }  // end function Stack
  
  Stack.prototype.clear = function() {
      
***************************************************************************************************************** function: clear

      Author:   Scott Severtson
      *********************************************************************************************************************/
  
      this.m_arr = new Array();
  
  }  // end function clear
  
  Stack.prototype.count = function() {
      
***************************************************************************************************************** function: count

      Author:   Scott Severtson
      *********************************************************************************************************************/
  
      return this.m_arr.length;
  
  }  // end function count
  
  Stack.prototype.destroy = function() {
      
***************************************************************************************************************** function: destroy

      Author:   Scott Severtson
      *********************************************************************************************************************/
  
      this.m_arr = null;
  
  }   // end function destroy
  
  Stack.prototype.peek = function() {
      
***************************************************************************************************************** function: peek

      Author:   Scott Severtson
      *********************************************************************************************************************/
      if(this.m_arr.length == 0) {
          return null;
      }
  
      return this.m_arr[this.m_arr.length - 1];
  
  }  // end function peek
  
  Stack.prototype.pop = function() {
      
***************************************************************************************************************** function: pop

      Author:   Scott Severtson
      *********************************************************************************************************************/
      if(this.m_arr.length == 0) {
          return null;
      }
  
      var o = this.m_arr[this.m_arr.length - 1];
      this.m_arr.length--;
      return o;
  
  }  // end function pop
  
  Stack.prototype.push = function(o) {
      
***************************************************************************************************************** function: push

      Author:   Scott Severtson
      *********************************************************************************************************************/
  
      this.m_arr[this.m_arr.length] = o;
  
  }  // end function push
  
  // =========================================================================
  // =========================================================================
  // =========================================================================
  
  // CONVENIENCE FUNCTIONS
  
  // =========================================================================
  // =========================================================================
  // =========================================================================
  
  function isEmpty(str) {
      
***************************************************************************************************************** function: isEmpty

      Author: mike@idle.org
  
      Description:
          convenience function to identify an empty string
  
      *********************************************************************************************************************/
      return (str==null) || (str.length==0);
  
  } // end function isEmpty
  
  function trim(trimString, leftTrim, rightTrim) {
      
***************************************************************************************************************** function: trim

      Author: may106@psu.edu
  
      Description:
          helper function to trip a string (trimString) of leading (leftTrim)
          and trailing (rightTrim) whitespace
  
      *********************************************************************************************************************/
      if (isEmpty(trimString)) {
          return "";
      }
  
      // the general focus here is on minimal method calls - hence only one
      // substring is done to complete the trim.
  
      if (leftTrim == null) {
          leftTrim = true;
      }
  
      if (rightTrim == null) {
          rightTrim = true;
      }
  
      var left=0;
      var right=0;
      var i=0;
      var k=0;
  
      // modified to properly handle strings that are all whitespace
      if (leftTrim == true) {
          while ((i<trimString.length) && (whitespace.indexOf(trimString.charAt(i++))!=-1)) {
              left++;
          }
      }
      if (rightTrim == true) {
          k=trimString.length-1;
          while((k>=left) && (whitespace.indexOf(trimString.charAt(k--))!=-1)) {
              right++;
          }
      }
      return trimString.substring(left, trimString.length - right);
  } // end function trim
  
  
function __escapeString author: David Joham djoham@yahoo.com
parameter: str : string - The string to be escaped
returns: : string - The escaped string

  
  function __escapeString(str) {
  
      var escAmpRegEx = /&/g;
      var escLtRegEx = /</g;
      var escGtRegEx = />/g;
      var quotRegEx = /"/g;
      var aposRegEx = /'/g;
  
      str = str.replace(escAmpRegEx, "&amp;");
      str = str.replace(escLtRegEx, "&lt;");
      str = str.replace(escGtRegEx, "&gt;");
      str = str.replace(quotRegEx, "&quot;");
      str = str.replace(aposRegEx, "&apos;");
  
    return str;
  }
  
  
function __unescapeString author: David Joham djoham@yahoo.com
parameter: str : string - The string to be unescaped
returns: : string - The unescaped string

  
  function __unescapeString(str) {
  
      var escAmpRegEx = /&amp;/g;
      var escLtRegEx = /&lt;/g;
      var escGtRegEx = /&gt;/g;
      var quotRegEx = /&quot;/g;
      var aposRegEx = /&apos;/g;
  
      str = str.replace(escAmpRegEx, "&");
      str = str.replace(escLtRegEx, "<");
      str = str.replace(escGtRegEx, ">");
      str = str.replace(quotRegEx, "\"");
      str = str.replace(aposRegEx, "'");
  
    return str;
  }
  
  


(C) Æliens 20/2/2008

You may not copy or print any of this material without explicit permission of the author or the publisher. In case of other copyright issues, contact the author.