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