123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364 |
- /* *******************************************************************
- * Copyright (c) 1999-2001 Xerox Corporation,
- * 2002 Palo Alto Research Center, Incorporated (PARC).
- * All rights reserved.
- * This program and the accompanying materials are made available
- * under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Xerox/PARC initial implementation
- * ******************************************************************/
-
- package org.aspectj.testing.xml;
-
- import java.io.PrintWriter;
- import java.util.List;
- import java.util.Stack;
-
- import org.aspectj.util.LangUtil;
-
- /**
- * Manage print stream to an XML document.
- * This tracks start/end elements and signals on error,
- * and optionally lineates buffer by accumulating
- * up to a maximum width (including indent).
- * This also has utilities for un/flattening lists and
- * rendering buffer.
- */
- public class XMLWriter {
- static final String SP = " ";
- static final String TAB = SP + SP;
-
- /** maximum value for maxWidth, when flowing buffer */
- public static final int MAX_WIDTH = 8000;
-
- /** default value for maxWidth, when flowing buffer */
- public static final int DEFAULT_WIDTH = 80;
-
- /** extremely inefficient! */
- public static String attributeValue(String input) {
- // if (-1 != input.indexOf("&")) {
- // String saved = input;
- // input = LangUtil.replace(input, "&", "ampamp;");
- // if (-1 == input.indexOf("&")) {
- // input = saved;
- // } else {
- // input = LangUtil.replace(input, "&", "&");
- // input = LangUtil.replace(input, "ampamp;", "&");
- // }
- // } else if (-1 != input.indexOf("&")) {
- // input = LangUtil.replace(input, "&", "&");
- // }
- input = input.replace('"', '~');
- input = input.replace('&', '=');
- return input;
- }
-
- /** @return name="{attributeValue({value})" */
- public static String makeAttribute(String name, String value) {
- return (name + "=\"" + attributeValue(value) + "\"");
- }
-
- /** same as flattenList, except also normalize \ -> / */
- public static String flattenFiles(String[] strings) {
- return flattenList(strings).replace('\\', '/');
- }
-
- /** same as flattenList, except also normalize \ -> / */
- public static String flattenFiles(List paths) {
- return flattenList(paths).replace('\\', '/');
- }
-
- /**
- * Expand comma-delimited String into list of values, without trimming
- * @param list List of items to print - null is silently ignored,
- * so for empty items use ""
- * @return String[]{} for null input, String[] {input} for input without comma,
- * or new String[] {items..} otherwise
- * @throws IllegalArgumentException if {any item}.toString() contains a comma
- */
- public static String[] unflattenList(String input) {
- return (String[]) LangUtil.commaSplit(input).toArray(new String[0]);
- }
-
- /** flatten input and add to list */
- public static void addFlattenedItems(List list, String input) {
- LangUtil.throwIaxIfNull(list, "list");
- if (null != input) {
- String[] items = XMLWriter.unflattenList(input);
- if (!LangUtil.isEmpty(items)) {
- for (String item : items) {
- if (!LangUtil.isEmpty(item)) {
- list.add(item);
- }
- }
- }
- }
- }
-
- /**
- * Collapse list into a single comma-delimited value (e.g., for list buffer)
- * @param list List of items to print - null is silently ignored,
- * so for empty items use ""
- * @return item{,item}...
- * @throws IllegalArgumentException if {any item}.toString() contains a comma
- */
- public static String flattenList(List list) {
- if ((null == list) || (0 == list.size())) {
- return "";
- }
- return flattenList(list.toArray());
- }
-
-
- /**
- * Collapse list into a single comma-delimited value (e.g., for list buffer)
- * @param list the String[] items to print - null is silently ignored,
- * so for empty items use ""
- * @return item{,item}...
- * @throws IllegalArgumentException if list[i].toString() contains a comma
- */
- public static String flattenList(Object[] list) {
- StringBuffer sb = new StringBuffer();
- if (null != list) {
- boolean printed = false;
- for (Object o : list) {
- if (null != o) {
- if (printed) {
- sb.append(",");
- } else {
- printed = true;
- }
- String s = o.toString();
- if (s.contains(",")) {
- throw new IllegalArgumentException("comma in " + s);
- }
- sb.append(s);
- }
- }
- }
- return sb.toString();
- }
-
- /** output sink */
- PrintWriter out;
-
- /** stack of String element names */
- Stack stack = new Stack();
-
- /** false if doing attributes */
- boolean attributesDone = true;
-
- /** current element prefix */
- String indent = "";
-
- /** maximum width (in char) of indent and buffer when flowing */
- int maxWidth;
-
- /**
- * Current text being flowed.
- * length() is always less than maxWidth.
- */
- StringBuffer buffer;
-
- /** @param out PrintWriter to print to - not null */
- public XMLWriter(PrintWriter out) {
- LangUtil.throwIaxIfNull(out, "out");
- this.out = out;
- buffer = new StringBuffer();
- maxWidth = DEFAULT_WIDTH;
- }
-
- /**
- * Set maximum width (in chars) of buffer to accumulate.
- * @param maxWidth int 0..MAX_WIDTH for maximum number of char to accumulate
- */
- public void setMaxWidth(int maxWidth) {
- if (0 > maxWidth) {
- this.maxWidth = 0;
- } else if (MAX_WIDTH < maxWidth) {
- this.maxWidth = MAX_WIDTH;
- } else {
- this.maxWidth = maxWidth;
- }
- }
-
- /** shortcut for entire element */
- public void printElement(String name, String attributes) {
- if (!attributesDone) throw new IllegalStateException("finish attributes");
- if (0 != buffer.length()) { // output on subelement
- outPrintln(buffer + ">");
- buffer.setLength(0);
- }
- String oldIndent = indent;
- if (0 < stack.size()) {
- indent += TAB;
- ((StackElement) stack.peek()).numChildren++;
- }
- outPrintln(indent + "<" + name + " " + attributes + "/>");
- indent = oldIndent;
- }
-
- /**
- * Start element only
- * @param name the String label of the element
- * @param closeTag if true, delimit the end of the starting tag
- */
- public void startElement(String name, boolean closeTag) {
- startElement(name, "", closeTag);
- }
-
- /**
- * Start element with buffer on the same line.
- * This does not flow buffer.
- * @param name String tag for the element
- * @param attr {name="value"}.. where value
- * is a product of attributeValue(String)
- */
- public void startElement(String name, String attr, boolean closeTag) {
- if (!attributesDone) throw new IllegalStateException("finish attributes");
- LangUtil.throwIaxIfFalse(!LangUtil.isEmpty(name), "empty name");
-
- if (0 != buffer.length()) { // output on subelement
- outPrintln(buffer + ">");
- buffer.setLength(0);
- }
- if (0 < stack.size()) {
- indent += TAB;
- }
- StringBuffer sb = new StringBuffer();
- sb.append(indent);
- sb.append("<");
- sb.append(name);
-
- if (!LangUtil.isEmpty(attr)) {
- sb.append(" ");
- sb.append(attr.trim());
- }
- attributesDone = closeTag;
- if (closeTag) {
- sb.append(">");
- outPrintln(sb.toString());
- } else if (maxWidth <= sb.length()) {
- outPrintln(sb.toString());
- } else {
- if (0 != this.buffer.length()) {
- throw new IllegalStateException("expected empty attributes starting " + name);
- }
- this.buffer.append(sb.toString());
- }
- if (0 < stack.size()) {
- ((StackElement) stack.peek()).numChildren++;
- }
- stack.push(new StackElement(name));
- }
-
- /**
- * @param name should be the same as that given to start the element
- * @throws IllegalStateException if start element does not match
- */
- public void endElement(String name) {
- // int level = stack.size();
- String err = null;
- StackElement element = null;
- if (0 == stack.size()) {
- err = "empty stack";
- } else {
- element = (StackElement) stack.pop();
- if (!element.name.equals(name)) {
- err = "expecting element " + element.name;
- }
- }
- if (null != err) {
- err = "endElement(" + name + ") " + stack + ": " + err;
- throw new IllegalStateException(err);
- }
- if (0 < element.numChildren) {
- outPrintln(indent + "</" + name + ">");
- } else if (0 < buffer.length()) {
- outPrintln(buffer + "/>");
- buffer.setLength(0);
- } else {
- outPrintln(indent + "/>");
- }
- if (!attributesDone) {
- attributesDone = true;
- }
- if (0 < stack.size()) {
- indent = indent.substring(0, indent.length() - TAB.length());
- }
- }
-
-
- /**
- * Print name=value if neither is null and name is not empty after trimming,
- * accumulating these until they are greater than maxWidth or buffer are
- * terminated with endAttributes(..) or endElement(..).
- * @param value the String to convert as attribute value - ignored if null
- * @param name the String to use as the attribute name
- * @throws IllegalArgumentException if name is null or empty after trimming
- */
- public void printAttribute(String name, String value) {
- if (attributesDone) throw new IllegalStateException("not in attributes");
- if (null == value) {
- return;
- }
- if ((null == name) || (0 == name.trim().length())) {
- throw new IllegalArgumentException("no name=" + name + "=" + value);
- }
-
- String newAttr = name + "=\"" + attributeValue(value) + "\"";
- int indentLen = indent.length();
- int bufferLen = buffer.length();
- int newAttrLen = (0 == bufferLen ? indentLen : 0) + newAttr.length();
-
- if (maxWidth > (bufferLen + newAttrLen)) {
- buffer.append(" ");
- buffer.append(newAttr);
- } else { // at least print old attributes; maybe also new
- if (0 < bufferLen) {
- outPrintln(buffer.toString());
- buffer.setLength(0);
- }
- buffer.append(indent + SP + newAttr);
- }
- }
-
- public void endAttributes() {
- if (attributesDone) throw new IllegalStateException("not in attributes");
- attributesDone = true;
- }
-
- public void printComment(String comment) {
- if (!attributesDone) throw new IllegalStateException("in attributes");
- outPrintln(indent + "<!-- " + comment + "-->");
- }
-
- public void close() {
- if (null != out) {
- out.close();
- }
-
- }
-
- public void println(String string) {
- outPrintln(string);
- }
-
- private void outPrintln(String s) {
- if (null == out) {
- throw new IllegalStateException("used after close");
- }
- out.println(s);
- }
- static class StackElement {
- String name;
- int numChildren;
- public StackElement(String name) {
- this.name = name;
- }
- }
-
- }
|