KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > freemarker > template > Template


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 JavaDoc;
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 2005/06/16 18:13:58 ddekany Exp $
92  */

93
94 public class Template extends Configurable {
95     public static final String JavaDoc DEFAULT_NAMESPACE_PREFIX = "D";
96     public static final String JavaDoc NO_NS_PREFIX = "N";
97
98     private Map macros = new HashMap();
99     private List imports = new Vector();
100     private TemplateElement rootElement;
101     private String JavaDoc encoding, defaultNS;
102     private final String JavaDoc 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 JavaDoc 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 JavaDoc name, Reader reader, Configuration cfg, String JavaDoc 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             FMParser parser = new FMParser(this,
145                                            ltb,
146                                            getConfiguration().getStrictSyntaxMode(),
147                                            getConfiguration().getWhitespaceStripping());
148             this.rootElement = parser.Root();
149         }
150         catch (TokenMgrError exc) {
151             throw new ParseException("Token manager error: " + exc, 0, 0);
152         }
153         finally {
154             ltb.close();
155         }
156         DebuggerService.registerTemplate(this);
157         namespaceURIToPrefixLookup = Collections.unmodifiableMap(namespaceURIToPrefixLookup);
158         prefixToNamespaceURILookup = Collections.unmodifiableMap(prefixToNamespaceURILookup);
159     }
160
161     /**
162      * This is equivalent to Template(name, reader, cfg, null)
163      */

164
165     public Template(String JavaDoc name, Reader reader, Configuration cfg) throws IOException {
166         this(name, reader, cfg, null);
167     }
168
169
170     /**
171      * Constructs a template from a character stream.
172      *
173      * This is the same as the 3 parameter version when you pass null
174      * as the cfg parameter.
175      *
176      * @deprecated This constructor uses the "default" {@link Configuration}
177      * instance, which can easily lead to erroneous, unpredictable behaviour.
178      * See more {@link Configuration#getDefaultConfiguration() here...}.
179      */

180     public Template(String JavaDoc name, Reader reader) throws IOException {
181         this(name, reader, null);
182     }
183
184     /**
185      * This constructor is only used internally.
186      */

187     Template(String JavaDoc name, TemplateElement root, Configuration config) {
188         this(name, config);
189         this.rootElement = root;
190         DebuggerService.registerTemplate(this);
191     }
192
193     /**
194      * Returns a trivial template, one that is just a single block of
195      * plain text, no dynamic content. (Used by the cache module to create
196      * unparsed templates.)
197      * @param name the path of the template file relative to the directory what you use to store
198      * the templates. See {@link #getName} for more details.
199      * @param content the block of text that this template represents
200      * @param config the configuration to which this template belongs
201      */

202     static public Template getPlainTextTemplate(String JavaDoc name, String JavaDoc content, Configuration config) {
203         Template template = new Template(name, config);
204         TextBlock block = new TextBlock(content);
205         template.rootElement = block;
206         DebuggerService.registerTemplate(template);
207         return template;
208     }
209
210     /**
211      * Processes the template, using data from the map, and outputs
212      * the resulting text to the supplied <tt>Writer</tt> The elements of the
213      * map are converted to template models using the default object wrapper
214      * returned by the {@link Configuration#getObjectWrapper() getObjectWrapper()}
215      * method of the <tt>Configuration</tt>.
216      * @param rootMap the root node of the data model. If null, an
217      * empty data model is used. Can be any object that the effective object
218      * wrapper can turn into a <tt>TemplateHashModel</tt>. Basically, simple and
219      * beans wrapper can turn <tt>java.util.Map</tt> objects into hashes
220      * and the Jython wrapper can turn both a <tt>PyDictionary</tt> as well as
221      * any object that implements <tt>__getitem__</tt> into a template hash.
222      * Naturally, you can pass any object directly implementing
223      * <tt>TemplateHashModel</tt> as well.
224      * @param out a <tt>Writer</tt> to output the text to.
225      * @throws TemplateException if an exception occurs during template processing
226      * @throws IOException if an I/O exception occurs during writing to the writer.
227      */

228     public void process(Object JavaDoc rootMap, Writer out)
229     throws TemplateException, IOException
230     {
231         createProcessingEnvironment(rootMap, out, null).process();
232     }
233
234     /**
235      * Processes the template, using data from the root map object, and outputs
236      * the resulting text to the supplied writer, using the supplied
237      * object wrapper to convert map elements to template models.
238      * @param rootMap the root node of the data model. If null, an
239      * empty data model is used. Can be any object that the effective object
240      * wrapper can turn into a <tt>TemplateHashModel</tt> Basically, simple and
241      * beans wrapper can turn <tt>java.util.Map</tt> objects into hashes
242      * and the Jython wrapper can turn both a <tt>PyDictionary</tt> as well as any
243      * object that implements <tt>__getitem__</tt> into a template hash.
244      * Naturally, you can pass any object directly implementing
245      * <tt>TemplateHashModel</tt> as well.
246      * @param wrapper The object wrapper to use to wrap objects into
247      * {@link TemplateModel} instances. If null, the default wrapper retrieved
248      * by {@link Configurable#getObjectWrapper()} is used.
249      * @param out the writer to output the text to.
250      * @param rootNode The root node for recursive processing, this may be null.
251      *
252      * @throws TemplateException if an exception occurs during template processing
253      * @throws IOException if an I/O exception occurs during writing to the writer.
254      */

255     public void process(Object JavaDoc rootMap, Writer out, ObjectWrapper wrapper, TemplateNodeModel rootNode)
256     throws TemplateException, IOException
257     {
258         Environment env = createProcessingEnvironment(rootMap, out, wrapper);
259         if (rootNode != null) {
260             env.setCurrentVisitorNode(rootNode);
261         }
262         env.process();
263     }
264     
265     /**
266      * Processes the template, using data from the root map object, and outputs
267      * the resulting text to the supplied writer, using the supplied
268      * object wrapper to convert map elements to template models.
269      * @param rootMap the root node of the data model. If null, an
270      * empty data model is used. Can be any object that the effective object
271      * wrapper can turn into a <tt>TemplateHashModel</tt> Basically, simple and
272      * beans wrapper can turn <tt>java.util.Map</tt> objects into hashes
273      * and the Jython wrapper can turn both a <tt>PyDictionary</tt> as well as any
274      * object that implements <tt>__getitem__</tt> into a template hash.
275      * Naturally, you can pass any object directly implementing
276      * <tt>TemplateHashModel</tt> as well.
277      * @param wrapper The object wrapper to use to wrap objects into
278      * {@link TemplateModel} instances. If null, the default wrapper retrieved
279      * by {@link Configurable#getObjectWrapper()} is used.
280      * @param out the writer to output the text to.
281      *
282      * @throws TemplateException if an exception occurs during template processing
283      * @throws IOException if an I/O exception occurs during writing to the writer.
284      */

285     public void process(Object JavaDoc rootMap, Writer out, ObjectWrapper wrapper)
286     throws TemplateException, IOException
287     {
288         process(rootMap, out, wrapper, null);
289     }
290     
291    /**
292     * Creates a {@link freemarker.core.Environment Environment} object,
293     * using this template, the data model provided as the root map object, and
294     * the supplied object wrapper to convert map elements to template models.
295     * You can then call Environment.process() on the returned environment
296     * to set off the actual rendering.
297     * Use this method if you want to do some special initialization on the environment
298     * before template processing, or if you want to read the environment after template
299     * processing.
300     *
301     * <p>Example:
302     *
303     * <p>This:
304     * <pre>
305     * Environment env = myTemplate.createProcessingEnvironment(root, out, null);
306     * env.process();
307     * </pre>
308     * is equivalent with this:
309     * <pre>
310     * myTemplate.process(root, out);
311     * </pre>
312     * But with <tt>createProcessingEnvironment</tt>, you can manipulate the environment
313     * before and after the processing:
314     * <pre>
315     * Environment env = myTemplate.createProcessingEnvironment(root, out);
316     * env.include("include/common.ftl", null, true); // before processing
317     * env.process();
318     * TemplateModel x = env.getVariable("x"); // after processing
319     * </pre>
320     *
321     * @param rootMap the root node of the data model. If null, an
322     * empty data model is used. Can be any object that the effective object
323     * wrapper can turn into a <tt>TemplateHashModel</tt> Basically, simple and
324     * beans wrapper can turn <tt>java.util.Map</tt> objects into hashes
325     * and the Jython wrapper can turn both a <tt>PyDictionary</tt> as well as any
326     * object that implements <tt>__getitem__</tt> into a template hash.
327     * Naturally, you can pass any object directly implementing
328     * <tt>TemplateHashModel</tt> as well.
329     * @param wrapper The object wrapper to use to wrap objects into
330     * {@link TemplateModel} instances. If null, the default wrapper retrieved
331     * by {@link Configurable#getObjectWrapper()} is used.
332     * @param out the writer to output the text to.
333     * @return the {@link freemarker.core.Environment Environment} object created for processing
334     * @throws TemplateException if an exception occurs while setting up the Environment object.
335     * @throws IOException if an exception occurs doing any auto-imports
336     */

337     public Environment createProcessingEnvironment(Object JavaDoc rootMap, Writer out, ObjectWrapper wrapper)
338     throws TemplateException, IOException
339     {
340         TemplateHashModel root = null;
341         if(rootMap instanceof TemplateHashModel) {
342             root = (TemplateHashModel)rootMap;
343         }
344         else {
345             if(wrapper == null) {
346                 wrapper = getObjectWrapper();
347             }
348
349             try {
350                 root = rootMap != null
351                     ? (TemplateHashModel)wrapper.wrap(rootMap)
352                     : new SimpleHash(wrapper);
353                 if(root == null) {
354                     throw new IllegalArgumentException JavaDoc(wrapper.getClass().getName() + " converted " + rootMap.getClass().getName() + " to null.");
355                 }
356             }
357             catch(ClassCastException JavaDoc e) {
358                 throw new IllegalArgumentException JavaDoc(wrapper.getClass().getName() + " could not convert " + rootMap.getClass().getName() + " to a TemplateHashModel.");
359             }
360         }
361         Environment env = new Environment(this, root, out);
362         getConfiguration().doAutoImports(env);
363         getConfiguration().doAutoIncludes(env);
364         return env;
365     }
366
367     /**
368      * Same as <code>createProcessingEnvironment(rootMap, out, null)</code>.
369      * @see #createProcessingEnvironment(Object rootMap, Writer out, ObjectWrapper wrapper)
370      */

371     public Environment createProcessingEnvironment(Object JavaDoc rootMap, Writer out)
372     throws TemplateException, IOException
373     {
374         return createProcessingEnvironment(rootMap, out, null);
375     }
376     
377     /**
378      * Returns a string representing the raw template
379      * text in canonical form.
380      */

381     public String JavaDoc toString() {
382         StringWriter sw = new StringWriter();
383         try {
384             dump(sw);
385         } catch (IOException ioe) {
386             throw new RuntimeException JavaDoc(ioe.getMessage());
387         }
388         return sw.toString();
389     }
390
391
392     /**
393      * The path of the template file relative to the directory what you use to store the templates.
394      * For example, if the real path of template is <tt>"/www/templates/community/forum.fm"</tt>,
395      * and you use "<tt>"/www/templates"</tt> as
396      * {@link Configuration#setDirectoryForTemplateLoading "directoryForTemplateLoading"},
397      * then <tt>name</tt> should be <tt>"community/forum.fm"</tt>. The <tt>name</tt> is used for example when you
398      * use <tt>&lt;include ...></tt> and you give a path that is relative to the current
399      * template, or in error messages when FreeMarker logs an error while it processes the template.
400      */

401     public String JavaDoc getName() {
402         return name;
403     }
404
405     /**
406      * Returns the Configuration object associated with this template.
407      */

408     public Configuration getConfiguration() {
409         return (Configuration) getParent();
410     }
411
412     /**
413      * Sets the character encoding to use for
414      * included files. Usually you don't set this value manually,
415      * instead it is assigned to the template upon loading.
416      */

417
418     public void setEncoding(String JavaDoc encoding) {
419         this.encoding = encoding;
420     }
421
422     /**
423      * Returns the character encoding used for reading included files.
424      */

425     public String JavaDoc getEncoding() {
426         return this.encoding;
427     }
428
429     /**
430      * Dump the raw template in canonical form.
431      */

432     public void dump(PrintStream ps) {
433         ps.print(rootElement.getCanonicalForm());
434     }
435
436     /**
437      * Dump the raw template in canonical form.
438      */

439     public void dump(Writer out) throws IOException {
440         out.write(rootElement.getCanonicalForm());
441     }
442
443     /**
444      * Called by code internally to maintain
445      * a table of macros
446      */

447     public void addMacro(Macro macro) {
448         macros.put(macro.getName(), macro);
449     }
450
451     /**
452      * Called by code internally to maintain
453      * a list of imports
454      */

455     public void addImport(LibraryLoad ll) {
456         imports.add(ll);
457     }
458
459     /**
460      * Returns the template source at the location
461      * specified by the coordinates given.
462      * @param beginColumn the first column of the requested source, 1-based
463      * @param beginLine the first line of the requested source, 1-based
464      * @param endColumn the last column of the requested source, 1-based
465      * @param endLine the last line of the requested source, 1-based
466      * @see freemarker.core.TemplateObject#getSource()
467      */

468     public String JavaDoc getSource(int beginColumn,
469                             int beginLine,
470                             int endColumn,
471                             int endLine)
472     {
473         // Our container is zero-based.
474
--beginLine;
475         --beginColumn;
476         --endColumn;
477         --endLine;
478         StringBuffer JavaDoc buf = new StringBuffer JavaDoc();
479         for (int i = beginLine ; i<=endLine; i++) {
480             if (i < lines.size()) {
481                 buf.append(lines.get(i));
482             }
483         }
484         int lastLineLength = lines.get(endLine).toString().length();
485         int trailingCharsToDelete = lastLineLength - endColumn -1;
486         buf.delete(0, beginColumn);
487         buf.delete(buf.length() - trailingCharsToDelete, buf.length());
488         return buf.toString();
489     }
490
491     /**
492      * This is a helper class that builds up the line table
493      * info for us.
494      */

495     private class LineTableBuilder extends FilterReader {
496
497         StringBuffer JavaDoc lineBuf = new StringBuffer JavaDoc();
498         int lastChar;
499
500         /**
501          * @param r the character stream to wrap
502          */

503         LineTableBuilder(Reader r) {
504             super(r);
505         }
506
507         public int read() throws IOException {
508             int c = in.read();
509             handleChar(c);
510             return c;
511         }
512
513         public int read(char cbuf[], int off, int len) throws IOException {
514             int numchars = in.read(cbuf, off, len);
515             for (int i=off; i < off+numchars; i++) {
516                 char c = cbuf[i];
517                 handleChar(c);
518             }
519             return numchars;
520         }
521
522         public void close() throws IOException {
523             if (lineBuf.length() >0) {
524                 lines.add(lineBuf.toString());
525                 lineBuf.setLength(0);
526             }
527             super.close();
528         }
529
530         private void handleChar(int c) {
531             if (c == '\n' || c == '\r') {
532                 if (lastChar == '\r' && c == '\n') { // CRLF under Windoze
533
int lastIndex = lines.size() -1;
534                     String JavaDoc lastLine = (String JavaDoc) lines.get(lastIndex);
535                     lines.set(lastIndex, lastLine + '\n');
536                 } else {
537                     lineBuf.append((char) c);
538                     lines.add(lineBuf.toString());
539                     lineBuf.setLength(0);
540                 }
541             }
542             else if (c == '\t') {
543                 int numSpaces = 8 - (lineBuf.length() %8);
544                 for (int i=0; i<numSpaces; i++) {
545                     lineBuf.append(' ');
546                 }
547             }
548             else {
549                 lineBuf.append((char) c);
550             }
551             lastChar = c;
552         }
553     }
554
555     /**
556      * @return the root TemplateElement object.
557      */

558     public TemplateElement getRootTreeNode() {
559         return rootElement;
560     }
561     
562     public Map getMacros() {
563         return macros;
564     }
565
566     public List getImports() {
567         return imports;
568     }
569
570     /**
571      * This is used internally.
572      */

573     public void addPrefixNSMapping(String JavaDoc prefix, String JavaDoc nsURI) {
574         if (nsURI.length() == 0) {
575             throw new IllegalArgumentException JavaDoc("Cannot map empty string URI");
576         }
577         if (prefix.length() == 0) {
578             throw new IllegalArgumentException JavaDoc("Cannot map empty string prefix");
579         }
580         if (prefix.equals(NO_NS_PREFIX)) {
581             throw new IllegalArgumentException JavaDoc("The prefix: " + prefix + " cannot be registered, it is reserved for special internal use.");
582         }
583         if (prefixToNamespaceURILookup.containsKey(prefix)) {
584             throw new IllegalArgumentException JavaDoc("The prefix: '" + prefix + "' was repeated. This is illegal.");
585         }
586         if (namespaceURIToPrefixLookup.containsKey(nsURI)) {
587             throw new IllegalArgumentException JavaDoc("The namespace URI: " + nsURI + " cannot be mapped to 2 different prefixes.");
588         }
589         if (prefix.equals(DEFAULT_NAMESPACE_PREFIX)) {
590             this.defaultNS = nsURI;
591         } else {
592             prefixToNamespaceURILookup.put(prefix, nsURI);
593             namespaceURIToPrefixLookup.put(nsURI, prefix);
594         }
595     }
596     
597     public String JavaDoc getDefaultNS() {
598         return this.defaultNS;
599     }
600     
601     /**
602      * @return the NamespaceUri mapped to this prefix in this template. (Or null if there is none.)
603      */

604     public String JavaDoc getNamespaceForPrefix(String JavaDoc prefix) {
605         if (prefix.equals("")) {
606             return defaultNS == null ? "" : defaultNS;
607         }
608         return (String JavaDoc) prefixToNamespaceURILookup.get(prefix);
609     }
610     
611     /**
612      * @return the prefix mapped to this nsURI in this template. (Or null if there is none.)
613      */

614     public String JavaDoc getPrefixForNamespace(String JavaDoc nsURI) {
615         if (nsURI == null) {
616             return null;
617         }
618         if (nsURI.length() == 0) {
619             return defaultNS == null ? "" : NO_NS_PREFIX;
620         }
621         if (nsURI.equals(defaultNS)) {
622             return "";
623         }
624         return (String JavaDoc) namespaceURIToPrefixLookup.get(nsURI);
625     }
626     
627     /**
628      * @return the prefixed name, based on the ns_prefixes defined
629      * in this template's header for the local name and node namespace
630      * passed in as parameters.
631      */

632     public String JavaDoc getPrefixedName(String JavaDoc localName, String JavaDoc nsURI) {
633         if (nsURI == null || nsURI.length() == 0) {
634             if (defaultNS != null) {
635                 return NO_NS_PREFIX + ":" + localName;
636             } else {
637                 return localName;
638             }
639         }
640         if (nsURI.equals(defaultNS)) {
641             return localName;
642         }
643         String JavaDoc prefix = getPrefixForNamespace(nsURI);
644         if (prefix == null) {
645             return null;
646         }
647         return prefix + ":" + localName;
648     }
649     
650     /**
651      * @return an array of the elements containing the given column and line numbers.
652      * @param column the column
653      * @param line the line
654      */

655     public TreePath JavaDoc containingElements(int column, int line) {
656         ArrayList elements = new ArrayList();
657         TemplateElement element = rootElement;
658 mainloop:
659         while (element.contains(column, line)) {
660             elements.add(element);
661             for (Enumeration enumeration = element.children(); enumeration.hasMoreElements();) {
662                 TemplateElement elem = (TemplateElement) enumeration.nextElement();
663                 if (elem.contains(column, line)) {
664                     element = elem;
665                     continue mainloop;
666                 }
667             }
668             break;
669         }
670         if (elements == null || elements.isEmpty()) {
671             return null;
672         }
673         return new TreePath JavaDoc(elements.toArray());
674     }
675
676     static public class WrongEncodingException extends ParseException {
677
678         public String JavaDoc specifiedEncoding;
679
680         public WrongEncodingException(String JavaDoc specifiedEncoding) {
681             this.specifiedEncoding = specifiedEncoding;
682         }
683
684     }
685 }
686
687
Popular Tags