- XML parser framework rewrite
[mir.git] / source / mir / generator / tal / TALTemplate.java
1 /*\r
2  * Copyright (C) 2001, 2002 The Mir-coders group\r
3  *\r
4  * This file is part of Mir.\r
5  *\r
6  * Mir is free software; you can redistribute it and/or modify\r
7  * it under the terms of the GNU General Public License as published by\r
8  * the Free Software Foundation; either version 2 of the License, or\r
9  * (at your option) any later version.\r
10  *\r
11  * Mir is distributed in the hope that it will be useful,\r
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
14  * GNU General Public License for more details.\r
15  *\r
16  * You should have received a copy of the GNU General Public License\r
17  * along with Mir; if not, write to the Free Software\r
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
19  *\r
20  * In addition, as a special exception, The Mir-coders gives permission to link\r
21  * the code of this program with  any library licensed under the Apache Software License,\r
22  * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library\r
23  * (or with modified versions of the above that use the same license as the above),\r
24  * and distribute linked combinations including the two.  You must obey the\r
25  * GNU General Public License in all respects for all of the code used other than\r
26  * the above mentioned libraries.  If you modify this file, you may extend this\r
27  * exception to your version of the file, but you are not obligated to do so.\r
28  * If you do not wish to do so, delete this exception statement from your version.\r
29  */\r
30 package mir.generator.tal;\r
31 \r
32 import java.io.PrintWriter;\r
33 import java.util.HashMap;\r
34 import java.util.Iterator;\r
35 import java.util.List;\r
36 import java.util.Map;\r
37 import java.util.Vector;\r
38 \r
39 import mir.generator.tal.interfaces.TALExpressionParser;\r
40 import mir.generator.tal.interfaces.TALLogger;\r
41 import mir.util.HTMLRoutines;\r
42 \r
43 /**\r
44  *\r
45  *\r
46  *\r
47  * @see <a href="http://dev.zope.org/Wikis/DevSite/Projects/ZPT/TAL%20Specification%201.4">TAL Spec</a>\r
48  */\r
49 \r
50 public class TALTemplate {\r
51   private TemplateNode rootNode;\r
52   private TALExpressionParser parser;\r
53 \r
54   public TALTemplate(TALExpressionParser aParser, TemplateNode aRootNode) {\r
55     rootNode = aRootNode;\r
56     parser = aParser;\r
57   }\r
58 \r
59   public void processTemplate(Object aContext, PrintWriter aDestination, TALLogger aLogger) throws TemplateProcessingException {\r
60     StringBuffer output = new StringBuffer();\r
61 \r
62     aLogger.debug("TALTemplate", "processing rootnode");\r
63     rootNode.process(parser, aContext, output, aLogger);\r
64     aLogger.debug("TALTemplate", "done processing rootnode");\r
65     aDestination.print(output);\r
66   }\r
67 \r
68   public interface TemplateNode {\r
69     public void process(TALExpressionParser aParser, Object aContext, StringBuffer aDestination, TALLogger aLogger) throws TemplateProcessingException;\r
70   }\r
71 \r
72   public static class CompositeTemplateNode\r
73       implements TemplateNode {\r
74     private List parts;\r
75 \r
76     public CompositeTemplateNode() {\r
77       parts = new Vector();\r
78     }\r
79 \r
80     public void process(TALExpressionParser aParser, Object aContext, StringBuffer aDestination, TALLogger aLogger) throws TemplateProcessingException {\r
81       Iterator i = parts.iterator();\r
82 \r
83       while (i.hasNext()) {\r
84         ((TemplateNode) i.next()).process(aParser, aContext, aDestination, aLogger);\r
85       }\r
86     }\r
87 \r
88     public void appendSubNode(TemplateNode aNode) {\r
89       if (aNode instanceof CompositeTemplateNode) {\r
90         Iterator i = ((CompositeTemplateNode) aNode).parts.iterator();\r
91         while (i.hasNext()) {\r
92           appendSubNode((TemplateNode) i.next());\r
93         }\r
94       }\r
95       else if (aNode instanceof PlainTextTemplateNode && parts.size()>0 &&\r
96                (parts.get(parts.size()-1) instanceof PlainTextTemplateNode)) {\r
97 \r
98         ((PlainTextTemplateNode) parts.get(parts.size()-1)).appendText(((PlainTextTemplateNode) aNode).getText());\r
99       }\r
100       else {\r
101         parts.add(aNode);\r
102       }\r
103     }\r
104   }\r
105 \r
106   public static class PlainTextTemplateNode\r
107       implements TemplateNode {\r
108     private String text;\r
109 \r
110     public PlainTextTemplateNode() {\r
111       this("");\r
112     }\r
113 \r
114     public PlainTextTemplateNode(String aText) {\r
115       text = aText;\r
116     }\r
117 \r
118     public void appendText(String aText) {\r
119       text = text + aText;\r
120     }\r
121 \r
122     protected String getText() {\r
123       return text;\r
124     }\r
125 \r
126     public void process(TALExpressionParser aParser, Object aContext, StringBuffer aDestination, TALLogger aLogger) throws TemplateProcessingException {\r
127       aDestination.append(text);\r
128     }\r
129   }\r
130 \r
131   public static class SmartTemplateNode implements TemplateNode {\r
132     private String tag;\r
133     private Map fixedAttributes;\r
134     private Map attributeModifiers;\r
135 \r
136     private List definitions;\r
137     private Object condition;\r
138 \r
139     private Object repeatVariable;\r
140     private Object repeatExpression;\r
141     private Object contentExpression;\r
142     private Object omitTagExpression;\r
143     private Object errorExpression;\r
144 \r
145     private TemplateNode body;\r
146 \r
147     public SmartTemplateNode(String aTag) {\r
148       tag = aTag;\r
149 \r
150       fixedAttributes = new HashMap();\r
151       attributeModifiers = new HashMap();\r
152 \r
153       definitions = new Vector();\r
154       condition = null;\r
155 \r
156       repeatVariable = null;\r
157       repeatExpression = null;\r
158       contentExpression = null;\r
159       omitTagExpression = null;\r
160 \r
161       body = null;\r
162     }\r
163 \r
164     public void setBody(TemplateNode aBody) {\r
165       body = aBody;\r
166     }\r
167 \r
168     public void addFixedAttribute(String aKey, String aValue) {\r
169       fixedAttributes.put(aKey, aValue);\r
170     }\r
171 \r
172     public void addModifiedAttribute(String aKey, Object aValue) {\r
173       attributeModifiers.put(aKey, aValue);\r
174     }\r
175 \r
176     public void addDefinition(Object aKey, Object aValue) {\r
177       definitions.add(new Definition(aKey, aValue));\r
178     }\r
179 \r
180     public void setCondition(Object aCondition) {\r
181       condition = aCondition;\r
182     }\r
183 \r
184     public void setRepeat(Object aRepeatVariable, Object aRepeatExpression) {\r
185       repeatVariable = aRepeatVariable;\r
186       repeatExpression = aRepeatExpression;\r
187     }\r
188 \r
189     public void setContent(Object aContentExpression) {\r
190       contentExpression = aContentExpression;\r
191     }\r
192 \r
193     public void setOmitTag(Object anOmitTagExpression) {\r
194       omitTagExpression = anOmitTagExpression;\r
195     }\r
196 \r
197     public void setError(Object anErrorExpression) {\r
198       errorExpression = anErrorExpression;\r
199     }\r
200 \r
201     public static class Definition {\r
202       private Object variable;\r
203       private Object expression;\r
204 \r
205       public Definition(Object aVariable, Object anExpression) {\r
206         variable = aVariable;\r
207         expression = anExpression;\r
208       }\r
209 \r
210       public Object getVariable() {\r
211         return variable;\r
212       }\r
213 \r
214       public Object getExpression() {\r
215         return expression;\r
216       }\r
217     }\r
218 \r
219     public void process(TALExpressionParser aParser, Object aContext, StringBuffer aDestination, TALLogger aLogger) throws TemplateProcessingException {\r
220       Iterator i;\r
221 \r
222         i = definitions.iterator();\r
223         while (i.hasNext()) {\r
224           Definition d = (Definition) i.next();\r
225           aParser.processAssignment(aContext, d.getVariable(), d.getExpression());\r
226         }\r
227 \r
228         if (condition == null || aParser.evaluateBooleanExpression(aContext, condition)) {\r
229           if (repeatExpression != null) {\r
230             i = aParser.evaluateListExpression(aContext, repeatExpression);\r
231 \r
232             while (i.hasNext()) {\r
233               aParser.processDirectAssignment(aContext, repeatVariable, i.next());\r
234               innerProcess(aParser, aContext, aDestination, aLogger);\r
235             }\r
236           }\r
237           else {\r
238             innerProcess(aParser, aContext, aDestination, aLogger);\r
239           }\r
240         }\r
241     };\r
242 \r
243     private void innerProcess(TALExpressionParser aParser, Object aContext, StringBuffer aDestination, TALLogger aLogger)\r
244        throws TemplateProcessingException\r
245     {\r
246       boolean omitTag = false;\r
247       if (omitTagExpression != null)\r
248         omitTag = aParser.evaluateBooleanExpression(aContext, omitTagExpression);\r
249 \r
250       if (!omitTag) {\r
251         Map generatedAttributes = new HashMap(fixedAttributes);\r
252 \r
253         Iterator i = attributeModifiers.keySet().iterator();\r
254         while (i.hasNext()) {\r
255           Map.Entry entry = (Map.Entry) i.next();\r
256 \r
257           generatedAttributes.put(entry.getKey(), aParser.evaluateStringExpression(aContext, entry.getValue()));\r
258         }\r
259 \r
260         aDestination.append("<");\r
261         aDestination.append(tag);\r
262 \r
263         i = generatedAttributes.entrySet().iterator();\r
264         while (i.hasNext()) {\r
265           Map.Entry entry = (Map.Entry) i.next();\r
266           aDestination.append(" ");\r
267           aDestination.append(entry.getKey());\r
268           aDestination.append("=");\r
269           aDestination.append("\"");\r
270           aDestination.append(HTMLRoutines.encodeHTML( (String) entry.getValue()));\r
271           aDestination.append("\"");\r
272         }\r
273         aDestination.append(">");\r
274       }\r
275 \r
276       StringBuffer destination = aDestination;\r
277       if (errorExpression != null) {\r
278         destination = new StringBuffer();\r
279       }\r
280       try {\r
281         if (contentExpression != null) {\r
282           destination.append(aParser.evaluateStringExpression(aContext, contentExpression));\r
283         }\r
284         else {\r
285           if (body != null)\r
286             body.process(aParser, aContext, destination, aLogger);\r
287         }\r
288       }\r
289       catch (Throwable t) {\r
290         if (!(t instanceof TemplateProcessingException))\r
291           aLogger.error("TALTemplate.SmartTemplateNode.processs", "exception occurred: " + t.toString());\r
292         if (errorExpression != null) {\r
293           try {\r
294             destination.delete(0, destination.length());\r
295 \r
296             aParser.processPseudoAssignment(aContext, "exception", t);\r
297             destination.append(aParser.evaluateStringExpression(aContext, errorExpression));\r
298           }\r
299           catch (Throwable s) {\r
300           }\r
301         }\r
302         else {\r
303           throw new TemplateProcessingException(t);\r
304         }\r
305       }\r
306       finally {\r
307         if (errorExpression != null) {\r
308           aDestination.append(destination);\r
309         }\r
310       }\r
311       if (!omitTag) {\r
312         aDestination.append("</");\r
313         aDestination.append(tag);\r
314         aDestination.append(">");\r
315       }\r
316     }\r
317   }\r
318 \r
319   public static class TemplateProcessingException extends Exception {\r
320     private Throwable cause;\r
321 \r
322     public TemplateProcessingException(Throwable aCause) {\r
323       this (aCause.getMessage(), aCause);\r
324     }\r
325 \r
326     public TemplateProcessingException(String aMessage, Throwable aCause) {\r
327       super(aMessage);\r
328 \r
329       cause = aCause;\r
330     }\r
331 \r
332     public TemplateProcessingException(String aMessage) {\r
333       this(aMessage, null);\r
334     }\r
335   }\r
336 }