|
||||||||||
| PREV CLASS NEXT CLASS | FRAMES NO FRAMES | |||||||||
| SUMMARY: NESTED | FIELD | CONSTR | METHOD | DETAIL: FIELD | CONSTR | METHOD | |||||||||
java.lang.Objectcom.x5.template.Chunk
public class Chunk
Chunk is part Hashtable, part StringBuilder, part find-and-replace.
Assign an initial template (you can stitch on bits of additional template
content as you go) with placeholder tags -- eg {$my_tag} -- and then
set up replacement rules for those tags like so:
TemplateSet templates = getTemplates(); // defined elsewhere
Chunk myChunk = templates.makeChunk("my_template");
myChunk.set("my_tag","hello tag");
System.out.print( myChunk.toString() );
NB: Template {$tags} are bounded by curly brackets, not (parentheses).
Be careful to always close off {#sub_templates}bla bla bla{#} with a single
hash mark surrounded by curly brackets/braces.
TemplateSet is handy if you have a folder with lots of html templates.
Here's an even simpler example, where the template string is supplied
without using TemplateSet:
String templateBody = "Hello {$name}! Your balance is ${$balance}."
+ "Pleasure serving you, {$name}!";
Chunk myChunk = new Chunk();
// .append() and .set() may be called in any order
// because tag replacement is delayed until the .toString() call.
myChunk.append( templateBody );
myChunk.set("name", user.getName());
myChunk.set("balance", user.getBalance());
System.out.println( myChunk.toString() );
// reset values and re-use -- original templates are not modified
// when .toString() output is generated.
myChunk.set("name", user2.getName());
myChunk.set("balance", user2.getBalance());
System.out.println( myChunk.toString() );
The .toString() method transparently invokes the find and replace
functionality.
FREQUENTLY ASKED QUESTIONS
Q: If I name things just right, will subtemplates get automatically
connected to like-named tags? ie, if I write a template file like this:
bla bla bla {$myTemplate} foo foo foo
{#myTemplate}Hello {$name}!{#}
A: No*. To keep things simple and reduce potential for confusion, Chunk
does not auto-magically fill any tags based on naming conventions or
in-template directives. You must explicitly invoke the "include command:
bla bla bla {.include #myTemplate} foo foo foo
* Actually, this documentation is outdated, and several extensions to the
original template syntax are now available:
There is now a powerful new tag modifier syntax which supports:
* providing default values for tags in-template
* automating template placement with "includes"
* in-template text filters including perl-style regex and sprintf
* macro-style templating
* extending the system to access alternate template repositories
Complete details are here: http://www.x5software.com/chunk
Q: My final output says "infinite recursion detected." What gives?
A: You did some variation of this:
TEMPLATE:
bla bla bla {$name}
{#name_info}My name is {$name}{#}
CODE:
...set("name", theme.getSnippet("file#name_info"));
...toString();
The outer template gets its {$name} tag replaced with "My name is {$name}" --
then, that replacement value is scanned for any tags that might need to be
swapped out for their values. It finds {$name} and, using the rule you gave,
replaces it with "My name is {$name}" so we now have My name is My name is ...
ad infinitum.
This situation is detected by assuming recursion depth will not normally go
deeper than 17. If you legitimately need to nest templates that deep, you
can flatten out the recursion by doing a .toString() expansion partway
through the nest OR you can tweak the depth limit value in the Chunk.java
source code.
Q: Where did my subtemplates go?
A: TemplateSet parses out subtemplates and leaves no trace of them in the
outer template where they were defined. Some people are surprised when
no placeholder tag is automagically generated and left in place of the
subtemplate definition -- sorry, this is not the convention. For optional
elements the template/code usually looks like this:
TEMPLATE:
bla bla bla
{$memberMenu:}
{#member_menu}this that etc{#}
foo foo foo
CODE:
if (isLoggedIn) {
myChunk.set("memberMenu", theme.getSnippet("file#member_menu"));
}
The subtemplate does not need to be defined right next to the tag where
it will be used (although that practice does promote readability).
Q: Are tag names and subtemplate names case sensitive?
A: Yes. I prefer to use mixed case in {$tagNames} with first letter
lowercase. In my experience this aids readability since tags are similar
to java variables in concept and that is the java case convention for
variables. Similarly, I prefer lowercase with underscores for all
{#sub_template_names}{#} since templates tend to be defined within html
files which are typically named in all lowercase.
ADVANCED USES
Chunk works great for the simple examples above, but Chunk can do
so much more... the find-and-replace alg is recursive, which is
extremely handy once you get the hang of it.
Internally it resists creating an expensive Hashtable until certain
threshhold conditions are reached.
Output can be constructed on-the-fly with .append() -- say
you're building an HTML table but don't know ahead of time how
many rows and columns it will contain, just loop through all
your data with calls to .append() after preparing each cell and row:
Chunk table = templates.makeChunk("my_table");
Chunk rows = templates.makeChunk();
Chunk row = templates.makeChunk("my_table.my_row");
Chunk cell = templates.makeChunk("my_table.my_cell");
rows.set("background_color", getRowColor() );
while (dataSet.hasMoreData()) {
DataObj data = dataSet.nextDataObj();
String[] attributes = data.getAttributes();
StringBuilder cells = new StringBuilder();
for (int i=0; i < attributes.length; i++) {
cell.set("cellContent", attributes[i]);
cells.append( cell.toString() );
}
row.set("name", data.getName());
row.set("id", data.getID());
row.set("cells",cells);
rows.append( row.toString() );
}
table.set("table_rows",rows);
System.out.println( table.toString() );
Possible contents of my_table.html:
<TABLE>
{$table_rows}
</TABLE>
{#my_row}
<TR bgcolor="{$background_color}">
<TD>{$id} - {$name}</TD>
{$cells}
</TR>
{#}
{#my_cell}
<TD>{$cell_content}</TD>
{#}
Copyright: waived, free to use
| Nested Class Summary |
|---|
| Nested classes/interfaces inherited from interface java.util.Map |
|---|
java.util.Map.Entry<K,V> |
| Field Summary | |
|---|---|
static int |
DEPTH_LIMIT
|
static int |
HASH_THRESH
|
protected java.lang.String |
tagEnd
|
protected java.lang.String |
tagStart
|
protected java.util.Vector<Snippet> |
template
|
protected Snippet |
templateRoot
|
static java.lang.String |
VERSION
|
| Constructor Summary | |
|---|---|
Chunk()
|
|
| Method Summary | |
|---|---|
protected java.lang.Object |
_resolveTagValue(SnippetTag tag,
int depth,
boolean ignoreParentContext)
|
void |
addData(DataCapsule smartObj)
Smart objects implementing DataCapsule can provide their own legend of available tags and which methods to call for exporting the tag data. |
void |
addData(DataCapsule smartObj,
java.lang.String altPrefix)
Two smart objects of the same type in a single template? No problem. |
void |
addProtocol(ContentSource src)
|
void |
append(Chunk toAdd)
Add a Chunk on to the end of a Chunk's "template" -- this "child" Chunk won't get it's .toString() invoked until the parent Chunk's tags are replaced, ie when the parent Chunk's .toString() method is invoked. |
void |
append(Snippet toAdd)
|
void |
append(java.lang.String toAdd)
Add a String on to the end a Chunk's template. |
void |
clear()
|
boolean |
containsKey(java.lang.Object key)
|
boolean |
containsValue(java.lang.Object value)
|
java.util.Set<java.util.Map.Entry<java.lang.String,java.lang.Object>> |
entrySet()
|
boolean |
equals(java.lang.Object o)
|
static java.lang.String |
findAndReplace(java.lang.String toSearch,
java.lang.String find,
java.lang.String replace)
Useful utility function. |
java.lang.Object |
get(java.lang.Object key)
|
ChunkFactory |
getChunkFactory()
|
ChunkLocale |
getLocale()
|
java.util.Map<java.lang.String,java.lang.Object> |
getTagsTable()
Retrieve all find-and-replace rules. |
java.lang.Object |
getTagValue(java.lang.String tagName)
Retrieves a tag replacement rule. |
java.lang.String |
getTemplateOrigin()
|
ContentSource |
getTemplateSet()
|
int |
hashCode()
|
boolean |
hasValue(java.lang.String tagName)
|
boolean |
isEmpty()
|
java.util.Set<java.lang.String> |
keySet()
|
java.lang.String |
makeTag(java.lang.String tagName)
|
java.lang.Object |
put(java.lang.String key,
java.lang.Object value)
|
void |
putAll(java.util.Map t)
|
java.lang.Object |
remove(java.lang.Object key)
|
void |
render(java.io.PrintStream out)
|
void |
render(java.io.Writer out)
|
void |
render(java.io.Writer out,
Chunk context)
|
void |
resetTags()
Clears all tag replacement rules. |
void |
resetTemplate()
Clears template |
protected java.lang.Object |
resolveTagValue(SnippetTag tag,
int depth)
|
protected java.lang.Object |
resolveTagValue(SnippetTag tag,
int depth,
java.lang.String origin)
|
protected java.lang.Object |
resolveTagValue(java.lang.String tagName,
int depth)
|
void |
set(java.lang.String tagName)
For convenience, sets a flag to "TRUE" - to reverse, call unset("flag") |
void |
set(java.lang.String tagName,
char tagValue)
For convenience, auto-converts char to String and creates tag replacement rule. |
void |
set(java.lang.String tagName,
Chunk tagValue)
Creates a find-and-replace rule for tag replacement. |
void |
set(java.lang.String tagName,
int tagValue)
For convenience, auto-converts int to String and creates tag replacement rule. |
void |
set(java.lang.String tagName,
long tagValue)
For convenience, auto-converts long to String and creates tag replacement rule. |
void |
set(java.lang.String tagName,
java.lang.Object tagValue)
Convenience method, chains to set(String s, Object o, String ifNull) |
void |
set(java.lang.String tagName,
java.lang.Object tagValue,
java.lang.String ifNull)
Create a tag replacement rule, supplying a default value in case the value passed is null. |
void |
set(java.lang.String tagName,
java.lang.String tagValue)
Creates a find-and-replace rule for tag replacement. |
void |
set(java.lang.String tagName,
java.lang.StringBuffer tagValue)
For convenience, auto-converts StringBuffer to String and creates tag replacement rule. |
void |
set(java.lang.String tagName,
java.lang.StringBuilder tagValue)
For convenience, auto-converts StringBuilder to String and creates tag replacement rule. |
void |
setChunkFactory(ChunkFactory factory)
|
void |
setErrorHandling(boolean renderErrs,
java.io.PrintStream err)
|
void |
setLiteral(java.lang.String tagName,
java.lang.String literalValue)
setLiteral() tag values will render verbatim, so even if the value contains tags/specials they will not be expanded. |
void |
setLocale(ChunkLocale chunkLocale)
|
void |
setLocale(java.util.Locale javaLocale)
|
void |
setLocale(java.lang.String localeCode)
|
void |
setMultiple(Chunk copyFrom)
Adds multiple find-and-replace rules using all rules from the passed Chunk. |
void |
setMultiple(java.util.Map<java.lang.String,java.lang.Object> rules)
Adds multiple find-and-replace rules using all entries in the Hashtable. |
void |
setOrDelete(java.lang.String tagName,
java.lang.Object tagValue)
Careful, setOrDelete will DELETE a previous value for the tag at this level if passed a null value. |
void |
setToBean(java.lang.String tagName,
java.lang.Object bean)
Make bean properties available to template |
void |
setToBean(java.lang.String tagName,
java.lang.Object bean,
java.lang.String ifNull)
Make bean properties available to template |
int |
size()
|
boolean |
stillNeeds(java.lang.String tagName)
|
java.lang.String |
toString()
Apply all tag replacement rules recursively and return template contents with translated tags. |
java.lang.String |
toString(Chunk context)
|
void |
unset(java.lang.String tagName)
unset("tag") deletes the named tag expansion rule from the ruleset. |
java.util.Collection<java.lang.Object> |
values()
|
| Methods inherited from class java.lang.Object |
|---|
clone, finalize, getClass, notify, notifyAll, wait, wait, wait |
| Field Detail |
|---|
public static final int HASH_THRESH
public static final int DEPTH_LIMIT
public static final java.lang.String VERSION
protected Snippet templateRoot
protected java.util.Vector<Snippet> template
protected java.lang.String tagStart
protected java.lang.String tagEnd
| Constructor Detail |
|---|
public Chunk()
| Method Detail |
|---|
public ContentSource getTemplateSet()
public void setChunkFactory(ChunkFactory factory)
public ChunkFactory getChunkFactory()
public void append(Snippet toAdd)
public void append(java.lang.String toAdd)
public void append(Chunk toAdd)
public void set(java.lang.String tagName,
java.lang.String tagValue)
tagName - will be ignored if null.tagValue - will be translated to the empty String if null -- use setOrDelete() instead of set() if you don't need/want this behavior.
public void set(java.lang.String tagName,
Chunk tagValue)
tagName - will be ignored if null.tagValue - will be translated to the empty String if null.append(Chunk)
public void set(java.lang.String tagName,
java.lang.Object tagValue)
public void setOrDelete(java.lang.String tagName,
java.lang.Object tagValue)
public void setLiteral(java.lang.String tagName,
java.lang.String literalValue)
tagName - literalValue -
public void set(java.lang.String tagName,
java.lang.Object tagValue,
java.lang.String ifNull)
tagName - tag to replacetagValue - replacement value -- no-op unless this is of type String or Chunk.ifNull - fallback replacement value in case tagValue is null
public void setToBean(java.lang.String tagName,
java.lang.Object bean)
public void setToBean(java.lang.String tagName,
java.lang.Object bean,
java.lang.String ifNull)
public void set(java.lang.String tagName)
public void set(java.lang.String tagName,
int tagValue)
public void set(java.lang.String tagName,
char tagValue)
public void set(java.lang.String tagName,
long tagValue)
public void set(java.lang.String tagName,
java.lang.StringBuilder tagValue)
public void set(java.lang.String tagName,
java.lang.StringBuffer tagValue)
public void unset(java.lang.String tagName)
tagName - public boolean hasValue(java.lang.String tagName)
public boolean stillNeeds(java.lang.String tagName)
public java.lang.String toString()
toString in class java.lang.Objectpublic java.lang.String toString(Chunk context)
public void render(java.io.PrintStream out)
throws java.io.IOException
java.io.IOException
public void render(java.io.Writer out)
throws java.io.IOException
java.io.IOException
public void render(java.io.Writer out,
Chunk context)
throws java.io.IOException
java.io.IOExceptionpublic java.lang.Object getTagValue(java.lang.String tagName)
public void addProtocol(ContentSource src)
protected java.lang.Object resolveTagValue(SnippetTag tag,
int depth,
java.lang.String origin)
protected java.lang.Object resolveTagValue(SnippetTag tag,
int depth)
protected java.lang.Object _resolveTagValue(SnippetTag tag,
int depth,
boolean ignoreParentContext)
protected java.lang.Object resolveTagValue(java.lang.String tagName,
int depth)
public void resetTags()
public void clear()
clear in interface java.util.Map<java.lang.String,java.lang.Object>public void resetTemplate()
public boolean containsKey(java.lang.Object key)
containsKey in interface java.util.Map<java.lang.String,java.lang.Object>public boolean containsValue(java.lang.Object value)
containsValue in interface java.util.Map<java.lang.String,java.lang.Object>public java.util.Set<java.util.Map.Entry<java.lang.String,java.lang.Object>> entrySet()
entrySet in interface java.util.Map<java.lang.String,java.lang.Object>public boolean equals(java.lang.Object o)
equals in interface java.util.Map<java.lang.String,java.lang.Object>equals in class java.lang.Objectpublic java.lang.Object get(java.lang.Object key)
get in interface java.util.Map<java.lang.String,java.lang.Object>public int hashCode()
hashCode in interface java.util.Map<java.lang.String,java.lang.Object>hashCode in class java.lang.Objectpublic boolean isEmpty()
isEmpty in interface java.util.Map<java.lang.String,java.lang.Object>public java.util.Set<java.lang.String> keySet()
keySet in interface java.util.Map<java.lang.String,java.lang.Object>
public java.lang.Object put(java.lang.String key,
java.lang.Object value)
put in interface java.util.Map<java.lang.String,java.lang.Object>public java.lang.Object remove(java.lang.Object key)
remove in interface java.util.Map<java.lang.String,java.lang.Object>public void putAll(java.util.Map t)
putAll in interface java.util.Map<java.lang.String,java.lang.Object>public int size()
size in interface java.util.Map<java.lang.String,java.lang.Object>public java.util.Collection<java.lang.Object> values()
values in interface java.util.Map<java.lang.String,java.lang.Object>public void setMultiple(java.util.Map<java.lang.String,java.lang.Object> rules)
public void setMultiple(Chunk copyFrom)
public java.util.Map<java.lang.String,java.lang.Object> getTagsTable()
public void addData(DataCapsule smartObj)
smartObj -
public void addData(DataCapsule smartObj,
java.lang.String altPrefix)
smartObj - altPrefix - public java.lang.String makeTag(java.lang.String tagName)
public void setErrorHandling(boolean renderErrs,
java.io.PrintStream err)
public void setLocale(java.lang.String localeCode)
public void setLocale(java.util.Locale javaLocale)
public void setLocale(ChunkLocale chunkLocale)
public ChunkLocale getLocale()
public static java.lang.String findAndReplace(java.lang.String toSearch,
java.lang.String find,
java.lang.String replace)
toSearch - text body.find - text to search for.replace - text to insert in place of "find" -- defaults to empty String if null is passed.
public java.lang.String getTemplateOrigin()
|
||||||||||
| PREV CLASS NEXT CLASS | FRAMES NO FRAMES | |||||||||
| SUMMARY: NESTED | FIELD | CONSTR | METHOD | DETAIL: FIELD | CONSTR | METHOD | |||||||||