merged 1.1 branch into head
[mir.git] / source / mir / generator / tal / template / CoreTemplateNodeLibrary.java
index e806deb..b2e2966 100755 (executable)
-/*\r
- * Copyright (C) 2001, 2002 The Mir-coders group\r
- *\r
- * This file is part of Mir.\r
- *\r
- * Mir is free software; you can redistribute it and/or modify\r
- * it under the terms of the GNU General Public License as published by\r
- * the Free Software Foundation; either version 2 of the License, or\r
- * (at your option) any later version.\r
- *\r
- * Mir is distributed in the hope that it will be useful,\r
- * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
- * GNU General Public License for more details.\r
- *\r
- * You should have received a copy of the GNU General Public License\r
- * along with Mir; if not, write to the Free Software\r
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
- *\r
- * In addition, as a special exception, The Mir-coders gives permission to link\r
- * the code of this program with  any library licensed under the Apache Software License,\r
- * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library\r
- * (or with modified versions of the above that use the same license as the above),\r
- * and distribute linked combinations including the two.  You must obey the\r
- * GNU General Public License in all respects for all of the code used other than\r
- * the above mentioned libraries.  If you modify this file, you may extend this\r
- * exception to your version of the file, but you are not obligated to do so.\r
- * If you do not wish to do so, delete this exception statement from your version.\r
- */\r
-\r
-package mir.generator.tal.template;\r
-\r
-import java.util.*;\r
-\r
-import mir.generator.tal.interfaces.TALExpressionParser;\r
-import mir.generator.tal.interfaces.TALLogger;\r
-import mir.util.HTMLRoutines;\r
-import mir.util.StringRoutines;\r
-import mir.util.xml.XMLName;\r
-import mir.util.xml.XMLParserExc;\r
-import mir.util.xml.XMLReaderTool;\r
-\r
-public class CoreTemplateNodeLibrary implements TemplateNodeLibrary {\r
-  private String prefix;\r
-  private String uri;\r
-\r
-  private boolean isOurTag(XMLName aName) {\r
-    return prefix.equals(aName.getPrefix()) || uri.equals(aName.getNamespaceURI());\r
-  }\r
-\r
-  public CoreTemplateNodeLibrary(String aPrefix, String aUri) {\r
-    prefix = aPrefix;\r
-    uri = aUri;\r
-  }\r
-\r
-  private static final String CONDITION_ATTRIBUTE = "condition";\r
-  private static final String REPEAT_ATTRIBUTE = "repeat";\r
-  private static final String CONTENT_ATTRIBUTE = "content";\r
-  private static final String ERROR_ATTRIBUTE = "on-error";\r
-  private static final String REPLACE_ATTRIBUTE = "replace";\r
-  private static final String DEFINITION_ATTRIBUTE = "define";\r
-  private static final String OMITTAG_ATTRIBUTE = "omit-tag";\r
-  private static final String ATTRIBUTE_ATTRIBUTE = "attributes";\r
-\r
-  public TemplateNode constructTemplateNode(TALExpressionParser aParser, XMLName aTag, Map anAttributes,\r
-      TemplateNode aChildTemplateNode, Map aTemplateContext) throws XMLParserExc {\r
-    TALBasicTemplateNode result = new TALBasicTemplateNode(XMLReaderTool.normalizeXMLName(aTag));\r
-    result.setBody(aChildTemplateNode);\r
-\r
-    if (isOurTag(aTag))\r
-      result.setOmitTag(aParser.preparseTRUE());\r
-\r
-    Iterator i = anAttributes.entrySet().iterator();\r
-    while (i.hasNext()) {\r
-      Map.Entry entry = (Map.Entry) i.next();\r
-      XMLName name = (XMLName) entry.getKey();\r
-\r
-      if (!isOurTag(name)) {\r
-        result.addFixedAttribute(XMLReaderTool.normalizeXMLName(name), (String) entry.getValue());\r
-      }\r
-      else {\r
-        if (name.getLocalName().equalsIgnoreCase(DEFINITION_ATTRIBUTE)) {\r
-          List definitions = StringRoutines.splitStringWithEscape((String) entry.getValue(), ';', '\\');\r
-\r
-          Iterator j = definitions.iterator();\r
-          while (j.hasNext())\r
-          {\r
-            List parts = StringRoutines.separateString((String) j.next(), " ");\r
-\r
-            if (parts.size()==2) {\r
-              result.addDefinition(aParser.preparseReferenceExpression((String) parts.get(0)), aParser.preparseExpression((String) parts.get(1)));\r
-            }\r
-          }\r
-        }\r
-        else if (name.getLocalName().equalsIgnoreCase(CONDITION_ATTRIBUTE)) {\r
-          result.setCondition(aParser.preparseBooleanExpression((String) entry.getValue()));\r
-        }\r
-        else if (name.getLocalName().equalsIgnoreCase(CONTENT_ATTRIBUTE)) {\r
-          result.setContent(aParser.preparseStringExpression((String) entry.getValue()));\r
-        }\r
-        else if (name.getLocalName().equalsIgnoreCase(ERROR_ATTRIBUTE)) {\r
-          result.setError(aParser.preparseStringExpression((String) entry.getValue()));\r
-        }\r
-        else if (name.getLocalName().equalsIgnoreCase(OMITTAG_ATTRIBUTE)) {\r
-          if (((String) entry.getValue()).trim().length()==0)\r
-            result.setOmitTag(aParser.preparseTRUE());\r
-          else\r
-            result.setOmitTag(aParser.preparseBooleanExpression((String) entry.getValue()));\r
-        }\r
-        else if (name.getLocalName().equalsIgnoreCase(REPLACE_ATTRIBUTE)) {\r
-          result.setOmitTag(aParser.preparseTRUE());\r
-          result.setContent(aParser.preparseStringExpression((String) entry.getValue()));\r
-        }\r
-        else if (name.getLocalName().equalsIgnoreCase(REPEAT_ATTRIBUTE)) {\r
-          List parts = StringRoutines.separateString((String) entry.getValue(), " ");\r
-\r
-          if (parts.size()==2) {\r
-            result.setRepeat(aParser.preparseReferenceExpression((String) parts.get(0)), aParser.preparseExpression((String) parts.get(1)));\r
-          }\r
-        }\r
-        else if (name.getLocalName().equalsIgnoreCase(ATTRIBUTE_ATTRIBUTE)) {\r
-          List attributes = StringRoutines.splitStringWithEscape((String) entry.getValue(), ';', '\\');\r
-\r
-          Iterator j = attributes.iterator();\r
-          while (j.hasNext()) {\r
-            String value = (String) j.next();\r
-            List parts = StringRoutines.separateString(value.trim(), " ");\r
-\r
-            if (parts.size()==2) {\r
-              result.addModifiedAttribute((String) parts.get(0), aParser.preparseExpression((String) parts.get(1)));\r
-            }\r
-            else {\r
-              throw new XMLParserExc(ATTRIBUTE_ATTRIBUTE + " tag should have exactly 2 parts ("+value+")");\r
-            }\r
-          }\r
-        }\r
-      }\r
-    }\r
-\r
-    return result;\r
-  }\r
-\r
-  public static class TALBasicTemplateNode implements TemplateNode {\r
-    private String tag;\r
-    private Map fixedAttributes;\r
-    private Map attributeModifiers;\r
-\r
-    private List definitions;\r
-    private Object condition;\r
-\r
-    private Object repeatVariable;\r
-    private Object repeatExpression;\r
-    private Object contentExpression;\r
-    private Object omitTagExpression;\r
-    private Object errorExpression;\r
-\r
-    private TemplateNode body;\r
-\r
-    public TALBasicTemplateNode(String aTag) {\r
-      tag = aTag;\r
-\r
-      fixedAttributes = new HashMap();\r
-      attributeModifiers = new HashMap();\r
-\r
-      definitions = new ArrayList();\r
-      condition = null;\r
-\r
-      repeatVariable = null;\r
-      repeatExpression = null;\r
-      contentExpression = null;\r
-      omitTagExpression = null;\r
-\r
-      body = null;\r
-    }\r
-\r
-    public void setBody(TemplateNode aBody) {\r
-      body = aBody;\r
-    }\r
-\r
-    public void addFixedAttribute(String aKey, String aValue) {\r
-      fixedAttributes.put(aKey, aValue);\r
-    }\r
-\r
-    public void addModifiedAttribute(String aKey, Object aValue) {\r
-      attributeModifiers.put(aKey, aValue);\r
-    }\r
-\r
-    public void addDefinition(Object aKey, Object aValue) {\r
-      definitions.add(new Definition(aKey, aValue));\r
-    }\r
-\r
-    public void setCondition(Object aCondition) {\r
-      condition = aCondition;\r
-    }\r
-\r
-    public void setRepeat(Object aRepeatVariable, Object aRepeatExpression) {\r
-      repeatVariable = aRepeatVariable;\r
-      repeatExpression = aRepeatExpression;\r
-    }\r
-\r
-    public void setContent(Object aContentExpression) {\r
-      contentExpression = aContentExpression;\r
-    }\r
-\r
-    public void setOmitTag(Object anOmitTagExpression) {\r
-      omitTagExpression = anOmitTagExpression;\r
-    }\r
-\r
-    public void setError(Object anErrorExpression) {\r
-      errorExpression = anErrorExpression;\r
-    }\r
-\r
-    public static class Definition {\r
-      private Object variable;\r
-      private Object expression;\r
-\r
-      public Definition(Object aVariable, Object anExpression) {\r
-        variable = aVariable;\r
-        expression = anExpression;\r
-      }\r
-\r
-      public Object getVariable() {\r
-        return variable;\r
-      }\r
-\r
-      public Object getExpression() {\r
-        return expression;\r
-      }\r
-    }\r
-\r
-    public void process(TALExpressionParser aParser, Object aContext,\r
-        StringBuffer aDestination, TALLogger aLogger, Map aTemplateContext,\r
-        TemplateLibrary aLibrary) throws TemplateProcessingException {\r
-      if (errorExpression != null) {\r
-        StringBuffer destination = new StringBuffer();\r
-\r
-        try {\r
-          outerProcess(aParser, aContext, destination, aLogger, aTemplateContext, aLibrary);\r
-        }\r
-        catch (Throwable t) {\r
-          try {\r
-//            destination.delete(0, destination.length());\r
-            aParser.processPseudoAssignment(aContext, "exception", t);\r
-            destination.insert(0, aParser.evaluateStringExpression(aContext, errorExpression));\r
-            destination.append(" >>>ERROR POSITION<<< ");\r
-          }\r
-          catch (Throwable s) {\r
-            throw new TemplateProcessingException(s);\r
-          }\r
-        }\r
-        finally {\r
-          aDestination.append(destination);\r
-        }\r
-      }\r
-      else {\r
-        outerProcess(aParser, aContext, aDestination, aLogger, aTemplateContext, aLibrary);\r
-      }\r
-    }\r
-\r
-    public String getPlainText() {\r
-      return body.getPlainText();\r
-    }\r
-\r
-    public void outerProcess(TALExpressionParser aParser, Object aContext,\r
-        StringBuffer aDestination, TALLogger aLogger, Map aTemplateContext,\r
-        TemplateLibrary aLibrary) throws TemplateProcessingException {\r
-\r
-      Object oldAttributes = aParser.evaluatePseudoVariable(aContext, "tagattributes");\r
-      aParser.processPseudoAssignment(aContext, "tagattributes", Collections.unmodifiableMap(fixedAttributes));\r
-\r
-      Object oldContent = aParser.evaluatePseudoVariable(aContext, "tagcontent");\r
-      aParser.processPseudoAssignment(aContext, "tagcontent", body.getPlainText());\r
-\r
-      try {\r
-        Iterator i;\r
-\r
-        i = definitions.iterator();\r
-        while (i.hasNext()) {\r
-          Definition d = (Definition) i.next();\r
-          aParser.processAssignment(aContext, d.getVariable(), d.getExpression());\r
-        }\r
-\r
-        if (condition == null || aParser.evaluateBooleanExpression(aContext, condition)) {\r
-          if (repeatExpression != null) {\r
-            i = aParser.evaluateListExpression(aContext, repeatExpression);\r
-\r
-            while (i.hasNext()) {\r
-              aParser.processDirectAssignment(aContext, repeatVariable, i.next());\r
-              innerProcess(aParser, aContext, aDestination, aLogger, aTemplateContext, aLibrary);\r
-            }\r
-          }\r
-          else {\r
-            innerProcess(aParser, aContext, aDestination, aLogger, aTemplateContext, aLibrary);\r
-          }\r
-        }\r
-      }\r
-      finally {\r
-        try {\r
-          aParser.processPseudoAssignment(aContext, "tagattributes", oldAttributes);\r
-          aParser.processPseudoAssignment(aContext, "tagcontent", oldContent);\r
-        }\r
-        catch (Throwable t) {\r
-        }\r
-      }\r
-    };\r
-\r
-    private void innerProcess(TALExpressionParser aParser, Object aContext,\r
-        StringBuffer aDestination, TALLogger aLogger, Map aTemplateContext, TemplateLibrary aLibrary)\r
-        throws TemplateProcessingException {\r
-\r
-      boolean omitTag = false;\r
-      StringBuffer content = aDestination;\r
-\r
-      if (omitTagExpression != null)\r
-        omitTag = aParser.evaluateBooleanExpression(aContext, omitTagExpression);\r
-\r
-      if (!omitTag) {\r
-        content = new StringBuffer();\r
-        Map generatedAttributes = new HashMap(fixedAttributes);\r
-\r
-        Iterator i = attributeModifiers.entrySet().iterator();\r
-        while (i.hasNext()) {\r
-          Map.Entry entry = (Map.Entry) i.next();\r
-\r
-          generatedAttributes.put(entry.getKey(), aParser.evaluateStringExpression(aContext, entry.getValue()));\r
-        }\r
-\r
-        aDestination.append("<");\r
-        aDestination.append(tag);\r
-\r
-        i = generatedAttributes.entrySet().iterator();\r
-        while (i.hasNext()) {\r
-          Map.Entry entry = (Map.Entry) i.next();\r
-          aDestination.append(" ");\r
-          aDestination.append(entry.getKey());\r
-          aDestination.append("=");\r
-          aDestination.append("\"");\r
-          aDestination.append(HTMLRoutines.encodeHTML( (String) entry.getValue()));\r
-          aDestination.append("\"");\r
-        }\r
-      }\r
-\r
-      try{\r
-        if (contentExpression != null) {\r
-          content.append(aParser.evaluateStringExpression(aContext, contentExpression));\r
-        }\r
-        else {\r
-          if (body != null) {\r
-            body.process(aParser, aContext, content, aLogger, aTemplateContext, aLibrary);\r
-          }\r
-        }\r
-        if (!omitTag) {\r
-          if (content.length()==0) {\r
-            aDestination.append(" />");\r
-          }\r
-          else {\r
-            aDestination.append(">");\r
-            aDestination.append(content);\r
-            aDestination.append("</");\r
-            aDestination.append(tag);\r
-            aDestination.append(">");\r
-          }\r
-        }\r
-      }\r
-      catch (Throwable t) {\r
-        if (!omitTag) {\r
-          aDestination.append(content);\r
-        }\r
-\r
-        if (t instanceof TemplateProcessingException) {\r
-          throw (TemplateProcessingException) t;\r
-        }\r
-        else if (t instanceof RuntimeException) {\r
-          throw (RuntimeException) t;\r
-        }\r
-        else throw new TemplateProcessingException(t.toString());\r
-      }\r
-    }\r
-  }\r
-}\r
+/*
+ * Copyright (C) 2005 The Mir-coders group
+ *
+ * This file is part of Mir.
+ *
+ * Mir is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Mir 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Mir; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * In addition, as a special exception, The Mir-coders gives permission to link
+ * the code of this program with  any library licensed under the Apache Software License.
+ * You must obey the GNU General Public License in all respects for all of the code used
+ * other than the above mentioned libraries.  If you modify this file, you may extend this
+ * exception to your version of the file, but you are not obligated to do so.
+ * If you do not wish to do so, delete this exception statement from your version.
+ */
+package mir.generator.tal.template;
+
+import mir.generator.tal.interfaces.TALExpressionParser;
+import mir.generator.tal.interfaces.TALLogger;
+import mir.util.HTMLRoutines;
+import mir.util.StringRoutines;
+import mir.util.xml.XMLName;
+import mir.util.xml.XMLParserExc;
+import mir.util.xml.XMLReaderTool;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+
+public class CoreTemplateNodeLibrary implements TemplateNodeLibrary {
+  private String prefix;
+  private String uri;
+
+  private boolean isOurTag(XMLName aName) {
+    return prefix.equals(aName.getPrefix()) || uri.equals(aName.getNamespaceURI());
+  }
+
+  public CoreTemplateNodeLibrary(String aPrefix, String aUri) {
+    prefix = aPrefix;
+    uri = aUri;
+  }
+
+  private static final String CONDITION_ATTRIBUTE = "condition";
+  private static final String REPEAT_ATTRIBUTE = "repeat";
+  private static final String CONTENT_ATTRIBUTE = "content";
+  private static final String ERROR_ATTRIBUTE = "on-error";
+  private static final String REPLACE_ATTRIBUTE = "replace";
+  private static final String DEFINITION_ATTRIBUTE = "define";
+  private static final String OMITTAG_ATTRIBUTE = "omit-tag";
+  private static final String ATTRIBUTE_ATTRIBUTE = "attributes";
+
+  public TemplateNode constructTemplateNode(TALExpressionParser aParser, XMLName aTag, Map anAttributes,
+      TemplateNode aChildTemplateNode, Map aTemplateContext) throws XMLParserExc {
+    TALBasicTemplateNode result = new TALBasicTemplateNode(XMLReaderTool.normalizeXMLName(aTag));
+    result.setBody(aChildTemplateNode);
+
+    if (isOurTag(aTag))
+      result.setOmitTag(aParser.preparseTRUE());
+
+    Iterator i = anAttributes.entrySet().iterator();
+    while (i.hasNext()) {
+      Map.Entry entry = (Map.Entry) i.next();
+      XMLName name = (XMLName) entry.getKey();
+
+      if (!isOurTag(name)) {
+        result.addFixedAttribute(XMLReaderTool.normalizeXMLName(name), (String) entry.getValue());
+      }
+      else {
+        if (name.getLocalName().equalsIgnoreCase(DEFINITION_ATTRIBUTE)) {
+          List definitions = StringRoutines.splitStringWithEscape((String) entry.getValue(), ';', '\\');
+
+          Iterator j = definitions.iterator();
+          while (j.hasNext())
+          {
+            List parts = StringRoutines.separateString((String) j.next(), " ");
+
+            if (parts.size()==2) {
+              result.addDefinition(aParser.preparseReferenceExpression((String) parts.get(0)), aParser.preparseExpression((String) parts.get(1)));
+            }
+          }
+        }
+        else if (name.getLocalName().equalsIgnoreCase(CONDITION_ATTRIBUTE)) {
+          result.setCondition(aParser.preparseBooleanExpression((String) entry.getValue()));
+        }
+        else if (name.getLocalName().equalsIgnoreCase(CONTENT_ATTRIBUTE)) {
+          result.setContent(aParser.preparseStringExpression((String) entry.getValue()));
+        }
+        else if (name.getLocalName().equalsIgnoreCase(ERROR_ATTRIBUTE)) {
+          result.setError(aParser.preparseStringExpression((String) entry.getValue()));
+        }
+        else if (name.getLocalName().equalsIgnoreCase(OMITTAG_ATTRIBUTE)) {
+          if (((String) entry.getValue()).trim().length()==0)
+            result.setOmitTag(aParser.preparseTRUE());
+          else
+            result.setOmitTag(aParser.preparseBooleanExpression((String) entry.getValue()));
+        }
+        else if (name.getLocalName().equalsIgnoreCase(REPLACE_ATTRIBUTE)) {
+          result.setOmitTag(aParser.preparseTRUE());
+          result.setContent(aParser.preparseStringExpression((String) entry.getValue()));
+        }
+        else if (name.getLocalName().equalsIgnoreCase(REPEAT_ATTRIBUTE)) {
+          List parts = StringRoutines.separateString((String) entry.getValue(), " ");
+
+          if (parts.size()==2) {
+            result.setRepeat(aParser.preparseReferenceExpression((String) parts.get(0)), aParser.preparseExpression((String) parts.get(1)));
+          }
+        }
+        else if (name.getLocalName().equalsIgnoreCase(ATTRIBUTE_ATTRIBUTE)) {
+          List attributes = StringRoutines.splitStringWithEscape((String) entry.getValue(), ';', '\\');
+
+          Iterator j = attributes.iterator();
+          while (j.hasNext()) {
+            String value = (String) j.next();
+            List parts = StringRoutines.separateString(value.trim(), " ");
+
+            if (parts.size()==2) {
+              result.addModifiedAttribute((String) parts.get(0), aParser.preparseExpression((String) parts.get(1)));
+            }
+            else {
+              throw new XMLParserExc(ATTRIBUTE_ATTRIBUTE + " tag should have exactly 2 parts ("+value+")");
+            }
+          }
+        }
+      }
+    }
+
+    return result;
+  }
+
+  public static class TALBasicTemplateNode implements TemplateNode {
+    private String tag;
+    private Map fixedAttributes;
+    private Map attributeModifiers;
+
+    private List definitions;
+    private Object condition;
+
+    private Object repeatVariable;
+    private Object repeatExpression;
+    private Object contentExpression;
+    private Object omitTagExpression;
+    private Object errorExpression;
+
+    private TemplateNode body;
+
+    public TALBasicTemplateNode(String aTag) {
+      tag = aTag;
+
+      fixedAttributes = new HashMap();
+      attributeModifiers = new HashMap();
+
+      definitions = new ArrayList();
+      condition = null;
+
+      repeatVariable = null;
+      repeatExpression = null;
+      contentExpression = null;
+      omitTagExpression = null;
+
+      body = null;
+    }
+
+    public void setBody(TemplateNode aBody) {
+      body = aBody;
+    }
+
+    public void addFixedAttribute(String aKey, String aValue) {
+      fixedAttributes.put(aKey, aValue);
+    }
+
+    public void addModifiedAttribute(String aKey, Object aValue) {
+      attributeModifiers.put(aKey, aValue);
+    }
+
+    public void addDefinition(Object aKey, Object aValue) {
+      definitions.add(new Definition(aKey, aValue));
+    }
+
+    public void setCondition(Object aCondition) {
+      condition = aCondition;
+    }
+
+    public void setRepeat(Object aRepeatVariable, Object aRepeatExpression) {
+      repeatVariable = aRepeatVariable;
+      repeatExpression = aRepeatExpression;
+    }
+
+    public void setContent(Object aContentExpression) {
+      contentExpression = aContentExpression;
+    }
+
+    public void setOmitTag(Object anOmitTagExpression) {
+      omitTagExpression = anOmitTagExpression;
+    }
+
+    public void setError(Object anErrorExpression) {
+      errorExpression = anErrorExpression;
+    }
+
+    public static class Definition {
+      private Object variable;
+      private Object expression;
+
+      public Definition(Object aVariable, Object anExpression) {
+        variable = aVariable;
+        expression = anExpression;
+      }
+
+      public Object getVariable() {
+        return variable;
+      }
+
+      public Object getExpression() {
+        return expression;
+      }
+    }
+
+    public void process(TALExpressionParser aParser, Object aContext,
+        StringBuffer aDestination, TALLogger aLogger, Map aTemplateContext,
+        TemplateLibrary aLibrary) throws TemplateProcessingException {
+      if (errorExpression != null) {
+        StringBuffer destination = new StringBuffer();
+
+        try {
+          outerProcess(aParser, aContext, destination, aLogger, aTemplateContext, aLibrary);
+        }
+        catch (Throwable t) {
+          try {
+//            destination.delete(0, destination.length());
+            aParser.processPseudoAssignment(aContext, "exception", t);
+            destination.insert(0, aParser.evaluateStringExpression(aContext, errorExpression));
+            destination.append(" >>>ERROR POSITION<<< ");
+          }
+          catch (Throwable s) {
+            throw new TemplateProcessingException(s);
+          }
+        }
+        finally {
+          aDestination.append(destination);
+        }
+      }
+      else {
+        outerProcess(aParser, aContext, aDestination, aLogger, aTemplateContext, aLibrary);
+      }
+    }
+
+    public String getPlainText() {
+      return body.getPlainText();
+    }
+
+    public void outerProcess(TALExpressionParser aParser, Object aContext,
+        StringBuffer aDestination, TALLogger aLogger, Map aTemplateContext,
+        TemplateLibrary aLibrary) throws TemplateProcessingException {
+
+      Object oldAttributes = aParser.evaluatePseudoVariable(aContext, "tagattributes");
+      aParser.processPseudoAssignment(aContext, "tagattributes", Collections.unmodifiableMap(fixedAttributes));
+
+      Object oldContent = aParser.evaluatePseudoVariable(aContext, "tagcontent");
+      aParser.processPseudoAssignment(aContext, "tagcontent", body.getPlainText());
+
+      try {
+        Iterator i;
+
+        i = definitions.iterator();
+        while (i.hasNext()) {
+          Definition d = (Definition) i.next();
+          aParser.processAssignment(aContext, d.getVariable(), d.getExpression());
+        }
+
+        if (condition == null || aParser.evaluateBooleanExpression(aContext, condition)) {
+          if (repeatExpression != null) {
+            i = aParser.evaluateListExpression(aContext, repeatExpression);
+
+            while (i.hasNext()) {
+              aParser.processDirectAssignment(aContext, repeatVariable, i.next());
+              innerProcess(aParser, aContext, aDestination, aLogger, aTemplateContext, aLibrary);
+            }
+          }
+          else {
+            innerProcess(aParser, aContext, aDestination, aLogger, aTemplateContext, aLibrary);
+          }
+        }
+      }
+      finally {
+        try {
+          aParser.processPseudoAssignment(aContext, "tagattributes", oldAttributes);
+          aParser.processPseudoAssignment(aContext, "tagcontent", oldContent);
+        }
+        catch (Throwable t) {
+        }
+      }
+    }
+
+    private void innerProcess(TALExpressionParser aParser, Object aContext,
+        StringBuffer aDestination, TALLogger aLogger, Map aTemplateContext, TemplateLibrary aLibrary)
+        throws TemplateProcessingException {
+
+      boolean omitTag = false;
+      StringBuffer content = aDestination;
+
+      if (omitTagExpression != null)
+        omitTag = aParser.evaluateBooleanExpression(aContext, omitTagExpression);
+
+      if (!omitTag) {
+        content = new StringBuffer();
+        Map generatedAttributes = new TreeMap(fixedAttributes);
+
+        Iterator i = attributeModifiers.entrySet().iterator();
+        while (i.hasNext()) {
+          Map.Entry entry = (Map.Entry) i.next();
+
+          generatedAttributes.put(entry.getKey(), aParser.evaluateStringExpression(aContext, entry.getValue()));
+        }
+
+        aDestination.append("<");
+        aDestination.append(tag);
+
+        i = generatedAttributes.entrySet().iterator();
+        while (i.hasNext()) {
+          Map.Entry entry = (Map.Entry) i.next();
+          aDestination.append(" ");
+          aDestination.append(entry.getKey());
+          aDestination.append("=");
+          aDestination.append("\"");
+          aDestination.append(HTMLRoutines.encodeHTML( (String) entry.getValue()));
+          aDestination.append("\"");
+        }
+      }
+
+      try{
+        if (contentExpression != null) {
+          content.append(aParser.evaluateStringExpression(aContext, contentExpression));
+        }
+        else {
+          if (body != null) {
+            body.process(aParser, aContext, content, aLogger, aTemplateContext, aLibrary);
+          }
+        }
+        if (!omitTag) {
+          if (content.length()==0) {
+            aDestination.append(" />");
+          }
+          else {
+            aDestination.append(">");
+            aDestination.append(content);
+            aDestination.append("</");
+            aDestination.append(tag);
+            aDestination.append(">");
+          }
+        }
+      }
+      catch (Throwable t) {
+        if (!omitTag) {
+          aDestination.append(content);
+        }
+
+        if (t instanceof TemplateProcessingException) {
+          throw (TemplateProcessingException) t;
+        }
+        else if (t instanceof RuntimeException) {
+          throw (RuntimeException) t;
+        }
+        else throw new TemplateProcessingException(t.toString());
+      }
+    }
+  }
+}