001 /*
002 // $Id: //open/util/resgen/src/org/eigenbase/xom/wrappers/GenericDOMParser.java#6 $
003 // Package org.eigenbase.xom is an XML Object Mapper.
004 // Copyright (C) 2005-2005 The Eigenbase Project
005 // Copyright (C) 2005-2005 Disruptive Tech
006 // Copyright (C) 2005-2005 LucidEra, Inc.
007 // Portions Copyright (C) 2001-2005 Kana Software, Inc. and others.
008 //
009 // This library is free software; you can redistribute it and/or modify it
010 // under the terms of the GNU Lesser General Public License as published by the
011 // Free Software Foundation; either version 2 of the License, or (at your
012 // option) any later version approved by The Eigenbase Project.
013 //
014 // This library is distributed in the hope that it will be useful,
015 // but WITHOUT ANY WARRANTY; without even the implied warranty of
016 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
017 // GNU Lesser General Public License for more details.
018 //
019 // You should have received a copy of the GNU Lesser General Public License
020 // along with this library; if not, write to the Free Software
021 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
022 */
023
024 package org.eigenbase.xom.wrappers;
025
026 import org.eigenbase.xom.*;
027 import org.w3c.dom.*;
028 import org.xml.sax.ErrorHandler;
029 import org.xml.sax.InputSource;
030 import org.xml.sax.SAXException;
031 import org.xml.sax.SAXParseException;
032
033 import java.io.*;
034 import java.net.URL;
035
036 /**
037 * A <code>GenericDOMParser</code> is an abstract base class for {@link
038 * XercesDOMParser} and {@link JaxpDOMParser}.
039 *
040 * @author jhyde
041 * @since Aug 29, 2002
042 * @version $Id: //open/util/resgen/src/org/eigenbase/xom/wrappers/GenericDOMParser.java#6 $
043 **/
044 abstract class GenericDOMParser
045 implements ErrorHandler, org.eigenbase.xom.Parser, Locator
046 {
047
048 // Used for capturing error messages as they occur.
049 StringWriter errorBuffer = null;
050 PrintWriter errorOut = null;
051
052 /** The document which spawns elements. The constructor of the derived
053 * class must set this. **/
054 protected Document document;
055
056 static final String LOAD_EXTERNAL_DTD_FEATURE =
057 "http://apache.org/xml/features/nonvalidating/load-external-dtd";
058 static final String VALIDATION_FEATURE =
059 "http://xml.org/sax/features/validation";
060 private boolean keepPositions;
061 private Annotator annotator;
062
063 public DOMWrapper create(String tagName) {
064 Element element = document.createElement(tagName);
065 return new W3CDOMWrapper(element, this);
066 }
067
068 public DOMWrapper parse(InputStream is) throws XOMException {
069 TeeInputStream tis = new TeeInputStream(is);
070 InputSource source = new InputSource(tis);
071 Document document = parseInputSource(source);
072 final W3CDOMWrapper wrapper =
073 new W3CDOMWrapper(document.getDocumentElement(), this);
074 if (keepPositions) {
075 String xmlString = new String(tis.getBytes());
076 annotator = new Annotator(xmlString, wrapper);
077 }
078 return wrapper;
079 }
080
081 public void setKeepPositions(boolean keepPositions) {
082 this.keepPositions = keepPositions;
083 }
084
085 public boolean isKeepPositions() {
086 return keepPositions;
087 }
088
089 public DOMWrapper parse(String xmlString) throws XOMException {
090 final DOMWrapper wrapper = parse(new StringReader(xmlString));
091 if (keepPositions) {
092 annotator = new Annotator(xmlString, wrapper);
093 }
094 return wrapper;
095 }
096
097 public DOMWrapper parse(Reader reader) throws XOMException {
098 Document document = parseInputSource(new InputSource(reader));
099 return new W3CDOMWrapper(document.getDocumentElement(), this);
100 }
101
102 /**
103 * Parses the specified URI and returns the document.
104 * @param in Input source
105 * @return Document
106 * @throws org.eigenbase.xom.XOMException on error
107 */
108 protected abstract Document parseInputSource(InputSource in)
109 throws XOMException;
110
111 /** Warning. */
112 public void warning(SAXParseException ex) {
113 errorOut.println("[Warning] " +
114 getLocationString(ex) + ": " +
115 ex.getMessage());
116 }
117
118 /** Error. */
119 public void error(SAXParseException ex) {
120 errorOut.println("[Error] " +
121 getLocationString(ex) + ": " +
122 ex.getMessage());
123 }
124
125 /** Fatal error. */
126 public void fatalError(SAXParseException ex)
127 throws SAXException {
128 errorOut.println("[Fatal Error] " +
129 getLocationString(ex) + ": " +
130 ex.getMessage());
131 throw ex;
132 }
133
134 /** Returns a string of the location.
135 * @param ex Exception
136 * @return Location string, e.g. "file.xml:4:72"
137 */
138 private String getLocationString(SAXParseException ex) {
139 StringBuffer str = new StringBuffer();
140
141 String systemId = ex.getSystemId();
142 if (systemId != null) {
143 int index = systemId.lastIndexOf('/');
144 if (index != -1) {
145 systemId = systemId.substring(index + 1);
146 }
147 str.append(systemId);
148 }
149 str.append(':');
150 str.append(ex.getLineNumber());
151 str.append(':');
152 str.append(ex.getColumnNumber());
153 return str.toString();
154 }
155
156 // implement Parser
157 public DOMWrapper parse(URL url)
158 throws XOMException {
159 try {
160 return parse(new BufferedInputStream(url.openStream()));
161 } catch (IOException ex) {
162 throw new XOMException(ex, "Document parse failed");
163 }
164 }
165
166 // Helper: reset the error buffer to prepare for a new parse.
167 protected void prepareParse() {
168 errorBuffer = new StringWriter();
169 errorOut = new PrintWriter(errorBuffer);
170 }
171
172 // Helper: throw an exception with messages of any errors
173 // accumulated during the parse.
174 protected void handleErrors() throws XOMException {
175 errorOut.flush();
176 String errorStr = errorBuffer.toString();
177 if (errorStr.length() > 0) {
178 throw new XOMException("Document parse failed: " + errorStr);
179 }
180 }
181
182 // implement Locator
183 public Location getLocation(DOMWrapper wrapper) {
184 return annotator.getLocation(wrapper);
185 }
186
187 /**
188 * Input stream that keeps a copy of every byte that flows through it.
189 */
190 private static class TeeInputStream extends FilterInputStream {
191 private final ByteArrayOutputStream baos = new ByteArrayOutputStream();
192
193 TeeInputStream(InputStream in) {
194 super(in);
195 }
196
197 public int read() throws IOException {
198 int x = super.read();
199 baos.write(x);
200 return x;
201 }
202
203 /**
204 * Returns the bytes that have been read from this stream.
205 *
206 * @return Array of bytes that have been read from this stream
207 */
208 public byte[] getBytes() {
209 return baos.toByteArray();
210 }
211 }
212 }
213
214 // End GenericDOMParser.java