2947bfe476c9826629a6de525c4e73ae246f0d55
[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(namespaceAware);
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         if (locator!=null && filename!=null)
92           ((XMLReaderExc) t).setLocation(filename, locator.getLineNumber(), locator.getColumnNumber());
93         throw (XMLReaderExc) t;
94       }
95
96       if (t instanceof XMLReaderFailure) {
97         throw (XMLReaderFailure) t;
98       }
99
100       throw new XMLReaderFailure(t);
101     }
102   }
103
104   private class XMLReaderHandler extends DefaultHandler {
105     private SAXParserFactory parserFactory;
106     private SectionsManager manager;
107     private InputSource inputSource;
108
109     public XMLReaderHandler(SAXParserFactory aParserFactory, SectionHandler aRootHandler) {
110       super();
111
112       parserFactory=aParserFactory;
113       manager = new SectionsManager();
114       manager.pushHandler(aRootHandler);
115    }
116
117     public void setDocumentLocator(Locator aLocator) {
118       locator=aLocator;
119     }
120
121     private void processInputStream(InputStream anInputStream) throws XMLReaderExc, XMLReaderFailure {
122       try {
123         SAXParser parser=parserFactory.newSAXParser();
124
125         inputSource = new InputSource(anInputStream);
126         parser.parse(inputSource, this);
127       }
128       catch (ParserConfigurationException e) {
129         throw new XMLReaderExc("Internal exception: "+e.getMessage());
130       }
131       catch (Throwable e) {
132         throw new XMLReaderFailure(e);
133       }
134     }
135
136     public void startElement(String aUri, String aTag, String aQualifiedName, Attributes anAttributes) throws SAXException {
137       Map attributesMap;
138       int i;
139
140       try {
141         attributesMap = new HashMap();
142         for (i=0; i<anAttributes.getLength(); i++)
143           attributesMap.put(anAttributes.getQName(i), anAttributes.getValue(i));
144
145         SectionHandler handler = manager.currentHandler().startElement(aQualifiedName, attributesMap);
146
147         manager.pushHandler( handler );
148       }
149       catch (XMLReaderExc e) {
150         throw new SAXParseException(e.getMessage(), null, e);
151       }
152       catch (Exception e) {
153         throw new SAXException(e);
154       }
155     }
156
157     public void endElement(String aUri, String aTag, String aQualifiedName) throws SAXException {
158       try
159       {
160         if (!aQualifiedName.equals("include")) {
161           SectionHandler handler = manager.popHandler();
162
163           handler.finishSection();
164
165           if (!manager.isEmpty()) {
166             manager.currentHandler().endElement(handler);
167           }
168         }
169       }
170       catch (XMLReaderExc e) {
171         throw new SAXParseException(e.getMessage(), null, e);
172       }
173       catch (Exception e) {
174         throw new SAXException(e);
175       }
176     }
177
178     public void characters(char[] aBuffer, int aStart, int anEnd) throws SAXException {
179       try {
180         String text = new String(aBuffer, aStart, anEnd);
181
182         manager.currentHandler().characters(text);
183       }
184       catch (XMLReaderExc e) {
185         throw new SAXParseException(e.getMessage(), null, e);
186       }
187       catch (Exception e) {
188         throw new SAXException(e);
189       }
190     }
191   }
192
193   private class SectionsManager {
194     Stack handlerStack;
195
196     public SectionsManager() {
197       handlerStack = new Stack();
198     }
199
200     public void pushHandler(SectionHandler aSectionHandler) {
201       handlerStack.push(aSectionHandler);
202     }
203
204     public SectionHandler popHandler() {
205       return (SectionHandler) handlerStack.pop();
206     }
207
208     public SectionHandler currentHandler() {
209       return (SectionHandler) handlerStack.peek();
210     }
211
212     public boolean isEmpty() {
213       return handlerStack.isEmpty();
214     }
215   }
216
217   public static interface SectionHandler {
218     public abstract SectionHandler startElement(String aTag, Map anAttributes) throws XMLReaderExc;
219
220     public abstract void endElement(SectionHandler aHandler) throws XMLReaderExc;
221
222     public void characters(String aCharacters) throws XMLReaderExc;
223
224     public void finishSection() throws XMLReaderExc;
225   }
226
227   public static abstract class AbstractSectionHandler implements SectionHandler {
228     public SectionHandler startElement(String aTag, Map anAttributes) throws XMLReaderExc {
229       return null;
230     };
231
232     public void endElement(SectionHandler aHandler) throws XMLReaderExc {
233     };
234
235     public void finishSection() throws XMLReaderExc {
236     }
237
238     public void characters(String aCharacters) throws XMLReaderExc {
239       if ( aCharacters.trim().length() > 0) {
240         throw new XMLReaderExc("Text not allowed");
241       }
242     }
243   }
244
245   public static class XMLReaderExc extends Exc {
246     private boolean hasLocation;
247     private String filename;
248     private int lineNr;
249     private int columnNr;
250
251     public XMLReaderExc(String aMessage) {
252       super(aMessage);
253       hasLocation = false;
254     }
255
256     protected void setLocation(String aFilename, int aLineNr, int aColumnNr) {
257       filename = aFilename;
258       lineNr = aLineNr;
259       columnNr = aColumnNr;
260       hasLocation = true;
261     }
262
263     public boolean getHasLocation() {
264       return hasLocation;
265     }
266
267     public int getLineNr() {
268       return lineNr;
269     }
270
271     public int getColumnNr() {
272       return columnNr;
273     }
274
275     public String getFilename() {
276       return filename;
277     }
278   }
279
280   public static class XMLReaderFailure extends Failure {
281     public XMLReaderFailure(String aMessage, Throwable aCause) {
282       super(aMessage, aCause);
283     }
284
285     public XMLReaderFailure(Throwable aCause) {
286       super(aCause.getMessage(), aCause);
287     }
288   }
289
290 }