factoryadapter.scala

来自「JAVA 语言的函数式编程扩展」· SCALA 代码 · 共 322 行

SCALA
322
字号
/*                     __                                               *\**     ________ ___   / /  ___     Scala API                            ****    / __/ __// _ | / /  / _ |    (c) 2003-2007, LAMP/EPFL             ****  __\ \/ /__/ __ |/ /__/ __ |    http://scala-lang.org/               **** /____/\___/_/ |_/____/_/ | |                                         ****                          |/                                          **\*                                                                      */// $Id: FactoryAdapter.scala 14634 2008-04-12 00:56:51Z emir $package scala.xml.parsingimport java.io.{InputStream, Reader, File, FileDescriptor, FileInputStream}import scala.collection.mutable.{HashMap,Stack}import org.xml.sax.{Attributes, InputSource}import org.xml.sax.SAXExceptionimport org.xml.sax.SAXNotRecognizedExceptionimport org.xml.sax.SAXNotSupportedExceptionimport org.xml.sax.SAXParseExceptionimport org.xml.sax.helpers.DefaultHandlerimport javax.xml.parsers.SAXParserFactoryimport javax.xml.parsers.ParserConfigurationExceptionimport javax.xml.parsers.SAXParser/** SAX adapter class, for use with Java SAX parser. Keeps track of  *  namespace bindings, without relying on namespace handling of the  *  underlying SAX parser. */abstract class FactoryAdapter extends DefaultHandler() {        val buffer      = new StringBuilder()  val attribStack = new Stack[MetaData]  val hStack      = new Stack[Node]   // [ element ] contains siblings  val tagStack    = new Stack[String]  var scopeStack  = new Stack[NamespaceBinding]  var curTag : String = null  var capture: Boolean = false  // abstract methods  /** Tests if an XML element contains text.   * @return true if element named <code>localName</code> contains text.   */  def nodeContainsText(localName: String): Boolean // abstract    /** creates an new non-text(tree) node.   * @param elemName   * @param attribs   * @param chIter   * @return a new XML element.   */  def createNode(pre: String, elemName: String, attribs: MetaData,                 scope: NamespaceBinding, chIter: List[Node]): Node //abstract     /** creates a Text node.   * @param text   * @return a new Text node.   */  def createText(text: String): Text // abstract  /** creates a new processing instruction node.  */  def createProcInstr(target: String, data: String): Seq[ProcInstr]       //  // ContentHandler methods  //    val normalizeWhitespace = false  /** Characters.  * @param ch  * @param offset  * @param length  */  override def characters(ch: Array[Char], offset: Int, length: Int): Unit = {    if (capture) {      if (normalizeWhitespace) {        // normalizing whitespace is not compliant, but useful */	var i: Int = offset        var ws = false        while (i < offset + length) {          if (ch(i).isWhitespace) {            if (!ws) {              buffer.append(' ')              ws = true            }          } else {            buffer.append(ch(i))            ws = false          }	  i += 1        }      } else { // compliant:report every character        buffer.append(ch, offset, length)      }    }            }  //var elemCount = 0; //STATISTICS  /* ContentHandler methods */  /* Start prefix mapping - use default impl.    def startPrefixMapping( prefix:String , uri:String ):Unit = {}    */  /* Start element. */  override def startElement(uri: String, _localName: String,                            qname: String, attributes: Attributes): Unit = {    /*elemCount = elemCount + 1; STATISTICS */    captureText()    //Console.println("FactoryAdapter::startElement("+uri+","+_localName+","+qname+","+attributes+")");    tagStack.push(curTag)    curTag = qname; //localName ;    val colon = qname.indexOf(':'.asInstanceOf[Int])    val localName = if(-1 == colon) qname else qname.substring(colon+1,qname.length())    //Console.println("FactoryAdapter::startElement - localName ="+localName);    capture = nodeContainsText(localName)    hStack.push(null)    var m: MetaData = Null    var scpe = scopeStack.top    for (i <- List.range(0, attributes.getLength())) {      //val attrType = attributes.getType(i); // unused for now      val qname = attributes.getQName(i)      val value = attributes.getValue(i)      val colon = qname.indexOf(':'.asInstanceOf[Int])      if (-1 != colon) {                     // prefixed attribute        val pre = qname.substring(0, colon)        val key = qname.substring(colon+1, qname.length())        if ("xmlns" /*XML.xmlns*/ == pre)          scpe = value.length() match {            case 0 => new NamespaceBinding(key, null,  scpe)            case _ => new NamespaceBinding(key, value, scpe)          }        else          m = new PrefixedAttribute(pre, key, Text(value), m)      } else if ("xmlns" /*XML.xmlns*/ == qname)        scpe = value.length() match {          case 0 => new NamespaceBinding(null, null,  scpe)          case _ => new NamespaceBinding(null, value, scpe)        }      else        m = new UnprefixedAttribute(qname, Text(value), m)    }    scopeStack.push(scpe)    attribStack.push(m)    ()  } // startElement(String,String,String,Attributes)    /** captures text, possibly normalizing whitespace   */  def captureText(): Unit = {    if (capture) {      val text = buffer.toString()      if (text.length() > 0 && !text.equals(" ")) {        hStack.push(createText(text))      }    }    buffer.setLength(0)  }  /** End element.   * @param uri   * @param localName   * @param qname   * @throws org.xml.sax.SAXException if ..   */  override def endElement(uri: String , _localName: String , qname: String): Unit = {    captureText()    val metaData = attribStack.pop    // reverse order to get it right    var v: List[Node] = Nil    var child: Node = hStack.pop    while (child ne null) {      v = child::v      child = hStack.pop    }    val colon = qname.indexOf(':'.asInstanceOf[Int])    val localName =      if (-1 == colon) qname      else qname.substring(colon+1, qname.length())      val scp = scopeStack.pop    // create element    val pre = if (-1 == colon) null else qname.substring(0, colon)    rootElem = createNode(pre, localName, metaData, scp, v)    hStack.push(rootElem)    // set    curTag = tagStack.pop    capture =      if (curTag ne null) nodeContainsText(curTag) // root level      else false  } // endElement(String,String,String)    /** Processing instruction.  */  override def processingInstruction(target: String, data: String) {    for (pi <- createProcInstr(target, data))      hStack.push(pi)  }    //  // ErrorHandler methods  //  /** Warning.*/  override def warning(ex: SAXParseException): Unit = {    // ignore warning, crimson warns even for entity resolution!    //printError("Warning", ex);  }  /** Error.     */  override def error(ex: SAXParseException): Unit =    printError("Error", ex)   /** Fatal error.*/  override def fatalError(ex: SAXParseException): Unit =    printError("Fatal Error", ex)  //  // Protected methods  //  /** Prints the error message */  protected def printError(errtype: String, ex: SAXParseException): Unit =    Console.withOut(Console.err) {    Console.print("[")    Console.print(errtype)    Console.print("] ")    var systemId = ex.getSystemId()    if (systemId ne null) {      val index = systemId.lastIndexOf('/'.asInstanceOf[Int])      if (index != -1)        systemId = systemId.substring(index + 1)      //Console.print(systemId)    }    Console.print(':')    Console.print(ex.getLineNumber())    Console.print(':')    Console.print(ex.getColumnNumber())    Console.print(": ")    Console.print(ex.getMessage())    Console.println    Console.flush  }  var rootElem: Node = null:Node  //FactoryAdapter  // MAIN  //  /** load XML document   * @param source   * @return a new XML document object   */  def loadXML(source: InputSource): Node = {    // create parser    val parser: SAXParser = try {      val f = SAXParserFactory.newInstance()      f.setNamespaceAware(false)      f.newSAXParser()    } catch {      case e: Exception =>        Console.err.println("error: Unable to instantiate parser")        throw e    }          // parse file    scopeStack.push(TopScope)    parser.parse(source, this)    scopeStack.pop    return rootElem  } // loadXML  /** loads XML from given file */  def loadFile(file: File): Node =    loadXML(new InputSource(new FileInputStream(file)))    /** loads XML from given file descriptor */  def loadFile(fileDesc: FileDescriptor): Node =    loadXML(new InputSource(new FileInputStream(fileDesc)))    /** loads XML from given file */  def loadFile(fileName: String): Node =    loadXML(new InputSource(new FileInputStream(fileName)))    /** loads XML from given InputStream */  def load(is: InputStream): Node =    loadXML(new InputSource(is))  /** loads XML from given Reader */  def load(reader: Reader): Node =    loadXML(new InputSource(reader))  /** loads XML from given sysID */  def load(sysID: String): Node =    loadXML(new InputSource(sysID))}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?