9b4d9286a7b42fccc2b3294425bc53d0bafd52be
[mir.git] / source / mir / util / xml / XMLParserEngine.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
31 package mir.util.xml;
32
33 import java.io.BufferedInputStream;
34 import java.io.File;
35 import java.io.FileInputStream;
36 import java.io.InputStream;
37 import java.io.InputStreamReader;
38 import java.io.Reader;
39 import java.io.StringReader;
40 import java.io.UnsupportedEncodingException;
41 import java.util.HashMap;
42 import java.util.Map;
43 import java.util.Stack;
44
45 import mir.util.ExceptionFunctions;
46 import mir.util.xml.html.XMLHTMLParserProvider;
47
48 public class XMLParserEngine {
49   private Map providers;
50   private XMLParserProvider defaultProvider;
51
52   private static XMLParserEngine instance = new XMLParserEngine();
53
54   public static XMLParserEngine getInstance() {
55     return instance;
56   }
57
58   private XMLParserEngine() {
59     providers = new HashMap();
60     defaultProvider = new XMLSAXParserProvider(false);
61     providers.put("xml", defaultProvider);
62     providers.put("xml.namespaceaware", new XMLSAXParserProvider(true));
63     providers.put("html", new XMLHTMLParserProvider());
64   }
65
66   /**
67    *
68    * @param aString
69    * @param aRootHandler
70    * @throws XMLParserFailure
71    * @throws XMLParserExc
72    */
73   public void parseString(String aProvider, String aString, SectionHandler aRootHandler) throws XMLParserFailure, XMLParserExc{
74     try {
75       parse(aProvider, new StringReader(aString), aRootHandler);
76     }
77     catch (Throwable t) {
78       throw new XMLParserFailure(t);
79     }
80   }
81
82   /**
83    *
84    * @param aFile
85    * @param aRootHandler
86    */
87   public void parse(String aProvider, File aFile, SectionHandler aRootHandler) throws XMLParserFailure, XMLParserExc {
88 //    filename = aFileName;
89
90     try {
91       parse(aProvider, new BufferedInputStream(new FileInputStream(aFile), 8192), aRootHandler);
92     }
93     catch (XMLParserExc e) {
94       throw e;
95     }
96     catch (Throwable t) {
97       throw new XMLParserFailure(t);
98     }
99   }
100
101   /**
102    * Parse xml coming from an input stream with the system default encoding
103    */
104   public void parse(String aProvider, InputStream anInputStream, SectionHandler aRootHandler) throws XMLParserFailure, XMLParserExc{
105     parse(aProvider, new InputStreamReader(anInputStream), aRootHandler);
106   }
107
108   /**
109    * Parse xml coming from an input stream according to the given encoding
110    */
111   public void parse(String aProvider, InputStream anInputStream, String anEncoding, SectionHandler aRootHandler) throws XMLParserFailure, XMLParserExc{
112     try {
113       parse(aProvider, new InputStreamReader(anInputStream, anEncoding), aRootHandler);
114     }
115     catch (UnsupportedEncodingException e) {
116       throw new XMLParserExc("Unsupported encoding: " + anEncoding);
117     }
118   }
119
120
121   /**
122    *
123    * @param aRootHandler
124    * @throws mir.util.xml.XMLParserFailure
125    * @throws mir.util.xml.XMLParserExc
126    */
127   public void parse(String aProvider, Reader aReader, SectionHandler aRootHandler) throws XMLParserFailure, XMLParserExc{
128     XMLParserProvider provider = (XMLParserProvider) providers.get(aProvider);
129
130     if (provider==null)
131       provider = defaultProvider;
132
133     XMLParserRunner runner = new XMLParserRunner(aRootHandler);
134
135     try {
136       provider.parse(aReader, runner);
137     }
138     catch (Throwable e) {
139       Throwable t = ExceptionFunctions.traceCauseException(e);
140
141       if (t instanceof XMLParserExc && runner.getLocator()!=null) {
142         ((XMLParserExc) t).setLocation(runner.getLocator().getLineNr(), runner.getLocator().getColumnNr());
143       }
144
145       if (t instanceof XMLParserExc) {
146         throw (XMLParserExc) t;
147       }
148
149       if (t instanceof XMLParserFailure) {
150         throw (XMLParserFailure) t;
151       }
152
153       throw new XMLParserFailure(t);
154     }
155   }
156
157   public interface XMLLocator {
158     public int getLineNr();
159     public int getColumnNr();
160   }
161
162   public interface XMLParserReceiver {
163     /**
164      * Provides an object with which it's possible to track the parser's
165      *    position.
166      */
167     public void setLocator(XMLLocator aLocator);
168
169     /**
170      * Extra document data, outside of tags and CDATA, will be passed verbatim
171      * to this method. This may include comments, DTDs, XML specifications,
172      * etc.
173      */
174     public void extra(String aPreAmble) throws XMLParserExc, XMLParserFailure;
175
176     public void startElement(XMLName anElement, Map anAttributes) throws XMLParserExc, XMLParserFailure;
177     public void endElement(XMLName anElement) throws XMLParserExc, XMLParserFailure;
178     public void startDocument() throws XMLParserExc, XMLParserFailure;
179     public void endDocument() throws XMLParserExc, XMLParserFailure;
180     public void text(String aText) throws XMLParserExc, XMLParserFailure;
181   }
182
183   public interface XMLParserProvider {
184     public void parse(Reader aReader, XMLParserReceiver aReceiver) throws XMLParserExc, XMLParserFailure;
185   }
186
187   private class XMLParserRunner implements XMLParserReceiver {
188     private SectionsManager manager;
189     private XMLLocator locator;
190     private SectionHandler rootHandler;
191
192     public XMLParserRunner(SectionHandler aRootHandler) {
193       super();
194
195       locator = null;
196       manager = new SectionsManager();
197       rootHandler = aRootHandler;
198     }
199
200     public void setLocator(XMLLocator aLocator) {
201       locator=aLocator;
202     }
203
204     public void extra(String anExtraData) throws XMLParserExc, XMLParserFailure {
205       SectionHandler handler = manager.currentHandler();
206
207       handler.extra(anExtraData);
208     }
209
210     public void startElement(XMLName anElement, Map anAttributes) throws XMLParserExc, XMLParserFailure {
211       SectionHandler handler = manager.currentHandler().startElement(anElement, anAttributes);
212
213       handler.startSection();
214
215       manager.pushHandler(handler);
216     }
217
218     public void endElement(XMLName anElement) throws XMLParserExc, XMLParserFailure {
219       SectionHandler handler = manager.popHandler();
220
221       handler.finishSection();
222
223       manager.currentHandler().endElement(handler);
224     }
225
226     public void startDocument() throws XMLParserExc, XMLParserFailure {
227       rootHandler.startSection();
228       manager.pushHandler(rootHandler);
229     }
230
231     public void endDocument() throws XMLParserExc, XMLParserFailure {
232       SectionHandler handler = manager.popHandler();
233
234       handler.finishSection();
235     }
236
237     public void text(String aText) throws XMLParserExc, XMLParserFailure {
238       manager.currentHandler().characters(aText);
239     }
240
241     public XMLLocator getLocator() {
242       return locator;
243     }
244   }
245
246   /**
247    *
248    * <p>Title: </p>
249    * <p>Description: </p>
250    * <p>Copyright: Copyright (c) 2003</p>
251    * <p>Company: </p>
252    * @author not attributable
253    * @version 1.0
254    */
255   private class SectionsManager {
256     private Stack handlerStack;
257
258     public SectionsManager() {
259       handlerStack = new Stack();
260     }
261
262     public void pushHandler(SectionHandler aSectionHandler) {
263       handlerStack.push(aSectionHandler);
264     }
265
266     public SectionHandler popHandler() {
267       return (SectionHandler) handlerStack.pop();
268     }
269
270     public SectionHandler currentHandler() {
271       return (SectionHandler) handlerStack.peek();
272     }
273
274     public boolean isEmpty() {
275       return handlerStack.isEmpty();
276     }
277   }
278
279 }