From owner-xml-dev@ic.ac.uk Fri Feb 6 09:38:13 1998 Date: Fri, 06 Feb 1998 10:25:39 -0500 From: Tyler Baker <tyler@infinet.com> Subject: XML Java IO Writer...
A while back I brought up the idea of having an XML InputStream which inherits FilterInputStream and did not get much response. Anyways, it would of been better for this to be an XMLReader since the Reader classes handle all of the nitty gritty character conversion for you in the first place.
Well due to the demands of the application I am writing now, it needs to format as well as parse XML data from a variety of streams so for now I am proposing that aside from just SAX, we have an IO package in the org.xml domain which could possibly have parsers assigned to them. I spent about half a day and wrote an XMLWriter class which is an extension of FilterInputStream for preparing XML Documents from Java without having to do a lot of OutputStream.write() calls manually from line to line. Things are packaged right now under org.xml.io, but that is only tentatively as I do not have any real permission from the guy who owns the rights to xml.org (I can't remember who you are so maybe this will get your attention). Right now I am using this in my own application and it works beautifully. This is what I would call a 0.1 version since it does not handle all sorts of things like Notations and lots of other stuff.
You can get the zip file with source code included.at http://www.infinet.com/~tyler/xml/xmlio01.zip.
Here is a brief description of the classes included:
package org.xml.io; import java.io.Writer; import java.io.FilterWriter; import java.io.IOException; import java.util.Hashtable; public class XMLWriter extends FilterWriter { public XMLWriter(Writer out, String padding) {} public void writeDocument(Element rootElement, String ID) throws IOException {} public void writeDocument(Element rootElement, String ID, Entity[] entities) throws IOException {} public void writeDocument(Element rootElement, String ID, Entity[] entities, boolean system) throws IOException { private String replaceText(String content) {} } This class takes as another argument, another Writer and a String which is essentially used for padding the nested levels of your document. For example, you could use two spaces as padding or else just a tab. You would create this class by making a call like this: XMLWriter writer = new XMLWriter(new OutputStreamWriter(out), " "); where out is of type OutputStream. To write a document you call writeDocument() which takes three forms. writeDocument(Element rootElement, String ID) is the same as writeDocument(Element rootElement, String ID, null, true) and writeDocument(Element rootElement, String ID, Entity[] entities) is the same as writeDocument(Element rootElement, String ID, Entity[] entities, true); writeDocument(Element rootElement, String ID, Entity[] entities, boolean system) is what is actually called. The element type is the root element you write, ID is the system or public ID of the DTD, entities are an array of type Entity[] which is used to replace in the document, and system is a flag indicating whether ID should be treated as a system ID or a public ID. So in my code I call this (the class calling this is of type element). writer.writeDocument(this, "forumReference.dtd"); package org.xml.io; public interface Element { String getName(); // may return null String getContent(); // may return null Attribute[] getAttributes(); // may return null Element[] getChildren(); // may return null String getComments(); } This interface defines an element type. Usually you implement this for each class which has data that can be mapped to an XML document. If on the other hand you have a class which should not be inherited or is even final, then use inner classes to solve your problem. For example, for java.net.InetAddress I use this in my code to implement the Element[] getChildren method. I use AbstractElement (included on org.xml.io) so I only have to redefine the methods that can return null anyways. public Element[] getChildren() { Element[] children = new Element[4]; children[0] = new AbstractElement() { public String getName() { return "id"; } public String getContent() { return ID; } }; children[1] = new AbstractElement() { public String getName() { return "host"; } public String getContent() { return host.getHostAddress(); } }; children[2] = new AbstractElement() { public String getName() { return "port"; } public String getContent() { return String.valueOf(port); } }; children[3] = new AbstractElement() { public String getName() { return "ior"; } public String getContent() { return IOR; } }; return children; } package org.xml.io; public interface Entity { String getName(); String getValue(); }
The Entity class is basically for replacement text of course. What it will do is replace any occurrences of getValue() in the rest of the stream with a '&' prepended and a ';' appended to getName(). when you call writeDocument() every entity passed will be checked in the document. This is an expensive operation so use it wisely. If null is passed as the Entity[] argument to writeDocument, then no checks will occur.
The XMLWriter class will recursively descent from the root element to all sub elements and get their content and write it out. This package is something I spent half a day on to basically get the job done for what I needed to do, and I would more than happily GPL it all later on under the xml.org.io package if given permission and there is interest in doing more (fixing bugs and adding complete XML functionality). Right now it all works for what I am doing and chopped about 300 lines of code (what I guess people call report writing) out of my application. The less code in my app, the better. Which also makes me ask is it better to have a parser which may be large in code size, but is easy to use so my production code is small, or a parser with little functionality that makes my production code large. Of course you can sometimes have the best of both worlds.
Tyler
xml-dev: A list for W3C XML Developers. To post, mailto:xml-dev@ic.ac.uk Archived as: http://www.lists.ic.ac.uk/hypermail/xml-dev/ To (un)subscribe, mailto:majordomo@ic.ac.uk the following message; (un)subscribe xml-dev To subscribe to the digests, mailto:majordomo@ic.ac.uk the following message; subscribe xml-dev-digest List coordinator, Henry Rzepa (mailto:rzepa@ic.ac.uk)