All pastes #29681 Raw Edit

Someone

public java v1 · immutable
#29681 ·published 2005-11-20 18:07 UTC
rendered paste body
/* * SAXdemo.java * Demonstration av grunderna i SAX 2.0 för Java * med extremt detaljerade kommentarer. * Stefan Gustavson (stegu@itn.liu.se) 2003-11-14 * * This source code is in the public domain. */// Import-satserna nedan är med flit specifika - ingen "*" någonstans.// Ett latare men mindre tydligt sätt att ordna samma saker vore:// import java.io.*// import org.xml.sax.*// import org.xml.sax.helpers.*// Nedanstående sätt är faktiskt det som rekommenderas för att inte// Java skall gå vilse bland eventuella klasser med likadana namn.// Dessutom är det i mitt tycke mer pedagogiskt, eftersom endast de// klasser som verkligen används importeras.// Satserna är tillagda vartefter de behövdes under programmeringens// gång. När kompilatorn klagar talar den faktiskt om exakt vilka klasser// som är okända, och dokumentationen från Sun ger sedan snabbt information// om vilka paket dessa klasser ligger i. Använd dokumentationen!import java.io.Writer;import java.io.BufferedWriter;import java.io.OutputStreamWriter;import java.io.IOException;import java.io.UnsupportedEncodingException;import org.xml.sax.XMLReader;import org.xml.sax.helpers.XMLReaderFactory;import org.xml.sax.SAXException;import org.xml.sax.InputSource;import org.xml.sax.Attributes;import org.xml.sax.helpers.DefaultHandler;import org.xml.sax.SAXParseException;// Vår enda klass löser alla problem på en gång. Detta är inte så snyggt,// men det håller detta exempel i en och samma fil, vilket gör det mer// lättläst, lättdistribuerat och även smidigt att skriva ut.// DefaultHandler är en klass som implementerar två interface:// ContentHandler och ErrorHandler. I stället för att skriva// "implements ContentHandler, ErrorHandler" kan man skriva// "extends DefaultHandler" och få alla metoder färdiga.// Defualtmetoderna är tomma (de gör ingenting), men de *finns*,// vilket gör att man kan kompilera sin klass även utan att// implementera alla callback-metoder, även de man inte behöver.class SAXdemo extends DefaultHandler {		// "output" är en buffrad wrapper för en OutputStream som vi använder för	// att skriva Unicode-text med automatisk omkodning till en 8-bitars	// teckenkodning som t ex den gamla soppan som används i Windows	// kommandotolk. Det är pinsamt nog inte ens ANSI-kod, utan den antika	// DOS-kodningen från 80-talet som används av "Kommandotolken"!	// Kodtabellen för denna kodning heter Codepage 850, eller "cp850".		private BufferedWriter output = null;	String tabbar=""; /////////HÄR DEKLARERAR JAG EN GLOBAL STRING SOM JAG ANVÄNDER I MINA TABMETODER		// En explicit konstruktor, för att göra initialiseringar och annat	public SAXdemo() {				// Glöm inte bort att anropa superklassens konstruktor!		// Det är konstruktorn för DefaultHandler som skapar alla bekväma metoder		// åt oss. Nu behöver vi faktiskt inte dem längre, eftersom denna klass i		// sin färdiga form implementerar alla metoder i interfacet, men under		// utvecklingen av en callback-hanterare är det praktiskt att ha de tomma		// defaultmetoderna att luta sig på.		super();				// Skapa en OutputStreamWriter som hanterar teckenkodningen		// i Windows kommandotolk. (Inget av det här är absolut		// nödvändigt för funktionen, men praktiskt för att hantera		// olika teckenkodningar.)		try {			output = new BufferedWriter(new OutputStreamWriter(System.out,"cp850"));		}		// Om "cp850" inte är känd på denna plattform, använd defaultkodningen		catch (UnsupportedEncodingException e) {			output = new BufferedWriter(new OutputStreamWriter(System.out));		};	}		//TVÅ METODER-LÄGG TILL TAB, TA BORT TAB	private void addTab(){				tabbar=tabbar + "\t";	}		private void removeTab(){				tabbar = tabbar.replaceFirst("\t", "");	}	// Vi definierar några privata metoder för att bekvämt kunna skriva ut	// text till vår automatöversättande BufferedWriter.		// Skriv ut en sträng och mata fram till ny rad	private void printout(String s) {		try {			output.write(tabbar);			output.write(s);			output.newLine();		}		// En eventuell IOException från write() måste hanteras eller skickas		// vidare. Vi väljer att hantera felet, men utan att egentligen åtgärda		// det. Vi bara berättar att felet uppstod och hoppas på förståelse.		catch (IOException e) {			System.err.println("I/O Exception: "+ e.getMessage());		}	}			// Skriv ut en character array, t ex den som kommer från callback-metoden	// characters(), och mata fram till ny rad	private void printout(char ch[], int start, int length) {		try {			output.write(tabbar);			output.write(ch, start, length);			output.newLine();		}		catch (IOException e) {			System.err.println("I/O Exception: "+ e.getMessage());		}	} 		// Skriv ut en enstaka character utan att mata fram till ny rad.	// Vissa specialtecken skrivs ut på speciellt sätt för tydlighets	// skull.	private void printout(char ch) {		try {			switch(ch) {				// Newline skrivs ut som "\n"			case '\n':				output.write("\\n");				break;				// Tabtecken skrivs ut som "\t"			case '\t':				output.write("\\t");				break;				// CR skrivs ut som "\r"			case '\r':				output.write("\\r");				break;			default:				output.write(ch);			}		}		catch (IOException e) {			System.err.println("I/O Exception: "+ e.getMessage());		}	}		// Gör flush() och close() på BufferedWriter-objektet, så att inte text	// som vi skrivit ut under exekveringen går förlorad.	// (Det räcker egentligen med close(), som gör en implicit flush().)	private void endOutput() {		try {			output.flush();			output.close();		}		catch (IOException e) {			System.err.println("I/O Exception: "+ e.getMessage());		}	}		// public static f*cking void main(), Java-applikationens "entry point"	public static void main(String args[]) {		// Skapa en XMLReader för att kunna parsa en XML-fil		// Notera att objektet i sig måste deklareras utanför try{}-blocket,		// annars kommer det inte att existera i resten av programmet!		// Själva initialiseringen sker dock som sig bör i ett try{}-block.		XMLReader xmlreader = null;		try {			xmlreader =				XMLReaderFactory.createXMLReader(				"org.apache.xerces.parsers.SAXParser");		}		// Det som kan hända här är att den angivna SAX-parsern inte hittas.		catch (SAXException e) {			System.err.println("Unable to create XMLReader: "				+ e.getMessage());		}				// Skapa och koppla en "event handler" till XMLReadern.		// Vår event handler är samma klass som denna klass (vår enda),		// vilket kanske är osnyggt för mer realistiska tillämpningar.		// Överväg åtminstone att skapa event handlers som egna klasser.		// Eftersom man inte kan ha en statisk klass som event handler så		// behöver vi instansiera den här klassen. Då körs konstruktorn också,		// vilket vi behöver för att output-objektet skall initialiseras.		SAXdemo handler = new SAXdemo();				// Vi implementerar både ContentHandler och EventHandler i samma klass.		// Detta kanske inte heller är det mest lämpliga sättet alla gånger.		xmlreader.setContentHandler(handler);		xmlreader.setErrorHandler(handler);				// Be om validering, ange en XML-fil och parsa den		try {			// Be om validering. Vi har en DTD och vill använda den fullt ut!			// (Här kan det uppstå en SAXNotRecognizedException eller en			// SAXNotSupportedException!)			xmlreader.setFeature("http://xml.org/sax/features/validation",true);			// Ange vilken fil vi vill parsa.			// (Här kan det faktiskt inte uppstå en IOException!			// Filen öppnas inte förrän man verkligen anropar parse().)			// Filnamnet borde nog egentligen anges som args[1] i stället			// för att kompileras in som en konstant sträng.			InputSource source = new InputSource("Jspex.xml");			// Parsa filen - det är nu som alla callbacks kommer att anropas!			// (Här kan det uppstå en SAXException eller en IOException!)			xmlreader.parse(source);		}		// Om något gick snett, försök inte hantera det, men tala om det		catch (Exception e) {			System.err.println("Can't open or parse file: "+ e.getMessage());		}		// Klart! Här slutar main().	}				// Konkreta, icke-tomma implementationer av de flesta callbacks	// som krävs av en ContentHandler. De som inte implementeras är:	// public void processingInstruction(String target, String data)	// public void skippedEntity(String name)	// public void endPrefixMapping(String prefix)	// public void setDocumentLocator(Locator locator)	// Dessa fyra använder i stället defaultmetoderna i "DefaultHandler".		public void startDocument() throws SAXException {		printout("startDocument");		addTab();	} 		public void endDocument() throws SAXException {		printout("endDocument");		removeTab();		endOutput();	} 		public void startElement(String uri, String localName, String qName,		Attributes atts)						throws SAXException {		addTab();		// Beroende på om vi har ett XML namespace aktiverat eller inte så		// kommer elementnamnet antingen i "uri" och "name" (med namespace)		// eller bara i "qName" (qualified name). Om vi har ett namespace		// kommer "uri" att innehålla något, annars är det en tom sträng.		// Man bör aldrig förutsätta att det ena eller det andra gäller,		// utan alltid bereda sig på båda alternativen!		if(uri.equals(""))						printout(qName );//"startElement: " + 					else			printout("{"+uri+"}"+localName);//startElement: 				// Skriv ut eventuella attribut som skickades i argumentet "atts".		// Notera att antalet attribut kan vara noll, ett eller flera!		// Namnen på attributen hittas genom att loopa över ett index och		// plocka dem ett och ett i den ordning de stod i filen, men		// attributvärdena hittas på det sätt man normalt använder, nämligen		// på sina respektive namn ("attName").		for (int i = 0; i < atts.getLength(); i++) {			String attName = atts.getQName(i);			printout(" " + attName + ": " + atts.getValue(attName));					}			} 		public void endElement(String uri, String localName, String qName)	{		removeTab();		if(uri.equals(""))			printout(qName);//"endElement:   " + 					else			printout("{"+uri+"}"+localName);//endElement:   	} 			/*	public void endElement(String uri, String localName, String qName){		removeTab();                		if(uri.equals(""))                        			printout(tabbar + "</" + qName + ">");                		else                        			printout("endElement:   {"+uri+"}"+localName);        	}	*/			public void characters(char ch[], int start, int length)	{		printout("Characters:");		printout(ch, start, length);	} 		/*	public void ignorableWhitespace(char[] ch, int start, int length) 	{	printout("Ignorable whitespace:");	for(int i=start; i<start+length; i++) {	printout(ch[i]);	}	printout("hej"); // (Bara för att få en radmatning efteråt)	}	*/				// Konkreta, icke-tomma implementationer av alla ErrorHandler-callbacks.	// Notera att dessa anropas på fler villkor om man bett om validering.	// Exakt vilket fel som signaleras anges som vanligt i Exception-objektet.	// Även om man bett om validering stoppas inte parsningen annat än vid ett	// "fatalError", så error() bör kanske egentligen avbryta programmet.	// För exemplets skull stoppar vi här inte för något, om vi inte måste.	public void warning(SAXParseException e) {		System.err.println("*** Warning! " + e.getMessage());	}	public void error(SAXParseException e) {		System.err.println("*** Error! " + e.getMessage());	}	public void fatalError(SAXParseException e) {		System.err.println("*** Fatal error!" + e.getMessage());	}	}