The spiralcraft-textgen module is designed to generate a wide variety of text output from plain text to various forms of markup.
The textgen syntax is a roughly based on XML. Since one of the uses of textgen is to generate actual XML, textgen uses a different delimiter syntax in order to differentiate between textgen template code and the target content.
A textgen template is a source code file that contains a tree of nested Elements defined by "tags". A tag is delimited by the <% ... %> symbols by convention.
Tags define the start and end of Elements, and always contain an Element name as the first token between the delimiters.
A "start tag" defines the start of an Element, and must be matched by an "end tag" with the same name. All content and Elements defined between an Element's start and end tags are considered "children" of that Element.
<%MyElement%>
...
<%/MyElement%>
An "empty tag" defines an Element with no children.
<%MyClosedElement/%>
Start tags or empty tags can contain attributes which inject values into the element before it is bound into the application context. Attribute values may be delimited with either double or single quotes.
<%MyElement myProp="value" myOtherProp='this is a "quoted" value'/%>
Tag names, when used for "component" type Elements, can include a namespace qualifier.
<%myns:MyElement%>
...
<%/myns:MyElement%>
In textgen, a namespace prefix is bound to a URI which identifies a package (a resource or a Java package) that contains the element definition.
A namespace prefix has file scope- it can be seen by the declaring Element, its children in the same textgen template file, any ELaine expressions in that file, and any namespace aware Java code invoked during the compilation process.
A namespace prefix is declared using the "tgns" attribute in the open tag or as follows:
<%myns:MyElement
tgns:myns="class:/my/module/package/"
tgns:myns2="class:/my/module/otherPackage/"
%>
<%/myns:MyElement%>
Any number of namespace prefixes may be declared in a single Element.
Elements are the basic unit of composition in textgen.
A textgen template file is compiled into a data structure that is then bound into the context of a running application, producing a tree of Elements called a "generator" that generates dynamic content and responds to events.
There are a few different types of Elements- each Element type addresses some function in the composition of a template.
Component Elements define the functional logic of a textgen template. They output content, interact with the application model, or provide context to child elements.
The qualified name of the element is resolved to the Java class or Builder assembly that defines the Element. Spiralcraft Builder is used as the underlying mechanism to instantiate Elements and inject their dependencies.
<%myns:MyElement myProp="someValue" myOtherProp="myOtherValue"%>
...
<%/myns:MyElement%>
The attributes in a Component Element inject Java bean properties into the Element instance before it is bound into the application context.
Textgen comes with some built-in Component Elements to provide basic capabilities. Extensions of textgen, such as the WebUI framework, provide an expanded set of Component Elements.
Property Elements are used to inject complex values into a component that cannot be conveniently expressed in attributes. Like attributes, the values referenced by Property Elements are injected before the Element is bound into the application context.
Property Elements do not have namespace prefixes, and always start with a ".". The element name, after the "." prefix, specifies the Java bean property that will receive the value.
<%myns:MyElement%>
<%.myComplexProp%>This is some text I don't want to put in an "attribute"
<%/.myComplexProp%>
<%/myns:MyElement%>
Object Elements are used within Property Elements to inject arbitrary Java objects into the properties of other Elements. Like Component Elements, the qualified name of the element is resolved to the Java class or Builder assembly that defines the object.
<%myns:MyElement%>
<%.myComplexProp%>
<%otherns:SomePOJO
tgns:otherns="class:/some/useful/api/"
itsBeanProp="someValue"
/%>
<%/.myComplexProp%>
<%/myns:MyElement%>
These elements do not use namespace prefixes and always start with a "@" prefix. They function at the pre-compilation stage to manipulate content fragments and control the compilation process.
The available processing elements are defined internally within the textgen compiler.
<%@include resource="myWrapper.tgl"%>
My content
<%/@include%>
Other syntax variations are used to facilitate common operations
The Eval element is a special empty element that outputs the result of an ELaine expression.
<%=1+1/%>
Also see the shorthand syntax for the @define and @insert Processing Elements
These elements provide common run-time functionality, and can be included in any markup system extended from spiralcraft.textgen without using a namespace prefix.
Output the result of the ELaine expression
<%=x+y*z/%>
Activate a group of elements when the condition is true
<%If x='condition'%>
...
<%/If%>
Activate an alternate group of elements when the condition is false
<%If x='condition'%>
...
<%Else/%>
...
<%/If%>
Make the value returned by the expression the subject of the local Focus for child elements.
<%With x='somePerson'%>
<%=.firstName/%> <%=.lastName/%>
<%/With%>
The value is recomputed on every rendering cycle.
When a stateful model is used, this property indicates that the target ("x") value should only be computed when the given expression returns false. This can be used to prevent expensive re-computation of unchanging data, or if the value is simply true, the value will be held for the scope of the associated state.
When a stateful model is used, this property indicates that the target ("x") value should only be recomputed when the value returned by the given expression changes. This allows the computation to be synchronized with other elements that change less frequently than every rendering. If the expression is time-based, computation can be scheduled according to a fixed period in this manner.
Iterate through a collection or array
<%Iterate x='somePersonCollection'%>
<%=[Iterate].index/%>: <%=.name/%>, <%=.value/%>
<%/Iterate%>
Output a header and/or footer when the value of an expression changes
<%Iterate x="mySalespeople"%>
<%Group x="region"%>
<%GroupHeader%>
<h2>Region: <%=region/%></h2>
<%GroupHeader%>
<%=name/%>
<%GroupFooter%>
(End Region: <%=region/%>)
<%GroupFooter%>
<%Group/%>
<%/Iterate%>
Format a date
<%DateFormat x="someDate" format="yyyy-MM-dd" timeZone="someTimeZone"/%>
DateFormat uses java.text.SimpleDateFormat internally. See the javadoc for the format string syntax.
Format a number
<%NumberFormat x="someNumber" format="$###,##0.00"/%>
NumberFormat uses java.text.NumberFormat internally. See the javadoc for the format string syntax.
Create a single object shared by all threads and visible to child elements
<%SharedReference typeX="[@mytypes:MyWidget]" instanceURI="myWidgetConfig"/%>
...
<%=[mytypes:MyWidget].myProperty/%>
...
<%/SharedReference%>
Create an object scoped to the state tree (ie. the session model) and visible to child elements
<%LocalReference typeX="[@mytypes:MyWidget]" instanceURI="myWidgetConfig"/%>
...
<%=[mytypes:MyWidget].myProperty/%>
...
<%/LocalReference%>
These elements manipulate markup resources and the page compilation process itself
Include a resource, possibly using it as a wrapper
<%@include resource="../myfile.textgen"/%>
<%@include resource="../wrapper.textgen"%>
This goes inside the wrapper where the wrapper puts @insert
<%/@include%>
Define a content block to be activated and/or bound in a different context
<%@include resource="myTemplate"%>
<%@define name="mySpecificContent"%>
This is customized and will go into the template and be rendered as a closure
<%=myCustomExpression/%>
<%mytags:MyTag/%>
<%@/define%>
<%/@include%>
Defining a block of markup can be accomplished using a shorthand method using the block name prefixed with "$" as the tag name.
This benefits usability by having the name of the block visible at both the beginning and end of the definition, as well as reducing boilerplate syntax.
<%$myblock%>
Today's date is <%DateFormat format="yyyy-mm-dd"/%>
<%/$myblock%>
Insert a predefined content block
This is a wrapper around the content
<%@insert/%>
inside the @include that included me
Here is some predefined content <%@insert name="myPredefinedBlock"/%>
Inserting a predefined block of markup can be accomplished using a shorthand method. The markup may contain its own nested inserts. The name of the markup block must start with a lower case letter.
This benefits usability by having the name of the block visible at both the beginning and end of the wrapped area, as well as reducing boilerplate syntax.
If the block is named "mywrapper":
<%mywrapper%>
Wrap this content in mywrapper
<%/mywrapper%>
Note: this element is deprecated in favor of the tgns:ns="URI" attribute on any element
Define a namespace prefix for use in tag names and spiralcraft.lang Expressions
<%@namespace mytypes="class:/mypackage/mytypes/"%>
<%mytypes:MyElement x="[mytypes:MyType].someProperty"/>
<%/@namespace%>
Suppress activation of a content block
<%@comment%>Don't activate this<%/@comment%>
Suppress activation of a content block
<%!%>Don't activate this<%/!%>