Save This Page
Home » freemarker-2.3.13 » freemarker.template » [javadoc | source]
    1   /*
    2    * Copyright (c) 2003 The Visigoth Software Society. All rights
    3    * reserved.
    4    *
    5    * Redistribution and use in source and binary forms, with or without
    6    * modification, are permitted provided that the following conditions
    7    * are met:
    8    *
    9    * 1. Redistributions of source code must retain the above copyright
   10    *    notice, this list of conditions and the following disclaimer.
   11    *
   12    * 2. Redistributions in binary form must reproduce the above copyright
   13    *    notice, this list of conditions and the following disclaimer in
   14    *    the documentation and/or other materials provided with the
   15    *    distribution.
   16    *
   17    * 3. The end-user documentation included with the redistribution, if
   18    *    any, must include the following acknowledgement:
   19    *       "This product includes software developed by the
   20    *        Visigoth Software Society (http://www.visigoths.org/)."
   21    *    Alternately, this acknowledgement may appear in the software itself,
   22    *    if and wherever such third-party acknowledgements normally appear.
   23    *
   24    * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the
   25    *    project contributors may be used to endorse or promote products derived
   26    *    from this software without prior written permission. For written
   27    *    permission, please contact visigoths@visigoths.org.
   28    *
   29    * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth"
   30    *    nor may "FreeMarker" or "Visigoth" appear in their names
   31    *    without prior written permission of the Visigoth Software Society.
   32    *
   33    * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   34    * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   35    * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   36    * DISCLAIMED.  IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR
   37    * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   38    * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   39    * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   40    * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   41    * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   42    * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   43    * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   44    * SUCH DAMAGE.
   45    * ====================================================================
   46    *
   47    * This software consists of voluntary contributions made by many
   48    * individuals on behalf of the Visigoth Software Society. For more
   49    * information on the Visigoth Software Society, please see
   50    * http://www.visigoths.org/
   51    */
   52   
   53   package freemarker.template;
   54   
   55   import java.io;
   56   import java.util;
   57   import javax.swing.tree.TreePath;
   58   import freemarker.core;
   59   
   60   import freemarker.debug.impl.DebuggerService;
   61   
   62   /**
   63    * <p>A core FreeMarker API that represents a compiled template.
   64    * Typically, you will use a {@link Configuration} object to instantiate a template.
   65    *
   66    * <PRE>
   67         Configuration cfg = new Configuration();
   68         ...
   69         Template myTemplate = cfg.getTemplate("myTemplate.html");
   70      </PRE>
   71    *
   72    * <P>However, you can also construct a template directly by passing in to
   73    * the appropriate constructor a java.io.Reader instance that is set to
   74    * read the raw template text. The compiled template is
   75    * stored in an an efficient data structure for later use.
   76    *
   77    * <p>To render the template, i.e. to merge it with a data model, and
   78    * thus produce "cooked" output, call the <tt>process</tt> method.
   79    *
   80    * <p>Any error messages from exceptions thrown during compilation will be
   81    * included in the output stream and thrown back to the calling code.
   82    * To change this behavior, you can install custom exception handlers using
   83    * {@link Configurable#setTemplateExceptionHandler(TemplateExceptionHandler)} on
   84    * a Configuration object (for all templates belonging to a configuration) or on
   85    * a Template object (for a single template).
   86    * 
   87    * <p>It's not legal to modify the values of FreeMarker settings: a) while the
   88    * template is executing; b) if the template object is already accessible from
   89    * multiple threads.
   90    * 
   91    * @version $Id: Template.java,v 1.216.2.3 2006/03/10 17:49:02 revusky Exp $
   92    */
   93   
   94   public class Template extends Configurable {
   95       public static final String DEFAULT_NAMESPACE_PREFIX = "D";
   96       public static final String NO_NS_PREFIX = "N";
   97   
   98       private Map macros = new HashMap();
   99       private List imports = new Vector();
  100       private TemplateElement rootElement;
  101       private String encoding, defaultNS;
  102       private final String name;
  103       private final ArrayList lines = new ArrayList();
  104       private Map prefixToNamespaceURILookup = new HashMap();
  105       private Map namespaceURIToPrefixLookup = new HashMap();
  106   
  107       /**
  108        * A prime constructor to which all other constructors should
  109        * delegate directly or indirectly.
  110        */
  111       private Template(String name, Configuration cfg)
  112       {
  113           super(cfg != null ? cfg : Configuration.getDefaultConfiguration());
  114           this.name = name;
  115       }
  116   
  117       /**
  118        * Constructs a template from a character stream.
  119        *
  120        * @param name the path of the template file relative to the directory what you use to store
  121        *        the templates. See {@link #getName} for more details.
  122        * @param reader the character stream to read from. It will always be closed (Reader.close()).
  123        * @param cfg the Configuration object that this Template is associated with.
  124        *        If this is null, the "default" {@link Configuration} object is used,
  125        *        which is highly discouraged, because it can easily lead to
  126        *        erroneous, unpredictable behaviour.
  127        *        (See more {@link Configuration#getDefaultConfiguration() here...})
  128        * @param encoding This is the encoding that we are supposed to be using. If this is
  129        * non-null (It's not actually necessary because we are using a Reader) then it is
  130        * checked against the encoding specified in the FTL header -- assuming that is specified,
  131        * and if they don't match a WrongEncodingException is thrown.
  132        */
  133       public Template(String name, Reader reader, Configuration cfg, String encoding)
  134       throws IOException
  135       {
  136           this(name, cfg);
  137           this.encoding = encoding;
  138   
  139           if (!(reader instanceof BufferedReader)) {
  140               reader = new BufferedReader(reader, 0x1000);
  141           }
  142           LineTableBuilder ltb = new LineTableBuilder(reader);
  143           try {
  144               try {
  145                   FMParser parser = new FMParser(this, ltb,
  146                           getConfiguration().getStrictSyntaxMode(),
  147                           getConfiguration().getWhitespaceStripping(),
  148                           getConfiguration().getTagSyntax());
  149                   this.rootElement = parser.Root();
  150               }
  151               catch (TokenMgrError exc) {
  152                   throw new ParseException("Token manager error: " + exc, 0, 0);
  153               }
  154           }
  155           catch(ParseException e) {
  156               e.setTemplateName(name);
  157               throw e;
  158           }
  159           finally {
  160               ltb.close();
  161           }
  162           DebuggerService.registerTemplate(this);
  163           namespaceURIToPrefixLookup = Collections.unmodifiableMap(namespaceURIToPrefixLookup);
  164           prefixToNamespaceURILookup = Collections.unmodifiableMap(prefixToNamespaceURILookup);
  165       }
  166   
  167       /**
  168        * This is equivalent to Template(name, reader, cfg, null)
  169        */
  170   
  171       public Template(String name, Reader reader, Configuration cfg) throws IOException {
  172           this(name, reader, cfg, null);
  173       }
  174   
  175   
  176       /**
  177        * Constructs a template from a character stream.
  178        *
  179        * This is the same as the 3 parameter version when you pass null
  180        * as the cfg parameter.
  181        * 
  182        * @deprecated This constructor uses the "default" {@link Configuration}
  183        * instance, which can easily lead to erroneous, unpredictable behaviour.
  184        * See more {@link Configuration#getDefaultConfiguration() here...}.
  185        */
  186       public Template(String name, Reader reader) throws IOException {
  187           this(name, reader, null);
  188       }
  189   
  190       /**
  191        * This constructor is only used internally.
  192        */
  193       Template(String name, TemplateElement root, Configuration config) {
  194           this(name, config);
  195           this.rootElement = root;
  196           DebuggerService.registerTemplate(this);
  197       }
  198   
  199       /**
  200        * Returns a trivial template, one that is just a single block of
  201        * plain text, no dynamic content. (Used by the cache module to create
  202        * unparsed templates.)
  203        * @param name the path of the template file relative to the directory what you use to store
  204        *        the templates. See {@link #getName} for more details.
  205        * @param content the block of text that this template represents
  206        * @param config the configuration to which this template belongs
  207        */
  208       static public Template getPlainTextTemplate(String name, String content, Configuration config) {
  209           Template template = new Template(name, config);
  210           TextBlock block = new TextBlock(content);
  211           template.rootElement = block;
  212           DebuggerService.registerTemplate(template);
  213           return template;
  214       }
  215   
  216       /**
  217        * Processes the template, using data from the map, and outputs
  218        * the resulting text to the supplied <tt>Writer</tt> The elements of the
  219        * map are converted to template models using the default object wrapper
  220        * returned by the {@link Configuration#getObjectWrapper() getObjectWrapper()}
  221        * method of the <tt>Configuration</tt>.
  222        * @param rootMap the root node of the data model.  If null, an
  223        * empty data model is used. Can be any object that the effective object
  224        * wrapper can turn into a <tt>TemplateHashModel</tt>. Basically, simple and
  225        * beans wrapper can turn <tt>java.util.Map</tt> objects into hashes
  226        * and the Jython wrapper can turn both a <tt>PyDictionary</tt> as well as
  227        * any object that implements <tt>__getitem__</tt> into a template hash.
  228        * Naturally, you can pass any object directly implementing
  229        * <tt>TemplateHashModel</tt> as well.
  230        * @param out a <tt>Writer</tt> to output the text to.
  231        * @throws TemplateException if an exception occurs during template processing
  232        * @throws IOException if an I/O exception occurs during writing to the writer.
  233        */
  234       public void process(Object rootMap, Writer out)
  235       throws TemplateException, IOException
  236       {
  237           createProcessingEnvironment(rootMap, out, null).process();
  238       }
  239   
  240       /**
  241        * Processes the template, using data from the root map object, and outputs
  242        * the resulting text to the supplied writer, using the supplied
  243        * object wrapper to convert map elements to template models.
  244        * @param rootMap the root node of the data model.  If null, an
  245        * empty data model is used. Can be any object that the effective object
  246        * wrapper can turn into a <tt>TemplateHashModel</tt> Basically, simple and
  247        * beans wrapper can turn <tt>java.util.Map</tt> objects into hashes
  248        * and the Jython wrapper can turn both a <tt>PyDictionary</tt> as well as any
  249        * object that implements <tt>__getitem__</tt> into a template hash.
  250        * Naturally, you can pass any object directly implementing
  251        * <tt>TemplateHashModel</tt> as well.
  252        * @param wrapper The object wrapper to use to wrap objects into
  253        * {@link TemplateModel} instances. If null, the default wrapper retrieved
  254        * by {@link Configurable#getObjectWrapper()} is used.
  255        * @param out the writer to output the text to.
  256        * @param rootNode The root node for recursive processing, this may be null.
  257        * 
  258        * @throws TemplateException if an exception occurs during template processing
  259        * @throws IOException if an I/O exception occurs during writing to the writer.
  260        */
  261       public void process(Object rootMap, Writer out, ObjectWrapper wrapper, TemplateNodeModel rootNode)
  262       throws TemplateException, IOException
  263       {
  264           Environment env = createProcessingEnvironment(rootMap, out, wrapper);
  265           if (rootNode != null) {
  266               env.setCurrentVisitorNode(rootNode);
  267           }
  268           env.process();
  269       }
  270       
  271       /**
  272        * Processes the template, using data from the root map object, and outputs
  273        * the resulting text to the supplied writer, using the supplied
  274        * object wrapper to convert map elements to template models.
  275        * @param rootMap the root node of the data model.  If null, an
  276        * empty data model is used. Can be any object that the effective object
  277        * wrapper can turn into a <tt>TemplateHashModel</tt> Basically, simple and
  278        * beans wrapper can turn <tt>java.util.Map</tt> objects into hashes
  279        * and the Jython wrapper can turn both a <tt>PyDictionary</tt> as well as any
  280        * object that implements <tt>__getitem__</tt> into a template hash.
  281        * Naturally, you can pass any object directly implementing
  282        * <tt>TemplateHashModel</tt> as well.
  283        * @param wrapper The object wrapper to use to wrap objects into
  284        * {@link TemplateModel} instances. If null, the default wrapper retrieved
  285        * by {@link Configurable#getObjectWrapper()} is used.
  286        * @param out the writer to output the text to.
  287        * 
  288        * @throws TemplateException if an exception occurs during template processing
  289        * @throws IOException if an I/O exception occurs during writing to the writer.
  290        */
  291       public void process(Object rootMap, Writer out, ObjectWrapper wrapper)
  292       throws TemplateException, IOException
  293       {
  294           process(rootMap, out, wrapper, null);
  295       }
  296       
  297      /**
  298       * Creates a {@link freemarker.core.Environment Environment} object,
  299       * using this template, the data model provided as the root map object, and
  300       * the supplied object wrapper to convert map elements to template models.
  301       * You can then call Environment.process() on the returned environment
  302       * to set off the actual rendering.
  303       * Use this method if you want to do some special initialization on the environment
  304       * before template processing, or if you want to read the environment after template
  305       * processing.
  306       *
  307       * <p>Example:
  308       *
  309       * <p>This:
  310       * <pre>
  311       * Environment env = myTemplate.createProcessingEnvironment(root, out, null);
  312       * env.process();
  313       * </pre>
  314       * is equivalent with this:
  315       * <pre>
  316       * myTemplate.process(root, out);
  317       * </pre>
  318       * But with <tt>createProcessingEnvironment</tt>, you can manipulate the environment
  319       * before and after the processing:
  320       * <pre>
  321       * Environment env = myTemplate.createProcessingEnvironment(root, out);
  322       * env.include("include/common.ftl", null, true);  // before processing
  323       * env.process();
  324       * TemplateModel x = env.getVariable("x");  // after processing
  325       * </pre>
  326       *
  327       * @param rootMap the root node of the data model.  If null, an
  328       * empty data model is used. Can be any object that the effective object
  329       * wrapper can turn into a <tt>TemplateHashModel</tt> Basically, simple and
  330       * beans wrapper can turn <tt>java.util.Map</tt> objects into hashes
  331       * and the Jython wrapper can turn both a <tt>PyDictionary</tt> as well as any
  332       * object that implements <tt>__getitem__</tt> into a template hash.
  333       * Naturally, you can pass any object directly implementing
  334       * <tt>TemplateHashModel</tt> as well.
  335       * @param wrapper The object wrapper to use to wrap objects into
  336       * {@link TemplateModel} instances. If null, the default wrapper retrieved
  337       * by {@link Configurable#getObjectWrapper()} is used.
  338       * @param out the writer to output the text to.
  339       * @return the {@link freemarker.core.Environment Environment} object created for processing
  340       * @throws TemplateException if an exception occurs while setting up the Environment object.
  341       * @throws IOException if an exception occurs doing any auto-imports
  342       */
  343       public Environment createProcessingEnvironment(Object rootMap, Writer out, ObjectWrapper wrapper)
  344       throws TemplateException, IOException
  345       {
  346           TemplateHashModel root = null;
  347           if(rootMap instanceof TemplateHashModel) {
  348               root = (TemplateHashModel)rootMap;
  349           }
  350           else {
  351               if(wrapper == null) {
  352                   wrapper = getObjectWrapper();
  353               }
  354   
  355               try {
  356                   root = rootMap != null
  357                       ? (TemplateHashModel)wrapper.wrap(rootMap)
  358                       : new SimpleHash(wrapper);
  359                   if(root == null) {
  360                       throw new IllegalArgumentException(wrapper.getClass().getName() + " converted " + rootMap.getClass().getName() + " to null.");
  361                   }
  362               }
  363               catch(ClassCastException e) {
  364                   throw new IllegalArgumentException(wrapper.getClass().getName() + " could not convert " + rootMap.getClass().getName() + " to a TemplateHashModel.");
  365               }
  366           }
  367           Environment env = new Environment(this, root, out);
  368           getConfiguration().doAutoImports(env);
  369           getConfiguration().doAutoIncludes(env);
  370           return env;
  371       }
  372   
  373       /**
  374        * Same as <code>createProcessingEnvironment(rootMap, out, null)</code>.
  375        * @see #createProcessingEnvironment(Object rootMap, Writer out, ObjectWrapper wrapper)
  376        */
  377       public Environment createProcessingEnvironment(Object rootMap, Writer out)
  378       throws TemplateException, IOException
  379       {
  380           return createProcessingEnvironment(rootMap, out, null);
  381       }
  382       
  383       /**
  384        * Returns a string representing the raw template
  385        * text in canonical form.
  386        */
  387       public String toString() {
  388           StringWriter sw = new StringWriter();
  389           try {
  390               dump(sw);
  391           } catch (IOException ioe) {
  392               throw new RuntimeException(ioe.getMessage());
  393           }
  394           return sw.toString();
  395       }
  396   
  397   
  398       /**
  399        * The path of the template file relative to the directory what you use to store the templates.
  400        * For example, if the real path of template is <tt>"/www/templates/community/forum.fm"</tt>,
  401        * and you use "<tt>"/www/templates"</tt> as
  402        * {@link Configuration#setDirectoryForTemplateLoading "directoryForTemplateLoading"},
  403        * then <tt>name</tt> should be <tt>"community/forum.fm"</tt>. The <tt>name</tt> is used for example when you
  404        * use <tt>&lt;include ...></tt> and you give a path that is relative to the current
  405        * template, or in error messages when FreeMarker logs an error while it processes the template.
  406        */
  407       public String getName() {
  408           return name;
  409       }
  410   
  411       /**
  412        * Returns the Configuration object associated with this template.
  413        */
  414       public Configuration getConfiguration() {
  415           return (Configuration) getParent();
  416       }
  417   
  418       /**
  419        * Sets the character encoding to use for
  420        * included files. Usually you don't set this value manually,
  421        * instead it is assigned to the template upon loading.
  422        */
  423   
  424       public void setEncoding(String encoding) {
  425           this.encoding = encoding;
  426       }
  427   
  428       /**
  429        * Returns the character encoding used for reading included files.
  430        */
  431       public String getEncoding() {
  432           return this.encoding;
  433       }
  434   
  435       /**
  436        * Dump the raw template in canonical form.
  437        */
  438       public void dump(PrintStream ps) {
  439           ps.print(rootElement.getCanonicalForm());
  440       }
  441   
  442       /**
  443        * Dump the raw template in canonical form.
  444        */
  445       public void dump(Writer out) throws IOException {
  446           out.write(rootElement.getCanonicalForm());
  447       }
  448   
  449       /**
  450        * Called by code internally to maintain
  451        * a table of macros
  452        */
  453       public void addMacro(Macro macro) {
  454           macros.put(macro.getName(), macro);
  455       }
  456   
  457       /**
  458        * Called by code internally to maintain
  459        * a list of imports
  460        */
  461       public void addImport(LibraryLoad ll) {
  462           imports.add(ll);
  463       }
  464   
  465       /**
  466        * Returns the template source at the location
  467        * specified by the coordinates given.
  468        * @param beginColumn the first column of the requested source, 1-based
  469        * @param beginLine the first line of the requested source, 1-based
  470        * @param endColumn the last column of the requested source, 1-based
  471        * @param endLine the last line of the requested source, 1-based
  472        * @see freemarker.core.TemplateObject#getSource()
  473        */
  474       public String getSource(int beginColumn,
  475                               int beginLine,
  476                               int endColumn,
  477                               int endLine)
  478       {
  479           // Our container is zero-based.
  480           --beginLine;
  481           --beginColumn;
  482           --endColumn;
  483           --endLine;
  484           StringBuffer buf = new StringBuffer();
  485           for (int i = beginLine ; i<=endLine; i++) {
  486               if (i < lines.size()) {
  487                   buf.append(lines.get(i));
  488               }
  489           }
  490           int lastLineLength = lines.get(endLine).toString().length();
  491           int trailingCharsToDelete = lastLineLength - endColumn -1;
  492           buf.delete(0, beginColumn);
  493           buf.delete(buf.length() - trailingCharsToDelete, buf.length());
  494           return buf.toString();
  495       }
  496   
  497       /**
  498        * This is a helper class that builds up the line table
  499        * info for us.
  500        */
  501       private class LineTableBuilder extends FilterReader {
  502   
  503           StringBuffer lineBuf = new StringBuffer();
  504           int lastChar;
  505   
  506           /**
  507            * @param r the character stream to wrap
  508            */
  509           LineTableBuilder(Reader r) {
  510               super(r);
  511           }
  512   
  513           public int read() throws IOException {
  514               int c = in.read();
  515               handleChar(c);
  516               return c;
  517           }
  518   
  519           public int read(char cbuf[], int off, int len) throws IOException {
  520               int numchars = in.read(cbuf, off, len);
  521               for (int i=off; i < off+numchars; i++) {
  522                   char c = cbuf[i];
  523                   handleChar(c);
  524               }
  525               return numchars;
  526           }
  527   
  528           public void close() throws IOException {
  529               if (lineBuf.length() >0) {
  530                   lines.add(lineBuf.toString());
  531                   lineBuf.setLength(0);
  532               }
  533               super.close();
  534           }
  535   
  536           private void handleChar(int c) {
  537               if (c == '\n' || c == '\r') {
  538                   if (lastChar == '\r' && c == '\n') { // CRLF under Windoze
  539                       int lastIndex = lines.size() -1;
  540                       String lastLine = (String) lines.get(lastIndex);
  541                       lines.set(lastIndex, lastLine + '\n');
  542                   } else {
  543                       lineBuf.append((char) c);
  544                       lines.add(lineBuf.toString());
  545                       lineBuf.setLength(0);
  546                   }
  547               }
  548               else if (c == '\t') {
  549                   int numSpaces = 8 - (lineBuf.length() %8);
  550                   for (int i=0; i<numSpaces; i++) {
  551                       lineBuf.append(' ');
  552                   }
  553               }
  554               else {
  555                   lineBuf.append((char) c);
  556               }
  557               lastChar = c;
  558           }
  559       }
  560   
  561       /**
  562        *  @return the root TemplateElement object.
  563        */
  564       public TemplateElement getRootTreeNode() {
  565           return rootElement;
  566       }
  567       
  568       public Map getMacros() {
  569           return macros;
  570       }
  571   
  572       public List getImports() {
  573           return imports;
  574       }
  575   
  576       /**
  577        * This is used internally.
  578        */
  579       public void addPrefixNSMapping(String prefix, String nsURI) {
  580           if (nsURI.length() == 0) {
  581               throw new IllegalArgumentException("Cannot map empty string URI");
  582           }
  583           if (prefix.length() == 0) {
  584               throw new IllegalArgumentException("Cannot map empty string prefix");
  585           }
  586           if (prefix.equals(NO_NS_PREFIX)) {
  587               throw new IllegalArgumentException("The prefix: " + prefix + " cannot be registered, it is reserved for special internal use.");
  588           }
  589           if (prefixToNamespaceURILookup.containsKey(prefix)) {
  590               throw new IllegalArgumentException("The prefix: '" + prefix + "' was repeated. This is illegal.");
  591           }
  592           if (namespaceURIToPrefixLookup.containsKey(nsURI)) {
  593               throw new IllegalArgumentException("The namespace URI: " + nsURI + " cannot be mapped to 2 different prefixes.");
  594           }
  595           if (prefix.equals(DEFAULT_NAMESPACE_PREFIX)) {
  596               this.defaultNS = nsURI;
  597           } else {
  598               prefixToNamespaceURILookup.put(prefix, nsURI);
  599               namespaceURIToPrefixLookup.put(nsURI, prefix);
  600           }
  601       }
  602       
  603       public String getDefaultNS() {
  604           return this.defaultNS;
  605       }
  606       
  607       /**
  608        * @return the NamespaceUri mapped to this prefix in this template. (Or null if there is none.)
  609        */
  610       public String getNamespaceForPrefix(String prefix) {
  611           if (prefix.equals("")) {
  612               return defaultNS == null ? "" : defaultNS;
  613           }
  614           return (String) prefixToNamespaceURILookup.get(prefix);
  615       }
  616       
  617       /**
  618        * @return the prefix mapped to this nsURI in this template. (Or null if there is none.)
  619        */
  620       public String getPrefixForNamespace(String nsURI) {
  621           if (nsURI == null) {
  622               return null;
  623           }
  624           if (nsURI.length() == 0) {
  625               return defaultNS == null ? "" : NO_NS_PREFIX;
  626           }
  627           if (nsURI.equals(defaultNS)) {
  628               return "";
  629           }
  630           return (String) namespaceURIToPrefixLookup.get(nsURI);
  631       }
  632       
  633       /**
  634        * @return the prefixed name, based on the ns_prefixes defined
  635        * in this template's header for the local name and node namespace
  636        * passed in as parameters.
  637        */
  638       public String getPrefixedName(String localName, String nsURI) {
  639           if (nsURI == null || nsURI.length() == 0) {
  640               if (defaultNS != null) {
  641                   return NO_NS_PREFIX + ":" + localName;
  642               } else {
  643                   return localName;
  644               }
  645           } 
  646           if (nsURI.equals(defaultNS)) {
  647               return localName;
  648           } 
  649           String prefix = getPrefixForNamespace(nsURI);
  650           if (prefix == null) {
  651               return null;
  652           }
  653           return prefix + ":" + localName;
  654       }
  655       
  656       /**
  657        * @return an array of the elements containing the given column and line numbers.
  658        * @param column the column
  659        * @param line the line
  660        */
  661       public TreePath containingElements(int column, int line) {
  662           ArrayList elements = new ArrayList();
  663           TemplateElement element = rootElement;
  664   mainloop:
  665           while (element.contains(column, line)) {
  666               elements.add(element);
  667               for (Enumeration enumeration = element.children(); enumeration.hasMoreElements();) {
  668                   TemplateElement elem = (TemplateElement) enumeration.nextElement();
  669                   if (elem.contains(column, line)) {
  670                       element = elem;
  671                       continue mainloop;
  672                   }
  673               }
  674               break;
  675           }
  676           if (elements == null || elements.isEmpty()) {
  677               return null;
  678           }
  679           return new TreePath(elements.toArray());
  680       }
  681   
  682       static public class WrongEncodingException extends ParseException {
  683   
  684           public String specifiedEncoding;
  685   
  686           public WrongEncodingException(String specifiedEncoding) {
  687               this.specifiedEncoding = specifiedEncoding;
  688           }
  689   
  690       }
  691   }
  692   

Save This Page
Home » freemarker-2.3.13 » freemarker.template » [javadoc | source]