/********************************************************************************** * $URL: https://source.sakaiproject.org/svn/citations/trunk/citations-osid/xserver/src/java/org/sakaibrary/xserver/XMLCleanup.java $ * $Id: XMLCleanup.java 105079 2012-02-24 23:08:11Z ottenhoff@longsight.com $ *********************************************************************************** * * Copyright (c) 2006, 2007, 2008 The Sakai Foundation * * Licensed under the Educational Community License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.opensource.org/licenses/ECL-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * **********************************************************************************/ package org.sakaibrary.xserver; import java.io.*; import org.xml.sax.*; import org.xml.sax.helpers.DefaultHandler; import javax.xml.parsers.SAXParserFactory; import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.SAXParser; public class XMLCleanup extends DefaultHandler { private static final org.apache.commons.logging.Log LOG = org.apache.commons.logging.LogFactory.getLog( "org.sakaibrary.xserver.XMLCleanup" ); private ByteArrayOutputStream bytes; private Writer out; private InputStream inputXml; StringBuilder textBuffer; private String indentString = " "; // Amount to indent private int indentLevel = 0; // X-Server error handling private boolean error = false; private boolean error_codeFlag = false; private boolean error_textFlag = false; private String error_code; private String error_text; public XMLCleanup() { bytes = new ByteArrayOutputStream(); try { out = new OutputStreamWriter( bytes, "UTF8" ); } catch( UnsupportedEncodingException e ) { LOG.warn( "XMLCleanup() unsupported encoding: " + e.getMessage() ); } } public ByteArrayOutputStream cleanup( InputStream xml) throws XServerException { inputXml = xml; // Use the default (non-validating) parser SAXParserFactory factory = SAXParserFactory.newInstance(); try { // Parse the input SAXParser saxParser = factory.newSAXParser(); saxParser.parse( inputXml, this ); // close the stream inputXml.close(); } catch (SAXParseException spe) { // Use the contained exception, if any Exception x = spe; if (spe.getException() != null) { x = spe.getException(); } // Error generated by the parser LOG.warn("XMLCleanup.cleanup() parsing exception: " + spe.getMessage() + " - xml line " + spe.getLineNumber() + ", uri " + spe.getSystemId(), x ); } catch (SAXException sxe) { // Error generated by this application // (or a parser-initialization error) Exception x = sxe; if (sxe.getException() != null) { x = sxe.getException(); } LOG.warn( "XMLCleanup.cleanup() SAX exception: " + sxe.getMessage(), x ); } catch (ParserConfigurationException pce) { // Parser with specified options can't be built LOG.warn( "XMLCleanup.cleanup() SAX parser cannot be built with " + "specified options" ); } catch (IOException ioe) { // I/O error LOG.warn( "XMLCleanup.cleanup() IO exception", ioe ); } catch (Throwable t) { LOG.warn( "XMLCleanup.cleanup() exception", t ); } if( error ) { throw new XServerException( error_code, error_text ); } return bytes; } //=========================================================== // SAX DocumentHandler methods //=========================================================== public void setDocumentLocator(Locator l) { // Save this to resolve relative URIs or to give diagnostics. try { out.flush(); } catch (IOException e) { // Ignore errors } } public void startDocument() throws SAXException { emit("<?xml version='1.0' encoding='UTF-8'?>"); } public void endDocument() throws SAXException { nl(); try { out.flush(); } catch (IOException e) { throw new SAXException("I/O error", e); } } public void startElement(String namespaceURI, String sName, // simple name String qName, // qualified name Attributes attrs) throws SAXException { echoText(); indentLevel++; nl(); String eName = sName; // element name if ("".equals(eName)) { eName = qName; // not namespaceAware } emit("<" + eName); if( eName.equals( "error_code" ) ) { // hit an error error = true; error_codeFlag = true; } else if( eName.equals( "error_text" ) ) { error_textFlag = true; } if (attrs != null) { for (int i = 0; i < attrs.getLength(); i++) { String aName = attrs.getLocalName(i); // Attr name if ("".equals(aName)) { aName = attrs.getQName(i); } if( !aName.equals( "xmlns" ) && !aName.equals( "xmlns:xsi" ) && !aName.equals( "xsi:schemaLocation" ) ) { emit(" "); emit(aName); emit(" = \""); emit(attrs.getValue(i)); emit("\""); } } } emit(">"); } public void endElement(String namespaceURI, String sName, // simple name String qName // qualified name ) throws SAXException { echoText(); nl(); // X-Server error handling if( error_codeFlag ) error_codeFlag = false; if( error_textFlag ) error_textFlag = false; String eName = sName; // element name if ("".equals(eName)) { eName = qName; // not namespaceAware } emit("</" + eName + ">"); indentLevel--; } public void characters(char[] buf, int offset, int len) throws SAXException { String s = new String(buf, offset, len); // take care of basic entity references before printing s = s.replaceAll( "&", "&" ); s = s.replaceAll( "<", "<" ); s = s.replaceAll( ">", ">" ); // s = s.replaceAll( "'", "'" ); // s = s.replaceAll( "\"", """ ); if (textBuffer == null) { textBuffer = new StringBuilder(s); } else { textBuffer.append(s); } if( error_codeFlag ) error_code = textBuffer.toString(); if( error_textFlag ) error_text = textBuffer.toString(); } public void ignorableWhitespace(char[] buf, int offset, int len) throws SAXException { // Ignore it } //=========================================================== // SAX ErrorHandler methods //=========================================================== public void error(SAXParseException e) throws SAXParseException { throw e; } // dump warnings too public void warning(SAXParseException err) throws SAXParseException { LOG.warn("SAXParser warning" + ", xml line " + err.getLineNumber() + ", uri " + err.getSystemId()); LOG.warn(" " + err.getMessage()); } //=========================================================== // Utility Methods //=========================================================== private void echoText() throws SAXException { if (textBuffer == null) { return; } String s = "" + textBuffer; if (!s.trim().equals("")) { emit(s); } textBuffer = null; } // Wrap I/O exceptions in SAX exceptions, to // suit handler signature requirements private void emit(String s) throws SAXException { try { out.write(s); out.flush(); } catch (IOException e) { throw new SAXException("I/O error", e); } } // Start a new line // and indent the next line appropriately private void nl() throws SAXException { String lineEnd = System.getProperty("line.separator"); try { out.write(lineEnd); for (int i = 0; i < indentLevel; i++) out.write(indentString); } catch (IOException e) { throw new SAXException("I/O error", e); } } }