diff options
author | buraq <buraq@epfl.ch> | 2003-06-13 12:40:21 +0000 |
---|---|---|
committer | buraq <buraq@epfl.ch> | 2003-06-13 12:40:21 +0000 |
commit | ee7107b4ab266bf5e9ee904e2b5bf22e3b2b856a (patch) | |
tree | 90d50c9a4546b905b285f4a6d443faf0dace1dee | |
parent | 4269eb620a51b4039a33523289f85f82c270493b (diff) | |
download | scala-ee7107b4ab266bf5e9ee904e2b5bf22e3b2b856a.tar.gz scala-ee7107b4ab266bf5e9ee904e2b5bf22e3b2b856a.tar.bz2 scala-ee7107b4ab266bf5e9ee904e2b5bf22e3b2b856a.zip |
classes for XML tool dtd2scala
-rw-r--r-- | sources/scala/xml/DeclToScala.java | 377 | ||||
-rw-r--r-- | sources/scala/xml/FactoryAdapter.java | 349 | ||||
-rw-r--r-- | sources/scala/xml/XMLDecl.java | 14 | ||||
-rw-r--r-- | sources/scala/xml/decl2scala.java | 183 |
4 files changed, 923 insertions, 0 deletions
diff --git a/sources/scala/xml/DeclToScala.java b/sources/scala/xml/DeclToScala.java new file mode 100644 index 0000000000..7eeb9538b1 --- /dev/null +++ b/sources/scala/xml/DeclToScala.java @@ -0,0 +1,377 @@ +package scala.xml ; + +import java.io.Writer ; +import java.io.PrintWriter ; +import java.io.OutputStream ; +import java.io.OutputStreamWriter ; + +import java.util.Map ; +import java.util.Iterator ; + +import scala.xml.XMLDecl ; +import XMLDecl.* ; + +import scalac.util.Name ; +import scalac.ast.parser.Scanner ; + + +public class DeclToScala { + + + static final String ATTRIBS_VALDEF = +"val _at:scala.Map[String,String] = if( attribs == null ) { new scala.HashMap[String,String] } else attribs ;"; + static final String ATTRIB_MAP = "attribs"; + static final String ATTRIB_T = "scala.Map[String,String]"; + + static final String CHILDREN_VALDEF = +"val _ch:SeqList[Element] = if( children == null ) { scala.SeqNil[Element] } else children ;"; + static final String CHILDREN_SEQ = "children"; + static final String CHILDREN_T = "scala.SeqList[Element]"; + + static final String RAW_NAME_DEF = "def getName:String = "; + + static final String GET_CHILDREN_DEF = "def getChildren:scala.SeqList[Element] = _ch ;"; + static final String GET_ATTRIBS_DEF = "def getAttribs:scala.Map[String,String] = _at ;"; + + static final int IND_STEP = 5; + + public DeclToScala() { + + fOut = new PrintWriter( System.out ); + this.moduleName = "myXML" ; + + } + + public DeclToScala( String moduleName ) { + + fOut = new PrintWriter( System.out ); + this.moduleName = moduleName ; + } + + String moduleName ; + + PrintWriter fOut ; + + int fIndent ; + + public void begin() { + fOut.println( "// this file is generated from a DTD"); + fOut.print( "module " ); + fOut.print( moduleName ); + fOut.println(" with {"); + fIndent = IND_STEP; + printIndent(); + fOut.println("import scala.xml ;"); + } + + public void end() { + fOut.println("}"); + fOut.flush(); + fOut.close(); + } + + /** Sets the output stream for printing. */ + /* + public void setOutput(OutputStream stream, String encoding) + throws java.io.UnsupportedEncodingException { + + if (encoding == null) { + encoding = "UTF8"; + } + + Writer writer = new OutputStreamWriter(stream, encoding); + fOut = new PrintWriter(writer); + + } // setOutput(OutputStream,String) + */ + /** + * @name - (raw) name of the Element + */ + void printClassDef( ElemDecl decl ) { + String clazzName = cookedCap( decl.name ); + + printIndent(); + + // convenience ! overloaded constructors, have to appear *before* + // the class def and need the "final" modifier + + fOut.println( "final def "+clazzName+"(ch:SeqList[Element]):"+clazzName+" = new "+clazzName+"( null[scala.Map[String,String]], ch ) ;" ); + + printIndent(); + + fOut.println( "final def "+clazzName+"( el:Element ):"+clazzName+" = new "+clazzName+"( null[scala.Map[String,String]], el::SeqNil[Element] ) ;" ); + + printIndent(); + // might contain text + if( decl.contentModel.indexOf("#PCDATA") != -1 ) { + + fOut.println( "final def "+clazzName+"( text:String ):"+clazzName+" = new "+clazzName+"( null[scala.Map[String,String]], PCDATA( text )::SeqNil[Element] ) ;" ); + printIndent(); + + } + + fOut.print( "case class " ); + + fOut.print( clazzName ); + + fOut.print('('); + fOut.print( ATTRIB_MAP ); fOut.print(':'); fOut.print( ATTRIB_T ); + fOut.print(','); + fOut.print( CHILDREN_SEQ ); fOut.print(':'); fOut.print( CHILDREN_T ); + fOut.print(')'); + + fOut.println(" extends Element with {"); + fIndent += IND_STEP ; + + printIndent(); + fOut.print( RAW_NAME_DEF ); + fOut.print('"'); fOut.print( decl.name ); fOut.print('"'); + fOut.println(';'); + + printIndent(); fOut.println( ATTRIBS_VALDEF ); + printIndent(); fOut.println( GET_ATTRIBS_DEF ); + printIndent(); fOut.println( CHILDREN_VALDEF ); + printIndent(); fOut.println( GET_CHILDREN_DEF ); + + + for( Iterator it = decl.attribs.keySet().iterator(); it.hasNext() ; ) + toScala( (AttrDecl) decl.attribs.get( it.next() )); + + fIndent -= IND_STEP ; + printIndent(); + fOut.println("}"); + fOut.flush(); + } + + /** Prints the indent. */ + void printIndent() { + for (int i = 0; i < fIndent; i++) { + fOut.print(' '); + } + } + + /** + * @name - (raw) name of the attribute + */ + void printSetMethod( String name ) { + printIndent(); + + fOut.print( "def " ); + fOut.print( cooked( name )); + fOut.print( "( arg:String ):Unit = _at.put(\"" ); + fOut.print( name ); + fOut.println( "\", arg ) ;"); + } + + /** + * @name - (raw) name of the attribute + */ + void printGetMethod( String name ) { + printIndent(); + + fOut.print( "def " ); + fOut.print( cooked( name )); + fOut.print( ":String = _at.get( "); + fOut.print( '"' );fOut.print( name );fOut.print( '"' ); + fOut.println( " ) ;"); + } + + void printFactory( Map elemMap ) { + + printIndent(); + fOut.println( +"val _factory: scala.Map[String, (scala.Map[String,String],scala.SeqList[Element])Element] = {"); + fIndent += IND_STEP; + printIndent(); + fOut.println( +"val res = new scala.HashMap[String,(scala.Map[String,String],scala.SeqList[Element])Element] ;"); + for(Iterator it = elemMap.keySet().iterator(); it.hasNext(); ) { + ElemDecl decl = (ElemDecl) elemMap.get( it.next() ); + printIndent(); + fOut.print( "res.put(\"" ); + fOut.print( decl.name ); + fOut.print( "\","); + fOut.print( cookedCap( decl.name )); + fOut.println(");"); + } + printIndent(); + fOut.println("res"); + printIndent(); + fOut.println( "}"); + fIndent -= IND_STEP; + + } + + void printContainsTextDef( Map elemMap ) { + printIndent(); + fOut.println("val _containsMap: scala.Map[String, Boolean] = {"); + fIndent += IND_STEP; + printIndent(); + fOut.println("val res = new scala.HashMap[String, Boolean] ;"); + + for(Iterator it = elemMap.keySet().iterator(); it.hasNext(); ) { + ElemDecl decl = (ElemDecl) elemMap.get( it.next() ); + printIndent(); + fOut.print( "res.put(\"" ); + fOut.print( decl.name ); + fOut.print( "\","); + + if( decl.contentModel.indexOf("#PCDATA") != -1 ) + fOut.print("True"); + else + fOut.print("False"); + + fOut.println(");"); + } + printIndent(); + fOut.println("res"); + fIndent -= IND_STEP; + printIndent(); + fOut.println( "}"); + } + + /* + name match { + case "groupname" => True; + case "name" => True; + case _ =>False + } + } + } + */ + + void printLoaderDef( ) { + printIndent(); + fOut.println("def load( filename:String ):Element = {"); + fIndent += IND_STEP; + printIndent(); + fOut.println("val fAdapter = new ScalaFactoryAdapter with {"); + fIndent += IND_STEP; + printIndent(); + fOut.println("val f = _factory ;"); + printIndent(); + fOut.println("val g = _containsMap ; "); + printIndent(); + fOut.println("};"); + fIndent -= IND_STEP; + printIndent(); + fOut.println("val b:scala.Object = fAdapter.loadXML( filename );"); + printIndent(); + fOut.println("b.as[ Element ]"); + printIndent(); + fOut.println("};"); + fIndent -= IND_STEP; + } + + public void toScala( Map elemMap ) { + begin(); + + fOut.println("/** the following elements are there"); + for(Iterator it = elemMap.keySet().iterator(); it.hasNext(); ) { + + ElemDecl decl = (ElemDecl) elemMap.get( it.next() ); + fOut.print(" * "); + fOut.print( decl.name ); + fOut.print(" : ["); + fOut.print( decl.contentModel ); + fOut.println(']'); + fOut.print(" * "); + fOut.println( "attribs: "+decl.attribs.keySet() ); + } + fOut.println("*/"); + + + for(Iterator it = elemMap.keySet().iterator(); it.hasNext(); ) { + + ElemDecl decl = (ElemDecl) elemMap.get( it.next() ); + toScala( decl ); + + } + printContainsTextDef( elemMap ); + printFactory( elemMap ); + printLoaderDef(); + + end(); + } + + public void toScala( XMLDecl decl ) { + switch(decl) { + case ElemDecl( _, _, _): + + printClassDef( (ElemDecl) decl ); + break; + + case AttrDecl( String name, String attrType ): + + if( attrType.equals("CDATA") ) { + //printSetMethod(name); + printGetMethod(name); + + } else { // ignore non-CDATA attribs + + System.err.print("[ignoring attribute \"" + +name+"\" of type \"" + +attrType+"\"]"); + } + break; + default: + System.err.println("unexpected XMLDecl"); + System.exit(-1); + } + } + + + // + // cooking raw names + // + + String cooked(StringBuffer cooked, String raw, int off) { + char ch; + for( int i = off; i < raw.length(); i++ ) { + switch( ch = raw.charAt( i ) ) { + case '-': + case ':': + cooked.append( '_' );break; + + default: + cooked.append( ch ); break; + } + } + + if( toy.isKeyword(raw)) + cooked.append('$'); + + return cooked.toString(); + + } + + // type -> type$ + // http-equiv -> http_equiv + + String cooked(String raw) { + return cooked(new StringBuffer(), raw, 0); + } + + // type -> Type$ + // http-equiv -> Http_equiv + + String cookedCap(String raw) { + StringBuffer cooked = new StringBuffer(); + cooked.append( Character.toUpperCase( raw.charAt( 0 ) )); + return cooked( cooked, raw, 1); + } + /* + static class ToyScanner extends Scanner { + public ToyScanner() { + initKeywords(); + } + + boolean isKeyword( String str ) { + Name name = Name.fromString( str ); + return (name.index <= maxKey) ; + } + } + */ + static Scanner toy = new Scanner(); + +} diff --git a/sources/scala/xml/FactoryAdapter.java b/sources/scala/xml/FactoryAdapter.java new file mode 100644 index 0000000000..ee037cfd12 --- /dev/null +++ b/sources/scala/xml/FactoryAdapter.java @@ -0,0 +1,349 @@ +package scala.xml ; +// MIT License + +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.io.PrintWriter; +import java.io.UnsupportedEncodingException; +import java.io.Writer; + +import java.util.Map ; +import java.util.HashMap ; +import java.util.LinkedList ; +import java.util.Stack ; +import java.util.Iterator ; + +import org.xml.sax.Attributes; +import org.xml.sax.ContentHandler; + + +import org.xml.sax.ErrorHandler; +import org.xml.sax.Locator; + +import org.xml.sax.SAXException; +import org.xml.sax.SAXNotRecognizedException; +import org.xml.sax.SAXNotSupportedException; +import org.xml.sax.SAXParseException; +import org.xml.sax.XMLReader; +import org.xml.sax.helpers.DefaultHandler; +import org.xml.sax.helpers.ParserAdapter; + +import org.xml.sax.helpers.XMLReaderFactory; + + +/** 2do: + - handle MixedContent properly ! + - ? canonical XML ? + - performance ( java Array <-> scala.Array ) + */ +public abstract class FactoryAdapter + extends DefaultHandler + implements ContentHandler, ErrorHandler // SAX2 +{ + + // default settings + + /** Default parser name. */ + protected static final String + DEFAULT_PARSER_NAME = "org.apache.xerces.parsers.SAXParser"; + + /** Namespaces feature id (http://xml.org/sax/features/namespaces). */ + protected static final String NAMESPACES_FEATURE_ID = "http://xml.org/sax/features/namespaces"; + + // + // Constructors + // + + /** Default constructor. */ + public FactoryAdapter() { + buffer = new StringBuffer(); + attribStack = new Stack(); + hStack = new Stack(); + tagStack = new Stack(); + //fOut = new PrintWriter( System.out ); + } // <init>() + + + // Data + + Stack hStack; // [ element ] contains siblings + Stack tagStack; // [String] + + Stack attribStack; + + String curTag ; + + StringBuffer buffer; + boolean capture; + + // these are defined in a scala class + + abstract boolean elementContainsText( String localName ) ; + + abstract scala.Object createElement(String elemName, + Map attribs, + Iterator chIter ); + + abstract scala.Object createPCDATA( String text ); + + + // + // ContentHandler methods + // + + /** Set document locator. */ + public void setDocumentLocator(Locator locator) { + } + + /** Start document. */ + public void startDocument() throws SAXException { + } + + + /** Characters. */ + public void characters(char[] ch, int offset, int length) + throws SAXException { + + boolean ws = false; + + //System.err.println( "before \""+buffer+"\"" ); + + if( capture ) + for( int i = offset; i < offset + length; i++ ) + if( Character.isWhitespace( ch[ i ] )) { + if( !ws ) { + buffer.append(' '); + ws = true; + } + } else { + buffer.append( ch[ i ] ); + ws = false; + } + + //System.err.println( "after \""+buffer+"\"" ); + //System.err.println(); + + } // characters(char[],int,int) + + /** Ignorable whitespace. */ + public void ignorableWhitespace(char[] ch, int offset, int length) + throws SAXException { + } + + /** End document. */ + public void endDocument() throws SAXException { + } + + // + // ContentHandler methods + // + + /** Start prefix mapping. */ + public void startPrefixMapping(String prefix, String uri) + throws SAXException { + } + + + + /** Start element. */ + public void startElement(String uri, String localName, String qname, + Attributes attributes) throws SAXException { + + captureText(); + + tagStack.push( curTag ); + curTag = localName ; + + capture = elementContainsText(localName) ; + + hStack.push( null ); + HashMap map = null; + + if (attributes == null) { + //fOut.println("null"); + } + else { + map = new HashMap(); + + int length = attributes.getLength(); + for (int i = 0; i < length; i++) { + String attrLocalName = attributes.getLocalName(i); + //String attrQName = attributes.getQName(i); + //String attrURI = attributes.getURI(i); + String attrType = attributes.getType(i); + String attrValue = attributes.getValue(i); + if( attrType.equals("CDATA") ) + map.put( attrLocalName, attrValue ); + + } + } + attribStack.push( map ); + + } // startElement(String,String,String,Attributes) + + + /** this way to deal with whitespace is quite nonstandard, but useful + */ + + void captureText() { + if( capture == true ) { + hStack.push( createPCDATA(buffer.toString() )); + } + buffer.setLength( 0 ); + } + + /** End element. */ + public void endElement(String uri, String localName, String qname) + throws SAXException { + + captureText(); + + + Map attribMap = (HashMap) attribStack.pop(); + + // reverse order to get it right + + LinkedList v = new LinkedList(); + scala.Object child = (scala.Object) hStack.pop(); + while( child != null ) { + v.addFirst( child ); + child = (scala.Object) hStack.pop(); + } + + // create element + + rootElem = createElement( localName, attribMap, v.iterator() ); + hStack.push( rootElem ); + + // set + + curTag = (String) tagStack.pop(); + + if( curTag != null ) // root level + capture = elementContainsText( curTag ); + else + capture = false; + + } // endElement(String,String,String) + + /** End prefix mapping. */ + public void endPrefixMapping(String prefix) throws SAXException { + } + + /** Skipped entity. */ + public void skippedEntity(String name) throws SAXException { + } + + // + // ErrorHandler methods + // + + /** Warning. */ + public void warning(SAXParseException ex) throws SAXException { + printError("Warning", ex); + } + + /** Error. */ + public void error(SAXParseException ex) throws SAXException { + printError("Error", ex); + } + + /** Fatal error. */ + public void fatalError(SAXParseException ex) throws SAXException { + printError("Fatal Error", ex); + throw ex; + } + + // + // Protected methods + // + + + /** Prints the error message. */ + protected void printError(String type, SAXParseException ex) { + + System.err.print("["); + System.err.print(type); + System.err.print("] "); + + String systemId = ex.getSystemId(); + if (systemId != null) { + int index = systemId.lastIndexOf('/'); + if (index != -1) + systemId = systemId.substring(index + 1); + //System.err.print(systemId); + } + + System.err.print(':'); + System.err.print(ex.getLineNumber()); + System.err.print(':'); + System.err.print(ex.getColumnNumber()); + System.err.print(": "); + System.err.print(ex.getMessage()); + System.err.println(); + System.err.flush(); + + } // printError(String,SAXParseException) + + scala.Object rootElem ; + // + // MAIN + // + + public scala.Object loadXML( String fileName ) { + + // variables + //PrintWriter out = new PrintWriter(System.out); + XMLReader parser = null; + + // use default parser + // create parser + try { + parser = XMLReaderFactory.createXMLReader(DEFAULT_PARSER_NAME); + } + catch (Exception e) { + System.err.println("error: Unable to instantiate parser ("+DEFAULT_PARSER_NAME+")"); + System.exit(-1); + } + + // set parser features + try { + parser.setFeature(NAMESPACES_FEATURE_ID, true); + } + catch (SAXException e) { + System.err.println("warning: Parser does not support feature ("+NAMESPACES_FEATURE_ID+")"); + } + + // set handlers + + parser.setErrorHandler( this ); + + if (parser instanceof XMLReader) { + parser.setContentHandler( this ); + } else { + System.err.println("wrong parser"); + System.exit(-1); + } + + // parse file + try { + System.err.println("[parsing \""+fileName+"\"]"); + parser.parse( fileName ); + } + catch (SAXParseException e) { + // ignore + } + catch (Exception e) { + System.err.println("error: Parse error occurred - "+e.getMessage()); + if (e instanceof SAXException) { + e = ((SAXException)e).getException(); + } + e.printStackTrace(System.err); + } + + return rootElem; + + } // loadXML + +} // class FactoryAdapter + diff --git a/sources/scala/xml/XMLDecl.java b/sources/scala/xml/XMLDecl.java new file mode 100644 index 0000000000..169c826677 --- /dev/null +++ b/sources/scala/xml/XMLDecl.java @@ -0,0 +1,14 @@ +package scala.xml ; + +import java.util.Map ; + +public class XMLDecl { + + case ElemDecl( String name, + String contentModel, + Map attribs); /*AttrDecl[]*/ + + case AttrDecl( String name, + String type ); // ignore default values + +} diff --git a/sources/scala/xml/decl2scala.java b/sources/scala/xml/decl2scala.java new file mode 100644 index 0000000000..5e2a6b86da --- /dev/null +++ b/sources/scala/xml/decl2scala.java @@ -0,0 +1,183 @@ +package scala.xml ; + +import org.xml.sax.SAXParseException; +import org.xml.sax.SAXException; +import org.xml.sax.XMLReader; +import org.xml.sax.helpers.DefaultHandler; +import org.xml.sax.helpers.XMLReaderFactory; +import org.xml.sax.Attributes; +import org.xml.sax.ext.DeclHandler; + +import java.util.Map ; +import java.util.HashMap ; +import java.util.TreeMap ; +import java.util.Iterator ; + +import XMLDecl.* ; + +/** 2 do : + - use DTD Handler to get the name of the DTD, use this as module name + - handle modes of attributes (add #REQUIRED ones, fill in default of #IMPLIED) + - allow package prefix to be given ! + - allow output directory to be given ! + */ + +public class dtd2scala + extends DefaultHandler + implements DeclHandler +{ + + static final String + DEFAULT_PARSER_NAME = "org.apache.xerces.parsers.SAXParser" ; + + public Map elemMap; // elementName -> elementDecl + + public dtd2scala() { + elemMap = new HashMap(); + } + + // DTDHandler methods + + /** Element declaration. */ + public void elementDecl(String name, String contentModel) + throws SAXException { + + ElemDecl decl = (ElemDecl) elemMap.get( name ); + + if( decl == null ) { + elemMap.put( name, decl = new ElemDecl( name, + contentModel, + new HashMap() )); + } else { + decl.contentModel = contentModel; + } + /* + System.out.print("element:"); + + System.out.print("[name:" + name); + + System.out.print(" contentModel:" + contentModel); + + System.out.println("]"); + */ + } // elementDecl(String,String) + + /** Attribute declaration. */ + public void attributeDecl(String elementName, String attributeName, + String type, String valueDefault, + String value) throws SAXException { + Map attribs; + + ElemDecl decl = (ElemDecl) elemMap.get( elementName ); + + if( decl == null ) { + attribs = new TreeMap(); + elemMap.put( elementName, + decl = new ElemDecl( elementName, + null, + attribs )); + } else { + attribs = decl.attribs; + } + + attribs.put( attributeName, new AttrDecl(attributeName, + type )); + + /* + System.out.print("attributes["); + System.out.print("elementName=" + elementName+","); + + System.out.print("attributeName=" + attributeName); + + System.out.println("]"); + */ + } // attributeDecl(String,String,String,String,String) + + + /** Internal entity declaration. */ + public void internalEntityDecl(String name, String text) + throws SAXException { + // ignore + } + + /** External entity declaration. */ + public void externalEntityDecl(String name, + String publicId, String systemId) + throws SAXException { + // ignore + } + + public void print() { + for(Iterator it = elemMap.keySet().iterator(); it.hasNext(); ) { + ElemDecl decl = (ElemDecl) elemMap.get( it.next() ); + System.out.print(decl.name); + AttrDecl adecl = null; + System.out.print("{"); + for(Iterator it2 = decl.attribs.keySet().iterator(); + it2.hasNext(); ) { + if(adecl != null) + System.out.print(","); + adecl = (AttrDecl) decl.attribs.get( it2.next() ); + System.out.print(adecl.name+":"+adecl.type); + } + System.out.println("}"); + } + + + } + + + public void print2( String moduleName ) { + + DeclToScala translate = new DeclToScala( moduleName ); + + translate.toScala( elemMap ); + + } + // main + + public static void main(String[] argv) throws Exception { + + + if( argv.length != 2 ) { + System.out.println("argument ?"); + System.exit( 0 ); + } + + String sysID = argv[ 0 ]; + dtd2scala myH = new dtd2scala(); + + XMLReader parser = + XMLReaderFactory.createXMLReader( DEFAULT_PARSER_NAME ); + + try { + parser.setProperty("http://xml.org/sax/properties/declaration-handler", myH); + } + catch (SAXException e) { + e.printStackTrace(System.err); + } + + try { + parser.parse( sysID ); + } + catch (SAXParseException e) { + + System.err.println("SaxParseEx"); + e.printStackTrace( System.err ); + + } + catch (Exception e) { + System.err.println("error: Parse error occurred - "+e.getMessage()); + if (e instanceof SAXException) { + e = ((SAXException)e).getException(); + } + e.printStackTrace(System.err); + } + + //myH.print(); + + myH.print2( argv[ 1 ] ); // todo:replace by root element + } // main + + +} // class MyDTDHandler |