View Javadoc

1   /*
2    $Id: MarkupBuilder.java,v 1.7 2004/05/26 13:35:55 jstrachan Exp $
3   
4    Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
5   
6    Redistribution and use of this software and associated documentation
7    ("Software"), with or without modification, are permitted provided
8    that the following conditions are met:
9   
10   1. Redistributions of source code must retain copyright
11      statements and notices.  Redistributions must also contain a
12      copy of this document.
13  
14   2. Redistributions in binary form must reproduce the
15      above copyright notice, this list of conditions and the
16      following disclaimer in the documentation and/or other
17      materials provided with the distribution.
18  
19   3. The name "groovy" must not be used to endorse or promote
20      products derived from this Software without prior written
21      permission of The Codehaus.  For written permission,
22      please contact info@codehaus.org.
23  
24   4. Products derived from this Software may not be called "groovy"
25      nor may "groovy" appear in their names without prior written
26      permission of The Codehaus. "groovy" is a registered
27      trademark of The Codehaus.
28  
29   5. Due credit should be given to The Codehaus -
30      http://groovy.codehaus.org/
31  
32   THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
33   ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
34   NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
35   FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
36   THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
37   INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
38   (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
39   SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
40   HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
41   STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
42   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
43   OF THE POSSIBILITY OF SUCH DAMAGE.
44  
45   */
46  package groovy.xml;
47  
48  import groovy.util.BuilderSupport;
49  import groovy.util.IndentPrinter;
50  
51  import java.io.PrintWriter;
52  import java.io.Writer;
53  import java.util.Iterator;
54  import java.util.Map;
55  
56  /***
57   * A helper class for creating XML or HTML markup
58   * 
59   * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
60   * @author Stefan Matthias Aust
61   * @version $Revision: 1.7 $
62   */
63  public class MarkupBuilder extends BuilderSupport {
64  
65      private IndentPrinter out;
66      private boolean nospace;
67      private int state;
68  
69      public MarkupBuilder() {
70          this(new IndentPrinter());
71      }
72  
73      public MarkupBuilder(PrintWriter writer) {
74          this(new IndentPrinter(writer));
75      }
76  
77      public MarkupBuilder(Writer writer) {
78          this(new IndentPrinter(new PrintWriter(writer)));
79      }
80  
81      public MarkupBuilder(IndentPrinter out) {
82          this.out = out;
83      }
84  
85      protected void setParent(Object parent, Object child) {
86      }
87  
88      /*
89      public Object getProperty(String property) {
90          if (property.equals("_")) {
91              nospace = true;
92              return null;
93          } else {
94              Object node = createNode(property);
95              nodeCompleted(getCurrent(), node);
96              return node;
97          }
98      }
99      */
100 
101     protected Object createNode(Object name) {
102         toState(1, name);
103         return name;
104     }
105 
106     protected Object createNode(Object name, Object value) {
107         toState(2, name);
108         out.print(">");
109         out.print(value.toString());
110         return name;
111     }
112 
113     protected Object createNode(Object name, Map attributes, Object value) {
114         toState(1, name);
115         for (Iterator iter = attributes.entrySet().iterator(); iter.hasNext();) {
116             Map.Entry entry = (Map.Entry) iter.next();
117             out.print(" ");
118             print(transformName(entry.getKey().toString()));
119             out.print("='");
120             print(transformValue(entry.getValue().toString()));
121             out.print("'");
122         }
123         // FIXME: the current state model doesn't allow for nodes with attributes and values
124         return name;
125     }
126 
127     protected Object createNode(Object name, Map attributes) {
128         return createNode(name, attributes, null);
129     }
130     
131     protected void nodeCompleted(Object parent, Object node) {
132         toState(3, node);
133         out.flush();
134     }
135 
136     protected void print(Object node) {
137         out.print(node == null ? "null" : node.toString());
138     }
139 
140     protected Object getName(String methodName) {
141 		return super.getName(transformName(methodName));
142 	}
143 
144     protected String transformName(String name) {
145     	if (name.startsWith("_")) name = name.substring(1);
146     	return name.replace('_', '-');
147     }
148 
149     protected String transformValue(String value) {
150         return value.replaceAll("//'", "&quot;");
151     }
152 
153     private void toState(int next, Object name) {
154         switch (state) {
155         case 0:
156             switch (next) {
157             case 1:
158             case 2:
159                 out.print("<");
160                 print(name);
161                 break;
162             case 3:
163                 throw new Error();
164             }
165             break;
166         case 1:
167             switch (next) {
168             case 1:
169             case 2:
170                 out.print(">");
171                 if (nospace) {
172                     nospace = false;
173                 } else {
174                     out.println();
175                     out.incrementIndent();
176                     out.printIndent();
177                 }
178                 out.print("<");
179                 print(name);
180                 break;
181             case 3:
182                 out.print(" />");
183                 break;
184             }
185             break;
186         case 2:
187             switch (next) {
188             case 1:
189             case 2:
190                 throw new Error();
191             case 3:
192                 out.print("</");
193                 print(name);
194                 out.print(">");
195                 break;
196             }
197             break;
198         case 3:
199             switch (next) {
200             case 1:
201             case 2:
202                 if (nospace) {
203                     nospace = false;
204                 } else {
205                     out.println();
206 	                out.printIndent();
207                 }
208                 out.print("<");
209                 print(name);
210                 break;
211             case 3:
212                 if (nospace) {
213                     nospace = false;
214                 } else {
215                     out.println();
216                     out.decrementIndent();
217                     out.printIndent();
218                 }
219                 out.print("</");
220                 print(name);
221                 out.print(">");
222                 break;
223             }
224             break;
225         }
226         state = next;
227     }
228 
229 }