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