a1be97c268411ea5a9803cfc9968609f1dfadbd4
[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.*;
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 parseString(String aString, SectionHandler aRootHandler) throws XMLReaderFailure, XMLReaderExc {
67     try {
68       parseInputSource(new InputSource(new StringReader(aString)), aRootHandler);
69     }
70     catch (Throwable t) {
71       throw new XMLReaderFailure(t);
72     }
73   }
74
75   public void parseFile(String aFileName, SectionHandler aRootHandler) throws XMLReaderFailure, XMLReaderExc {
76     filename= aFileName;
77     try {
78       parseInputStream(new FileInputStream(aFileName), aRootHandler);
79     }
80     catch (Throwable t) {
81       throw new XMLReaderFailure(t);
82     }
83   }
84
85   public void parseInputStream(InputStream anInputStream, SectionHandler aRootHandler) throws XMLReaderFailure, XMLReaderExc {
86     parseInputSource(new InputSource(anInputStream), aRootHandler);
87   }
88
89   public void parseInputSource(InputSource anInputSource, SectionHandler aRootHandler) throws XMLReaderFailure, XMLReaderExc {
90     try {
91       SAXParserFactory parserFactory = SAXParserFactory.newInstance();
92
93       parserFactory.setNamespaceAware(true);
94       parserFactory.setValidating(true);
95
96       XMLReaderHandler handler = new XMLReaderHandler(parserFactory, aRootHandler);
97
98       handler.processInputSource(anInputSource);
99     }
100     catch (Throwable e) {
101       Throwable t = ExceptionFunctions.traceCauseException(e);
102
103       if (t instanceof XMLReaderExc) {
104         throw (XMLReaderExc) t;
105       }
106
107       if (t instanceof XMLReaderFailure) {
108         throw (XMLReaderFailure) t;
109       }
110
111       throw new XMLReaderFailure(t);
112     }
113   }
114   private class XMLReaderHandler extends DefaultHandler {
115     private SAXParserFactory parserFactory;
116     private SectionsManager manager;
117
118     public XMLReaderHandler(SAXParserFactory aParserFactory, SectionHandler aRootHandler) {
119       super();
120
121       parserFactory=aParserFactory;
122       manager = new SectionsManager();
123       manager.pushHandler(aRootHandler);
124    }
125
126     public void setDocumentLocator(Locator aLocator) {
127       locator=aLocator;
128     }
129
130     private void processInputSource(InputSource anInputSource) throws XMLReaderExc, XMLReaderFailure {
131       try {
132         SAXParser parser=parserFactory.newSAXParser();
133
134         parser.parse(anInputSource, this);
135       }
136       catch (Throwable e) {
137         Throwable t = ExceptionFunctions.traceCauseException(e);
138
139         if (t instanceof XMLReaderExc) {
140           if (locator!=null && filename!=null)
141             ((XMLReaderExc) t).setLocation(filename, locator.getLineNumber(), locator.getColumnNumber());
142           throw (XMLReaderExc) t;
143         }
144
145         if (t instanceof SAXParseException) {
146           XMLReaderExc r = new XMLReaderExc(t.getMessage());
147
148           if (locator!=null && filename!=null)
149             r.setLocation(filename, locator.getLineNumber(), locator.getColumnNumber());
150
151           throw r;
152         }
153
154         if (t instanceof XMLReaderFailure) {
155           throw (XMLReaderFailure) t;
156         }
157
158         if (t instanceof ParserConfigurationException) {
159           throw new XMLReaderFailure("Internal exception: "+t.toString(), t);
160         }
161
162         throw new XMLReaderFailure(t);
163       }
164     }
165
166     public void startElement(String aUri, String aLocalName, String aQualifiedName, Attributes anAttributes) throws SAXException {
167       Map attributesMap;
168       int i;
169
170       try {
171         attributesMap = new HashMap();
172
173 //        if (namespaceAware)
174           for (i=0; i<anAttributes.getLength(); i++)
175             attributesMap.put(new XMLName(anAttributes.getURI(i), XMLReaderTool.getNameSpaceFromQualifiedName(anAttributes.getQName(i)), anAttributes.getLocalName(i)), anAttributes.getValue(i));
176 /*        else
177           for (i=0; i<anAttributes.getLength(); i++)
178             attributesMap.put(anAttributes.getLocalName(i), anAttributes.getValue(i));
179 */
180
181         SectionHandler handler = manager.currentHandler().startElement(new XMLName(aUri, XMLReaderTool.getNameSpaceFromQualifiedName(aQualifiedName), aLocalName), attributesMap);
182
183         manager.pushHandler( handler );
184       }
185       catch (XMLReaderExc e) {
186         throw new SAXParseException(e.getMessage(), null, e);
187       }
188       catch (Exception e) {
189         throw new SAXException(e);
190       }
191     }
192
193     public void endElement(String aUri, String aLocalName, String aQualifiedName) throws SAXException {
194       try
195       {
196         if (!aQualifiedName.equals("include")) {
197           SectionHandler handler = manager.popHandler();
198
199           handler.finishSection();
200
201           if (!manager.isEmpty()) {
202             manager.currentHandler().endElement(handler);
203           }
204         }
205       }
206       catch (XMLReaderExc e) {
207         throw new SAXParseException(e.getMessage(), null, e);
208       }
209       catch (Exception e) {
210         throw new SAXException(e);
211       }
212     }
213
214     public void characters(char[] aBuffer, int aStart, int anEnd) throws SAXException {
215       try {
216         String text = new String(aBuffer, aStart, anEnd);
217
218         manager.currentHandler().characters(text);
219       }
220       catch (XMLReaderExc e) {
221         throw new SAXParseException(e.getMessage(), null, e);
222       }
223       catch (Exception e) {
224         throw new SAXException(e);
225       }
226     }
227   }
228
229   private class SectionsManager {
230     Stack handlerStack;
231
232     public SectionsManager() {
233       handlerStack = new Stack();
234     }
235
236     public void pushHandler(SectionHandler aSectionHandler) {
237       handlerStack.push(aSectionHandler);
238     }
239
240     public SectionHandler popHandler() {
241       return (SectionHandler) handlerStack.pop();
242     }
243
244     public SectionHandler currentHandler() {
245       return (SectionHandler) handlerStack.peek();
246     }
247
248     public boolean isEmpty() {
249       return handlerStack.isEmpty();
250     }
251   }
252
253   public static interface SectionHandler {
254     public abstract SectionHandler startElement(XMLName aTag, Map anAttributes) throws XMLReaderExc;
255
256     public abstract void endElement(SectionHandler aHandler) throws XMLReaderExc;
257
258     public void characters(String aCharacters) throws XMLReaderExc;
259
260     public void finishSection() throws XMLReaderExc;
261   }
262
263   public static abstract class AbstractSectionHandler implements SectionHandler {
264     public SectionHandler startElement(XMLName aTag, Map anAttributes) throws XMLReaderExc {
265       return startElement(aTag.getLocalName(), anAttributes);
266     };
267
268     public SectionHandler startElement(String aLocalName, Map anAttributes) throws XMLReaderExc {
269       return null;
270     };
271
272     public void endElement(SectionHandler aHandler) throws XMLReaderExc {
273     };
274
275     public void finishSection() throws XMLReaderExc {
276     }
277
278     public void characters(String aCharacters) throws XMLReaderExc {
279       if ( aCharacters.trim().length() > 0) {
280         throw new XMLReaderExc("Text not allowed");
281       }
282     }
283   }
284
285   public static class XMLReaderExc extends Exc {
286     private boolean hasLocation;
287     private String filename;
288     private int lineNr;
289     private int columnNr;
290
291     public XMLReaderExc(String aMessage) {
292       super(aMessage);
293       hasLocation = false;
294     }
295
296     protected void setLocation(String aFilename, int aLineNr, int aColumnNr) {
297       filename = aFilename;
298       lineNr = aLineNr;
299       columnNr = aColumnNr;
300       hasLocation = true;
301     }
302
303     public boolean getHasLocation() {
304       return hasLocation;
305     }
306
307     public int getLineNr() {
308       return lineNr;
309     }
310
311     public int getColumnNr() {
312       return columnNr;
313     }
314
315     public String getFilename() {
316       return filename;
317     }
318   }
319
320   public static class XMLReaderFailure extends Failure {
321     public XMLReaderFailure(String aMessage, Throwable aCause) {
322       super(aMessage, aCause);
323     }
324
325     public XMLReaderFailure(Throwable aCause) {
326       super(aCause.getMessage(), aCause);
327     }
328   }
329
330   public static class XMLName {
331     private String namespaceURI;
332     private String localName;
333     private String prefix;
334
335     public XMLName(String aLocalName) {
336       this(null, null, aLocalName);
337     }
338
339     public XMLName(String aNamespaceURI, String aPrefix, String aLocalName) {
340       localName="";
341       prefix="";
342       namespaceURI="";
343
344       if (aLocalName!=null)
345         localName = aLocalName;
346       if (aPrefix!=null)
347         prefix = aPrefix;
348       if (aNamespaceURI!=null)
349         namespaceURI = aNamespaceURI;
350     }
351
352     public XMLName(String aNamespaceURI, String aLocalName) {
353       this (aNamespaceURI, null, aLocalName);
354     }
355
356     public String getNamespaceURI() {
357       return namespaceURI;
358     }
359
360     public String getLocalName() {
361       return localName;
362     }
363
364     public String getPrefix() {
365       return prefix;
366     }
367
368     public int hashCode() {
369       if (namespaceURI == null)
370         return localName.hashCode() + 3*prefix.hashCode();
371       else
372         return localName.hashCode() + 3*namespaceURI.hashCode();
373     }
374
375     public String toString() {
376       return ((namespaceURI.length()>0)? "["+namespaceURI+"]":"")+((prefix.length()>0)?prefix+":":"")+localName;
377     }
378
379     public boolean equals(Object anObject) {
380       if (anObject instanceof XMLName) {
381         if (namespaceURI==null)
382           return (((XMLName) anObject).namespaceURI == null) &&
383                  prefix.equals(((XMLName) anObject).prefix) &&
384                  localName.equals(((XMLName) anObject).localName);
385         else
386           return namespaceURI.equals(((XMLName) anObject).namespaceURI) &&
387                  localName.equals(((XMLName) anObject).localName);
388       }
389       else
390         return false;
391     }
392   }
393
394 }