2 * Copyright (C) 2005 The Mir-coders group
4 * This file is part of Mir.
6 * Mir is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * Mir is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with Mir; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 * In addition, as a special exception, The Mir-coders gives permission to link
21 * the code of this program with any library licensed under the Apache Software License.
22 * You must obey the GNU General Public License in all respects for all of the code used
23 * other than the above mentioned libraries. If you modify this file, you may extend this
24 * exception to your version of the file, but you are not obligated to do so.
25 * If you do not wish to do so, delete this exception statement from your version.
27 package mir.generator.tal.template;
29 import java.util.HashMap;
30 import java.util.Iterator;
31 import java.util.List;
34 import mir.generator.tal.interfaces.TALExpressionParser;
35 import mir.generator.tal.interfaces.TALLogger;
36 import mir.util.HTMLRoutines;
37 import mir.util.StringRoutines;
38 import mir.util.xml.XMLName;
39 import mir.util.xml.XMLParserExc;
40 import mir.util.xml.XMLReaderTool;
42 public class MacroTemplateNodeLibrary implements TemplateNodeLibrary {
44 private static final String DEFINE_MACRO_ATTRIBUTE = "define-macro";
45 private static final String USE_MACRO_ATTRIBUTE = "use-macro";
46 private static final String DEFINE_SLOT_ATTRIBUTE = "define-slot";
47 private static final String FILL_SLOT_ATTRIBUTE = "fill-macro";
49 public static final String MACRO_DEFINITIONS_KEY = "$" + MacroTemplateNodeLibrary.class.getName() + "$macro_definitions";
50 public static final String ORPHANED_SLOTS_KEY = "$" + MacroTemplateNodeLibrary.class.getName() + "$macro_definitions";
52 private String prefix;
56 private boolean isOurTag(XMLName aName) {
57 return prefix.equals(aName.getPrefix()) || uri.equals(aName.getNamespaceURI());
60 public MacroTemplateNodeLibrary(String aPrefix, String aUri) {
65 public TemplateNode constructTemplateNode(TALExpressionParser anExpressionParser, XMLName aTag, Map anAttributes,
66 TemplateNode aChildTemplateNode, Map aTemplateContext) throws XMLParserExc {
68 StringBuffer prefix = new StringBuffer();
69 boolean useSurroundingTag = !(isOurTag(aTag));
71 prefix.append("<").append(XMLReaderTool.normalizeXMLName(aTag));
72 String suffix = "</"+XMLReaderTool.normalizeXMLName(aTag)+">";
74 String macroDefinition = null;
75 String slotDefinition = null;
76 String slotFill = null;
77 Object macroCallExpression = null;
79 Iterator i = anAttributes.entrySet().iterator();
82 Map.Entry entry = (Map.Entry) i.next();
83 XMLName name = (XMLName) entry.getKey();
85 if (!isOurTag(name)) {
86 prefix.append(" ").append(XMLReaderTool.normalizeXMLName(name));
87 prefix.append("=\"").append(HTMLRoutines.encodeHTML( (String) entry.getValue())).append('"');
90 if (name.getLocalName().equalsIgnoreCase(DEFINE_MACRO_ATTRIBUTE)) {
91 macroDefinition = (String) entry.getValue();
93 else if (name.getLocalName().equalsIgnoreCase(USE_MACRO_ATTRIBUTE)) {
94 macroCallExpression = anExpressionParser.preparseStringExpression((String) entry.getValue());
96 else if (name.getLocalName().equalsIgnoreCase(DEFINE_SLOT_ATTRIBUTE)) {
97 slotDefinition = (String) entry.getValue();
99 else if (name.getLocalName().equalsIgnoreCase(FILL_SLOT_ATTRIBUTE)) {
100 slotFill = (String) entry.getValue();
106 MacroTemplateNode result;
107 if (useSurroundingTag) {
108 result = new MacroTemplateNode(aChildTemplateNode, prefix.toString(), suffix, slotDefinition, slotFill);
111 result = new MacroTemplateNode(aChildTemplateNode, "", "", slotDefinition, slotFill);
114 if (macroCallExpression!=null) {
115 result.setMacroCall(macroCallExpression);
118 if (macroDefinition!=null) {
119 macroDefinition = macroDefinition.trim();
120 if (macroDefinition.length()==0) {
121 throw new XMLParserExc("Empty macro name");
124 Map definitions = (Map) aTemplateContext.get(MACRO_DEFINITIONS_KEY);
125 if (definitions==null) {
126 definitions=new HashMap();
127 aTemplateContext.put(MACRO_DEFINITIONS_KEY, definitions);
130 if (definitions.containsKey(macroDefinition)) {
131 throw new XMLParserExc("Duplicate macro name: " + macroDefinition);
134 definitions.put(macroDefinition, result);
136 Map slots = (Map) aTemplateContext.get(ORPHANED_SLOTS_KEY);
144 private class MacroTemplateNode implements TemplateNode {
145 private TemplateNode childNode;
146 private String prefix;
147 private String suffix;
149 private Object macroCallTemplateExpression = null;
151 private String slotDefinition;
152 private String slotFill;
154 public MacroTemplateNode(TemplateNode aChildNode, String aPrefix, String aSuffix,
155 String aSlotDefinition, String aSlotFill) {
156 childNode = aChildNode;
160 slotDefinition = aSlotDefinition;
161 slotFill = aSlotFill;
164 public void setMacroCall(Object anExpression) {
165 macroCallTemplateExpression = anExpression;
169 public void process(TALExpressionParser aParser, Object aContext, StringBuffer aDestination,
170 TALLogger aLogger, Map aTemplateContext, TemplateLibrary aLibrary) throws TemplateProcessingException {
172 if (macroCallTemplateExpression!=null) {
173 String macroPath = aParser.evaluateStringExpression(aContext, macroCallTemplateExpression);
174 List parts = StringRoutines.separateString(macroPath, "#");
175 if (parts.size()!=2) {
176 throw new TemplateProcessingException("Invalid macro path '" + macroPath + "'");
179 Template template = aLibrary.lookupTemplate((String) parts.get(0));
180 Map definitions = (Map) template.getContext().get(MACRO_DEFINITIONS_KEY);
181 if (template==null) {
182 throw new TemplateProcessingException("Cannot find template '" + (String) parts.get(0) + "'");
184 if (definitions==null || !definitions.containsKey(parts.get(1))) {
185 throw new TemplateProcessingException("No macro '"+(String) parts.get(1)+"' found in template '" + (String) parts.get(0) + "'");
188 MacroTemplateNode macro = (MacroTemplateNode) definitions.get(parts.get(1));
190 macro.process(aParser, aContext, aDestination, aLogger, aTemplateContext, aLibrary);
193 aDestination.append(prefix);
195 childNode.process(aParser, aContext, aDestination, aLogger, aTemplateContext, aLibrary);
196 aDestination.append(suffix);
200 public String getPlainText() {
201 return childNode.getPlainText();