/* * $Id: TagList.java,v 1.3 2005/06/16 00:57:05 ian Exp $ * $Name: gxparse-sf-alpha-2_0 $ * * This file is part of GXPARSE, a general XML parser API. * Copyright (C) 2003-2005 Ian E. Gorman * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * or go to http://www.gnu.org/ * * Ian E. Gorman http://gorman.ca/ */ package xml; import ca.gorman.io.*; import ca.gorman.xml.parse.*; import ca.gorman.xml.parse.sax.ValidatingParserFactory; import ca.gorman.xml.parse.util.DtdUtilities; import java.io.*; import java.net.URI; /**

* Example that lists start and end tags, using resequencing to place the * character count for each element immediately after the start tag for that * element. * * @author (ian) Ian E. Gorman. */ public class TagList extends AbstractErrorListener> { /* * A single method, with multiple invocations active at the same time, is * used because all elements receive identical handling. * * At the start of each element, the start tag is printed, followed by a * Mark for the character counts. Three new CharArrayWriters are pushed on * on WriterStacks to collect PCDATA, CDATA, and Ignorable Whitespace. Then * the element content is parsed, causing the element method to be invoked * again for each child element, and causing the character content to go to * one of the CharArrayWriters. * * At the end of an element, the three CharArrayWriters for that element * are popped (to stop the accumulation of characters, and their sizes are * written to the previously written Mark. This has the same effect as if * we could reposition to a previous point in the output, insert more data, * and then reposition to the end of the output to continue writing data. */ private final String INDENT = " "; private final String lineSeparator = System.getProperty("line.separator").intern(); private AbstractMessageListener> messageListener = AbstractMessageListener.>newInstance(); private String [] argv = null; private int anonymousKeyCount = 0; private String indent = ""; private boolean isCdata = false; // Writer stacks for temporary storage of character data private WriterStack cdataWriterStack = new WriterStack(new NullOutputWriter()); private WriterStack pcdataWriterStack = new WriterStack(new NullOutputWriter()); private WriterStack ignorableWhitespaceWriterStack = new WriterStack(new NullOutputWriter()); // Writer with pseudo-random access to the output stream private ResequencingWriter resequencingWriter; private Input input; // private Writer out; private PrintWriter err; public TagList(Input input, Writer out, Writer err) throws IOException, NoSuchMethodException, IllegalAccessException { super(); this.input = input; this.err = new PrintWriter(err, true); resequencingWriter = new ResequencingWriter(out); } public static void main(String[] argv) { Input input = new Input(new InputStreamReader(System.in)); Writer out = new OutputStreamWriter(System.out); Writer err = new OutputStreamWriter(System.err);; try { if (argv.length > 0) { input = new Input(new URI(argv[0])); } new TagList(input, out, err).run(); } catch(Exception e) { e.printStackTrace(); } } /**

* Prepare to write the document, including some of the initial preparation * for writing before and after the current point in the output document, * and start the parser. */ public void run() { try { // get parser ParserFactory parserFactory = ValidatingParserFactory.newInstance(); Parser parser = parserFactory.newParser(); parser.setListener(this); parser.parse(input); } catch(Exception e) { e.printStackTrace(err); } finally { try { resequencingWriter.close(); } catch(Exception e) { err.println(e.getMessage()); } try { err.flush(); } catch(Exception e) { System.err.println(e.getMessage()); } } } ////// character handlers ///////////////// public void characters(Parser parser, CharSequence charSequence) throws ListenerException, IOException { // copy input to the appropriate stack, CDATA or PCDATA if (isCdata) { cdataWriterStack.append(charSequence); } else { pcdataWriterStack.append(charSequence); } } public void cdata(Parser parser, CurrentMarkedSection cdata) throws ListenerException, IOException { // change processing state while in CDATA marked section isCdata = true; cdata.parseContent(); isCdata = false; } public void ignorableWhitespace(Parser parser, CharSequence charSequence) throws ListenerException, IOException { // copy input to the output ignorableWhitespaceWriterStack.append(charSequence); } // every element is handled the same way public void doElement(Parser parser, CurrentElement element) throws ListenerException, IOException { // output the start tag and increase the indent level printStartTag(element); String saveIndent = indent; indent += INDENT; // Get an anonymous Mark and write it as a placeholder for data that // will be acquired later in the input Resequencer.Mark mark = resequencingWriter.mark(); resequencingWriter.write(mark); // set up to collect character content in several writers CharArrayWriter pcdataArrayWriter = new CharArrayWriter(); pcdataWriterStack.push(pcdataArrayWriter); CharArrayWriter cdataArrayWriter = new CharArrayWriter(); cdataWriterStack.push(cdataArrayWriter); CharArrayWriter igwspArrayWriter = new CharArrayWriter(); ignorableWhitespaceWriterStack.push(igwspArrayWriter); // process the element content, doing any output required for child // elements. Pop the CharArrayWriters so that they will not collect // any more output. element.parseContent(); pcdataWriterStack.pop(); cdataWriterStack.pop(); ignorableWhitespaceWriterStack.pop(); // Now write the character counts to the Mark (placeholder) that was // written immediately after the start tag // This has the same effect as if we could rewind the output to a // previous point, insert additional data at the previous point, and // then return to the current end of output to append more data. int pcdataSize = pcdataArrayWriter.size(); if (pcdataSize > 0) { mark.write(indent + "PCDATA: " + Integer.toString(pcdataSize) + lineSeparator); } int cdataSize = cdataArrayWriter.size(); if (cdataSize > 0) { mark.write(indent + "CDATA: " + Integer.toString(cdataSize) + lineSeparator); } int igwspSize = igwspArrayWriter.size(); if (igwspSize > 0) { mark.write(indent + "IgnorableWhitespace: " + Integer.toString(igwspSize) + lineSeparator); } // restore the previous indent level and output the end tag indent = saveIndent; printEndTag(element); } private void printStartTag(Element element) throws IOException { Attribute [] attribute = element.getAttributes(); resequencingWriter.write(indent + "<" + DtdUtilities.getPrefixedName(element)); for (int i = 0 ; i < attribute.length ; ++i) { resequencingWriter.write(" " + DtdUtilities.getPrefixedName(attribute[i]) + "=\"" + attribute[i].getQuotableValue() + "\""); } resequencingWriter.write(">" + lineSeparator); } private void printEndTag(Element element) throws IOException { resequencingWriter.write(indent + "" + lineSeparator); } }