001: package org.sakaibrary.xserver;
002:
003: import java.io.*;
004:
005: import org.xml.sax.*;
006: import org.xml.sax.helpers.DefaultHandler;
007: import javax.xml.parsers.SAXParserFactory;
008: import javax.xml.parsers.ParserConfigurationException;
009: import javax.xml.parsers.SAXParser;
010:
011: public class XMLCleanup extends DefaultHandler {
012: private static final org.apache.commons.logging.Log LOG = org.apache.commons.logging.LogFactory
013: .getLog("org.sakaibrary.xserver.XMLCleanup");
014:
015: private ByteArrayOutputStream bytes;
016: private Writer out;
017: private InputStream inputXml;
018: StringBuffer textBuffer;
019: private String indentString = " "; // Amount to indent
020: private int indentLevel = 0;
021:
022: // X-Server error handling
023: private boolean error = false;
024: private boolean error_codeFlag = false;
025: private boolean error_textFlag = false;
026: private String error_code;
027: private String error_text;
028:
029: public XMLCleanup() {
030: bytes = new ByteArrayOutputStream();
031:
032: try {
033: out = new OutputStreamWriter(bytes, "UTF8");
034: } catch (UnsupportedEncodingException e) {
035: LOG.warn("XMLCleanup() unsupported encoding: "
036: + e.getMessage());
037: }
038: }
039:
040: public ByteArrayOutputStream cleanup(InputStream xml)
041: throws XServerException {
042: inputXml = xml;
043:
044: // Use the default (non-validating) parser
045: SAXParserFactory factory = SAXParserFactory.newInstance();
046:
047: try {
048: // Parse the input
049: SAXParser saxParser = factory.newSAXParser();
050: saxParser.parse(inputXml, this );
051:
052: // close the stream
053: inputXml.close();
054: } catch (SAXParseException spe) {
055: // Use the contained exception, if any
056: Exception x = spe;
057:
058: if (spe.getException() != null) {
059: x = spe.getException();
060: }
061:
062: // Error generated by the parser
063: LOG.warn("XMLCleanup.cleanup() parsing exception: "
064: + spe.getMessage() + " - xml line "
065: + spe.getLineNumber() + ", uri "
066: + spe.getSystemId(), x);
067: } catch (SAXException sxe) {
068: // Error generated by this application
069: // (or a parser-initialization error)
070: Exception x = sxe;
071:
072: if (sxe.getException() != null) {
073: x = sxe.getException();
074: }
075:
076: LOG.warn("XMLCleanup.cleanup() SAX exception: "
077: + sxe.getMessage(), x);
078: } catch (ParserConfigurationException pce) {
079: // Parser with specified options can't be built
080: LOG
081: .warn("XMLCleanup.cleanup() SAX parser cannot be built with "
082: + "specified options");
083: } catch (IOException ioe) {
084: // I/O error
085: LOG.warn("XMLCleanup.cleanup() IO exception", ioe);
086: } catch (Throwable t) {
087: LOG.warn("XMLCleanup.cleanup() exception", t);
088: }
089:
090: if (error) {
091: throw new XServerException(error_code, error_text);
092: }
093:
094: return bytes;
095: }
096:
097: //===========================================================
098: // SAX DocumentHandler methods
099: //===========================================================
100: public void setDocumentLocator(Locator l) {
101: // Save this to resolve relative URIs or to give diagnostics.
102: try {
103: out.flush();
104: } catch (IOException e) {
105: // Ignore errors
106: }
107: }
108:
109: public void startDocument() throws SAXException {
110: emit("<?xml version='1.0' encoding='UTF-8'?>");
111: }
112:
113: public void endDocument() throws SAXException {
114: nl();
115: try {
116: out.flush();
117: } catch (IOException e) {
118: throw new SAXException("I/O error", e);
119: }
120: }
121:
122: public void startElement(String namespaceURI, String sName, // simple name
123: String qName, // qualified name
124: Attributes attrs) throws SAXException {
125: echoText();
126: indentLevel++;
127: nl();
128:
129: String eName = sName; // element name
130:
131: if ("".equals(eName)) {
132: eName = qName; // not namespaceAware
133: }
134:
135: emit("<" + eName);
136:
137: if (eName.equals("error_code")) {
138: // hit an error
139: error = true;
140: error_codeFlag = true;
141: } else if (eName.equals("error_text")) {
142: error_textFlag = true;
143: }
144:
145: if (attrs != null) {
146: for (int i = 0; i < attrs.getLength(); i++) {
147: String aName = attrs.getLocalName(i); // Attr name
148:
149: if ("".equals(aName)) {
150: aName = attrs.getQName(i);
151: }
152:
153: if (!aName.equals("xmlns")
154: && !aName.equals("xmlns:xsi")
155: && !aName.equals("xsi:schemaLocation")) {
156: emit(" ");
157: emit(aName);
158: emit(" = \"");
159: emit(attrs.getValue(i));
160: emit("\"");
161: }
162: }
163: }
164:
165: emit(">");
166: }
167:
168: public void endElement(String namespaceURI, String sName, // simple name
169: String qName // qualified name
170: ) throws SAXException {
171: echoText();
172: nl();
173:
174: // X-Server error handling
175: if (error_codeFlag)
176: error_codeFlag = false;
177: if (error_textFlag)
178: error_textFlag = false;
179:
180: String eName = sName; // element name
181:
182: if ("".equals(eName)) {
183: eName = qName; // not namespaceAware
184: }
185:
186: emit("</" + eName + ">");
187: indentLevel--;
188: }
189:
190: public void characters(char[] buf, int offset, int len)
191: throws SAXException {
192: String s = new String(buf, offset, len);
193:
194: // take care of basic entity references before printing
195: s = s.replaceAll("&", "&");
196: s = s.replaceAll("<", "<");
197: s = s.replaceAll(">", ">");
198: // s = s.replaceAll( "'", "'" );
199: // s = s.replaceAll( "\"", """ );
200:
201: if (textBuffer == null) {
202: textBuffer = new StringBuffer(s);
203: } else {
204: textBuffer.append(s);
205: }
206:
207: if (error_codeFlag)
208: error_code = textBuffer.toString();
209: if (error_textFlag)
210: error_text = textBuffer.toString();
211: }
212:
213: public void ignorableWhitespace(char[] buf, int offset, int len)
214: throws SAXException {
215: // Ignore it
216: }
217:
218: //===========================================================
219: // SAX ErrorHandler methods
220: //===========================================================
221: public void error(SAXParseException e) throws SAXParseException {
222: throw e;
223: }
224:
225: // dump warnings too
226: public void warning(SAXParseException err) throws SAXParseException {
227: LOG.warn("SAXParser warning" + ", xml line "
228: + err.getLineNumber() + ", uri " + err.getSystemId());
229: LOG.warn(" " + err.getMessage());
230: }
231:
232: //===========================================================
233: // Utility Methods
234: //===========================================================
235: private void echoText() throws SAXException {
236: if (textBuffer == null) {
237: return;
238: }
239:
240: String s = "" + textBuffer;
241:
242: if (!s.trim().equals("")) {
243: emit(s);
244: }
245:
246: textBuffer = null;
247: }
248:
249: // Wrap I/O exceptions in SAX exceptions, to
250: // suit handler signature requirements
251: private void emit(String s) throws SAXException {
252: try {
253: out.write(s);
254: out.flush();
255: } catch (IOException e) {
256: throw new SAXException("I/O error", e);
257: }
258: }
259:
260: // Start a new line
261: // and indent the next line appropriately
262: private void nl() throws SAXException {
263: String lineEnd = System.getProperty("line.separator");
264:
265: try {
266: out.write(lineEnd);
267:
268: for (int i = 0; i < indentLevel; i++)
269: out.write(indentString);
270: } catch (IOException e) {
271: throw new SAXException("I/O error", e);
272: }
273: }
274: }
|