954b2e7178fa216f0fa497576b5c13de273a6474
[mir.git] / source / mir / util / XMLReader.java
1 /*
2  * Copyright (C) 2001, 2002 The Mir-coders group
3  *
4  * This file is part of Mir.
5  *
6  * Mir is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * Mir is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with Mir; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  * In addition, as a special exception, The Mir-coders gives permission to link
21  * the code of this program with  any library licensed under the Apache Software License,
22  * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library
23  * (or with modified versions of the above that use the same license as the above),
24  * and distribute linked combinations including the two.  You must obey the
25  * GNU General Public License in all respects for all of the code used other than
26  * the above mentioned libraries.  If you modify this file, you may extend this
27  * exception to your version of the file, but you are not obligated to do so.
28  * If you do not wish to do so, delete this exception statement from your version.
29  */
30 package mir.util;
31
32 import java.io.FileInputStream;
33 import java.io.InputStream;
34 import java.util.HashMap;
35 import java.util.Map;
36 import java.util.Stack;
37
38 import javax.xml.parsers.ParserConfigurationException;
39 import javax.xml.parsers.SAXParser;
40 import javax.xml.parsers.SAXParserFactory;
41
42 import multex.Exc;
43 import multex.Failure;
44
45 import org.xml.sax.Attributes;
46 import org.xml.sax.InputSource;
47 import org.xml.sax.Locator;
48 import org.xml.sax.SAXException;
49 import org.xml.sax.SAXParseException;
50 import org.xml.sax.helpers.DefaultHandler;
51
52 public class XMLReader {
53   private Locator locator;
54   private String filename;
55   private boolean namespaceAware;
56
57   public XMLReader() {
58     this(false);
59   }
60
61   public XMLReader(boolean aNameSpaceAware) {
62     namespaceAware = aNameSpaceAware;
63     filename="";
64   }
65
66   public void parseFile(String aFileName, SectionHandler aRootHandler) throws XMLReaderFailure, XMLReaderExc {
67     filename= aFileName;
68     try {
69       parseInputStream(new FileInputStream(aFileName), aRootHandler);
70     }
71     catch (Throwable t) {
72       throw new XMLReaderFailure(t);
73     }
74   }
75
76   public void parseInputStream(InputStream anInputStream, SectionHandler aRootHandler) throws XMLReaderFailure, XMLReaderExc {
77     try {
78       SAXParserFactory parserFactory = SAXParserFactory.newInstance();
79
80       parserFactory.setNamespaceAware(true);
81       parserFactory.setValidating(true);
82
83       XMLReaderHandler handler = new XMLReaderHandler(parserFactory, aRootHandler);
84
85       handler.processInputStream(anInputStream);
86     }
87     catch (Throwable e) {
88       Throwable t = ExceptionFunctions.traceCauseException(e);
89
90       if (t instanceof XMLReaderExc) {
91         throw (XMLReaderExc) t;
92       }
93
94       if (t instanceof XMLReaderFailure) {
95         throw (XMLReaderFailure) t;
96       }
97
98       throw new XMLReaderFailure(t);
99     }
100   }
101
102   private class XMLReaderHandler extends DefaultHandler {
103     private SAXParserFactory parserFactory;
104     private SectionsManager manager;
105     private InputSource inputSource;
106
107     public XMLReaderHandler(SAXParserFactory aParserFactory, SectionHandler aRootHandler) {
108       super();
109
110       parserFactory=aParserFactory;
111       manager = new SectionsManager();
112       manager.pushHandler(aRootHandler);
113    }
114
115     public void setDocumentLocator(Locator aLocator) {
116       locator=aLocator;
117     }
118
119     private void processInputStream(InputStream anInputStream) throws XMLReaderExc, XMLReaderFailure {
120       try {
121         SAXParser parser=parserFactory.newSAXParser();
122
123         inputSource = new InputSource(anInputStream);
124         parser.parse(inputSource, this);
125       }
126       catch (Throwable e) {
127         Throwable t = ExceptionFunctions.traceCauseException(e);
128
129         if (t instanceof XMLReaderExc) {
130           if (locator!=null && filename!=null)
131             ((XMLReaderExc) t).setLocation(filename, locator.getLineNumber(), locator.getColumnNumber());
132           throw (XMLReaderExc) t;
133         }
134
135         if (t instanceof SAXParseException) {
136           XMLReaderExc r = new XMLReaderExc(t.getMessage());
137
138           if (locator!=null && filename!=null)
139             r.setLocation(filename, locator.getLineNumber(), locator.getColumnNumber());
140
141           throw r;
142         }
143
144         if (t instanceof XMLReaderFailure) {
145           throw (XMLReaderFailure) t;
146         }
147
148         if (t instanceof ParserConfigurationException) {
149           throw new XMLReaderFailure("Internal exception: "+t.toString(), t);
150         }
151
152         throw new XMLReaderFailure(t);
153       }
154     }
155
156     public void startElement(String aUri, String aLocalName, String aQualifiedName, Attributes anAttributes) throws SAXException {
157       Map attributesMap;
158       int i;
159
160       try {
161         attributesMap = new HashMap();
162
163         if (namespaceAware)
164           for (i=0; i<anAttributes.getLength(); i++)
165             attributesMap.put(new XMLName(anAttributes.getURI(i), anAttributes.getLocalName(i)), anAttributes.getValue(i));
166         else
167           for (i=0; i<anAttributes.getLength(); i++)
168             attributesMap.put(anAttributes.getLocalName(i), anAttributes.getValue(i));
169
170         SectionHandler handler = manager.currentHandler().startElement(new XMLName(aUri, aLocalName), attributesMap);
171
172         manager.pushHandler( handler );
173       }
174       catch (XMLReaderExc e) {
175         throw new SAXParseException(e.getMessage(), null, e);
176       }
177       catch (Exception e) {
178         throw new SAXException(e);
179       }
180     }
181
182     public void endElement(String aUri, String aLocalName, String aQualifiedName) throws SAXException {
183       try
184       {
185         if (!aQualifiedName.equals("include")) {
186           SectionHandler handler = manager.popHandler();
187
188           handler.finishSection();
189
190           if (!manager.isEmpty()) {
191             manager.currentHandler().endElement(handler);
192           }
193         }
194       }
195       catch (XMLReaderExc e) {
196         throw new SAXParseException(e.getMessage(), null, e);
197       }
198       catch (Exception e) {
199         throw new SAXException(e);
200       }
201     }
202
203     public void characters(char[] aBuffer, int aStart, int anEnd) throws SAXException {
204       try {
205         String text = new String(aBuffer, aStart, anEnd);
206
207         manager.currentHandler().characters(text);
208       }
209       catch (XMLReaderExc e) {
210         throw new SAXParseException(e.getMessage(), null, e);
211       }
212       catch (Exception e) {
213         throw new SAXException(e);
214       }
215     }
216   }
217
218   private class SectionsManager {
219     Stack handlerStack;
220
221     public SectionsManager() {
222       handlerStack = new Stack();
223     }
224
225     public void pushHandler(SectionHandler aSectionHandler) {
226       handlerStack.push(aSectionHandler);
227     }
228
229     public SectionHandler popHandler() {
230       return (SectionHandler) handlerStack.pop();
231     }
232
233     public SectionHandler currentHandler() {
234       return (SectionHandler) handlerStack.peek();
235     }
236
237     public boolean isEmpty() {
238       return handlerStack.isEmpty();
239     }
240   }
241
242   public static interface SectionHandler {
243     public abstract SectionHandler startElement(XMLName aTag, Map anAttributes) throws XMLReaderExc;
244
245     public abstract void endElement(SectionHandler aHandler) throws XMLReaderExc;
246
247     public void characters(String aCharacters) throws XMLReaderExc;
248
249     public void finishSection() throws XMLReaderExc;
250   }
251
252   public static abstract class AbstractSectionHandler implements SectionHandler {
253     public SectionHandler startElement(XMLName aTag, Map anAttributes) throws XMLReaderExc {
254       return startElement(aTag.getLocalName(), anAttributes);
255     };
256
257     public SectionHandler startElement(String aLocalName, Map anAttributes) throws XMLReaderExc {
258       return null;
259     };
260
261     public void endElement(SectionHandler aHandler) throws XMLReaderExc {
262     };
263
264     public void finishSection() throws XMLReaderExc {
265     }
266
267     public void characters(String aCharacters) throws XMLReaderExc {
268       if ( aCharacters.trim().length() > 0) {
269         throw new XMLReaderExc("Text not allowed");
270       }
271     }
272   }
273
274   public static class XMLReaderExc extends Exc {
275     private boolean hasLocation;
276     private String filename;
277     private int lineNr;
278     private int columnNr;
279
280     public XMLReaderExc(String aMessage) {
281       super(aMessage);
282       hasLocation = false;
283     }
284
285     protected void setLocation(String aFilename, int aLineNr, int aColumnNr) {
286       filename = aFilename;
287       lineNr = aLineNr;
288       columnNr = aColumnNr;
289       hasLocation = true;
290     }
291
292     public boolean getHasLocation() {
293       return hasLocation;
294     }
295
296     public int getLineNr() {
297       return lineNr;
298     }
299
300     public int getColumnNr() {
301       return columnNr;
302     }
303
304     public String getFilename() {
305       return filename;
306     }
307   }
308
309   public static class XMLReaderFailure extends Failure {
310     public XMLReaderFailure(String aMessage, Throwable aCause) {
311       super(aMessage, aCause);
312     }
313
314     public XMLReaderFailure(Throwable aCause) {
315       super(aCause.getMessage(), aCause);
316     }
317   }
318
319   public static class XMLName {
320     private String namespaceURI;
321     private String localName;
322
323     public XMLName(String aLocalName) {
324       this(aLocalName, null);
325     }
326
327     public XMLName(String aNamespaceURI, String aLocalName) {
328       namespaceURI = aNamespaceURI;
329       localName = aLocalName;
330     }
331
332     public String getNamespaceURI() {
333       return namespaceURI;
334     }
335
336     public String getLocalName() {
337       return localName;
338     }
339
340     public int hashCode() {
341       if (namespaceURI == null)
342         return localName.hashCode();
343       else
344         return localName.hashCode() + 3*namespaceURI.hashCode();
345     }
346
347     public String toString() {
348       return namespaceURI+":"+localName;
349     }
350
351     public boolean equals(Object anObject) {
352       if (anObject instanceof XMLName) {
353         if (namespaceURI==null)
354           return (((XMLName) anObject).namespaceURI == null) &&
355                  localName.equals(((XMLName) anObject).localName);
356         else
357           return namespaceURI.equals(((XMLName) anObject).namespaceURI) &&
358                  localName.equals(((XMLName) anObject).localName);
359       }
360       else
361         return false;
362     }
363   }
364
365 }