001: //The contents of this file are subject to the Mozilla Public License Version 1.1
002: //(the "License"); you may not use this file except in compliance with the
003: //License. You may obtain a copy of the License at http://www.mozilla.org/MPL/
004: //
005: //Software distributed under the License is distributed on an "AS IS" basis,
006: //WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
007: //for the specific language governing rights and
008: //limitations under the License.
009: //
010: //The Original Code is "The Columba Project"
011: //
012: //The Initial Developers of the Original Code are Frederik Dietz and Timo Stich.
013: //Portions created by Frederik Dietz and Timo Stich are Copyright (C) 2003.
014: //
015: //All Rights Reserved.
016: package org.columba.core.xml;
017:
018: import java.io.BufferedWriter;
019: import java.io.CharArrayWriter;
020: import java.io.FileOutputStream;
021: import java.io.IOException;
022: import java.io.InputStream;
023: import java.io.OutputStream;
024: import java.io.OutputStreamWriter;
025: import java.io.Writer;
026: import java.net.URL;
027: import java.util.Enumeration;
028: import java.util.Iterator;
029: import java.util.List;
030: import java.util.logging.Logger;
031:
032: import javax.swing.JOptionPane;
033: import javax.xml.parsers.SAXParser;
034: import javax.xml.parsers.SAXParserFactory;
035:
036: import org.columba.core.logging.Logging;
037: import org.xml.sax.Attributes;
038: import org.xml.sax.SAXException;
039: import org.xml.sax.helpers.DefaultHandler;
040:
041: public class XmlIO extends DefaultHandler {
042:
043: private static final Logger LOG = Logger
044: .getLogger("org.columba.core.xml");
045:
046: private static final String ROOT_XML_ELEMENT_NAME = "__COLUMBA_XML_TREE_TOP__";
047:
048: // Top level element (Used to hold everything else)
049: private XmlElement rootElement;
050:
051: // The current element you are working on
052: private XmlElement currentElement;
053:
054: // For writing out the data
055: // Indent for each level
056: private int writeIndent = 2;
057:
058: // Maximum data to put on a "one liner"
059: private int maxOneLineData = 20;
060:
061: // Buffer for collecting data from
062: // the "characters" SAX event.
063: private CharArrayWriter contents = new CharArrayWriter();
064:
065: private URL url = null;
066:
067: /*
068: * // Default constructor public XmlIO() { }
069: */
070: /*
071: * // setup and load constructor public XmlIO(String FilePath) {
072: * currentElement = null;
073: * }
074: */
075: public XmlIO(URL url) {
076: super ();
077: this .url = url;
078: }
079:
080: // setup and load constructor
081: public XmlIO() {
082: currentElement = null;
083: }
084:
085: // setup and load constructor
086:
087: /**
088: * Creates a XmlIO object with the specified element at the top.
089: *
090: * @param element
091: * the element at the top.
092: */
093: public XmlIO(XmlElement element) {
094: rootElement = new XmlElement(ROOT_XML_ELEMENT_NAME);
095: rootElement.addElement(element);
096: }
097:
098: public void setURL(URL url) {
099: this .url = url;
100: }
101:
102: public boolean load() {
103: // this.file = F;
104: return load(url);
105: }
106:
107: // Load a file. This is what starts things off.
108:
109: /**
110: * Loads from the InputStream into the root Xml Element.
111: *
112: * @param input
113: * the input stream to load from.
114: */
115: public boolean load(InputStream input) {
116:
117: rootElement = new XmlElement(ROOT_XML_ELEMENT_NAME);
118: currentElement = rootElement;
119:
120: try {
121: // Create the XML reader...
122: // xr = XMLReaderFactory.createXMLReader();
123: SAXParserFactory factory = SAXParserFactory.newInstance();
124:
125: // Set the ContentHandler...
126: // xr.setContentHandler( this );
127: SAXParser saxParser = factory.newSAXParser();
128:
129: saxParser.parse(input, this );
130: } catch (javax.xml.parsers.ParserConfigurationException ex) {
131: LOG
132: .severe("XML config error while attempting to read from the input stream \n'"
133: + input + "'");
134: LOG.severe(ex.toString());
135: ex.printStackTrace();
136:
137: return (false);
138: } catch (SAXException ex) {
139: // Error
140: LOG
141: .severe("XML parse error while attempting to read from the input stream \n'"
142: + input + "'");
143: LOG.severe(ex.toString());
144: ex.printStackTrace();
145:
146: return (false);
147: } catch (IOException ex) {
148: LOG
149: .severe("I/O error while attempting to read from the input stream \n'"
150: + input + "'");
151: LOG.severe(ex.toString());
152: ex.printStackTrace();
153:
154: return (false);
155: }
156:
157: // XmlElement.printNode( getRoot(), "");
158: return (true);
159: }
160:
161: /**
162: * Load a file. This is what starts things off.
163: *
164: * @param inputURL
165: * the URL to load XML from.
166: */
167: public boolean load(URL inputURL) {
168:
169: rootElement = new XmlElement(ROOT_XML_ELEMENT_NAME);
170: currentElement = rootElement;
171:
172: try {
173: // Create the XML reader...
174: // xr = XMLReaderFactory.createXMLReader();
175: SAXParserFactory factory = SAXParserFactory.newInstance();
176:
177: // Set the ContentHandler...
178: // xr.setContentHandler( this );
179: SAXParser saxParser = factory.newSAXParser();
180:
181: saxParser.parse(inputURL.toString(), this );
182: } catch (javax.xml.parsers.ParserConfigurationException ex) {
183: LOG
184: .severe("XML config error while attempting to read XML file \n'"
185: + inputURL + "'");
186: LOG.severe(ex.toString());
187: if (Logging.DEBUG)
188: ex.printStackTrace();
189:
190: return (false);
191: } catch (SAXException ex) {
192: // Error
193: LOG
194: .severe("XML parse error while attempting to read XML file \n'"
195: + inputURL + "'");
196: LOG.severe(ex.toString());
197: if (Logging.DEBUG)
198: ex.printStackTrace();
199:
200: return (false);
201: } catch (IOException ex) {
202: LOG
203: .severe("I/O error while attempting to read XML file \n'"
204: + inputURL + "'");
205: LOG.severe(ex.toString());
206: if (Logging.DEBUG)
207: ex.printStackTrace();
208:
209: return (false);
210: }
211:
212: // XmlElement.printNode( getRoot(), "");
213: return (true);
214: }
215:
216: // Implement the content hander methods that
217: // will delegate SAX events to the tag tracker network.
218: public void startElement(String namespaceURI, String localName,
219: String qName, Attributes attrs) throws SAXException {
220: // Resetting contents buffer.
221: // Assuming that tags either tag content or children, not both.
222: // This is usually the case with XML that is representing
223: // data strucutures in a programming language independant way.
224: // This assumption is not typically valid where XML is being
225: // used in the classical text mark up style where tagging
226: // is used to style content and several styles may overlap
227: // at once.
228: try {
229: contents.reset();
230:
231: String name = localName; // element name
232:
233: if (name.equals("")) {
234: name = qName; // namespaceAware = false
235: }
236:
237: XmlElement p = currentElement;
238:
239: currentElement = currentElement.addSubElement(name);
240: currentElement.setParent(p);
241:
242: if (attrs != null) {
243: for (int i = 0; i < attrs.getLength(); i++) {
244: String aName = attrs.getLocalName(i); // Attr name
245:
246: if (aName.equals("")) {
247: aName = attrs.getQName(i);
248: }
249:
250: currentElement.addAttribute(aName, attrs
251: .getValue(i));
252: }
253: }
254: } catch (java.lang.NullPointerException ex) {
255: LOG.severe("Null!!!");
256: LOG.severe(ex.toString());
257: ex.printStackTrace();
258: }
259: }
260:
261: public void endElement(String namespaceURI, String localName,
262: String qName) throws SAXException {
263: currentElement.setData(contents.toString().trim());
264: contents.reset();
265:
266: currentElement = currentElement.getParent();
267: }
268:
269: public void characters(char[] ch, int start, int length)
270: throws SAXException {
271: // accumulate the contents into a buffer.
272: contents.write(ch, start, length);
273: }
274:
275: /**
276: * Returns the root for the XmlElement hiearchy. Note that this Xml Element
277: * will always have the name <code>__COLUMBA_XML_TREE_TOP__</code>.
278: * <p>
279: * Methods that want to retrieve elements from this root should use the
280: * {@link XmlElement#getElement(String)} in order to get the wanted element.
281: *
282: * @return a XmlElement if it has been loaded or initialized with it; null
283: * otherwise.
284: */
285: public XmlElement getRoot() {
286: return (rootElement);
287: }
288:
289: public void errorDialog(String Msg) {
290: JOptionPane.showMessageDialog(null, "Error: " + Msg);
291: }
292:
293: public void warningDialog(String Msg) {
294: JOptionPane.showMessageDialog(null, "Warning: " + Msg);
295: }
296:
297: public void infoDialog(String Msg) {
298: JOptionPane.showMessageDialog(null, "Info: " + Msg);
299: }
300:
301: public void save() throws Exception {
302: write(new FileOutputStream(url.getPath()));
303: }
304:
305: //
306: // Writer interface
307: //
308: public void write(OutputStream out) throws IOException {
309: BufferedWriter PW = new BufferedWriter(new OutputStreamWriter(
310: out, "UTF-8"));
311: PW.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
312:
313: if (rootElement.subElements.size() > 0) {
314: for (int i = 0; i < rootElement.subElements.size(); i++) {
315: _writeSubNode(PW, (XmlElement) rootElement.subElements
316: .get(i), 0);
317: }
318: }
319:
320: PW.flush();
321: }
322:
323: private void _writeSubNode(Writer out, XmlElement element,
324: int indent) throws IOException {
325: _writeSpace(out, indent);
326: out.write("<");
327: out.write(element.getName());
328:
329: for (Enumeration e = element.getAttributeNames(); e
330: .hasMoreElements();) {
331: String K = (String) e.nextElement();
332: out.write(" " + K + "=\""
333: + TextUtils.escapeText(element.getAttribute(K))
334: + "\"");
335: }
336:
337: out.write(">");
338:
339: String data = element.getData();
340:
341: if ((data != null) && !data.equals("")) {
342: if (data.length() > maxOneLineData) {
343: out.write("\n");
344: _writeSpace(out, indent + writeIndent);
345: }
346:
347: out.write(TextUtils.escapeText(data));
348: }
349:
350: List subElements = element.getElements();
351:
352: if (subElements.size() > 0) {
353: out.write("\n");
354:
355: for (Iterator it = subElements.iterator(); it.hasNext();) {
356: _writeSubNode(out, (XmlElement) it.next(), indent
357: + writeIndent);
358:
359: // for (int i = 0; i < subElements.size(); i++) {
360: // _writeSubNode(
361: // out,
362: // (XmlElement) subElements.get(i),
363: // indent + writeIndent);
364: }
365:
366: _writeSpace(out, indent);
367: }
368:
369: if (data.length() > maxOneLineData) {
370: out.write("\n");
371: _writeSpace(out, indent);
372: }
373:
374: out.write("</" + TextUtils.escapeText(element.getName())
375: + ">\n");
376: }
377:
378: private void _writeSpace(Writer out, int numSpaces)
379: throws IOException {
380: for (int i = 0; i < numSpaces; i++) {
381: out.write(" ");
382: }
383: }
384: }
385:
386: // End class XmlIO
|