NAME

Cindy - use unmodified XML or HTML documents as templates.

SYNOPSIS

use Cindy;

my $doc = get_html_doc('cindy.html');
my $data = get_xml_doc('cindy.xml');
my $descriptions = parse_cis('cindy.cjs');

my $out = inject($data, $doc, $descriptions);

print $out->toStringHTML();

DESCRIPTION

Cindy does Content INjection into XML and HTML documents. The positions for the modifications as well as for the data are identified by xpath expressions. These are kept in a seperate file called a Content inJection Sheet. The syntax of this CJS file (the ending .cis implies a japanese charset in the apache defaults) remotely resembles CSS. The actions for content modification are those implemented by TAL.

If you want to use Cindy for web development you will probably need Cindy::Apache2 (see http://search.cpan.org/%7ejzobel/Cindy-Apache2/) which is distributed separately since it introduces additional dependencies.

CJS SYNTAX

The syntax for content injection sheets is pretty simple. In most cases it is

<source path> <action> <target path> ;

If the syntax for an action differs from the above this is documented with the action.

The source and target path are xpath expressions by default. The action describes how to move the data. The whitespace before the terminating ; is required, since xpath expressions may end with a colon. The xpath expressions must not contain whitespaces. Alternatively they can be enclosed in double quotes.

Everything from a ; to the end of the line is ignored and can be used for comments.

A first line

use css ;

switches the interpretation of source and target path from xpath to CSS selectors. These are less powerful but according to Parr (see http://www.cs.usfca.edu/~parrt/papers/mvc.templates.pdf) this can be considered a good thing. Using css selectors reduces Cindies entanglement index from 4 to 1.

CJS ACTIONS

Actions locate data and document nodes and perform an operation that creates a modified document.

All source paths for actions other than repeat should locate one node. Otherwise the action is executed for all source nodes on the same target. The action is executed for all target nodes.

Actions are executed in the order they appear in the sheet. Subsheets are executed after the enclosing sheet.

The following example illustrates the effect of exectuion order. If a target node is omitted, an action that changes its content will not have any effect.

true()    omit-tag  <target> ;
<source>  content   <target> ;

So the above is not equvalent to the replace action.

Execution matches document nodes and then data nodes. Thereafter the actions are executed. Since execution of a repeat action copies the document node for each repetition, changes to this node done after the repeat are lost. At last this is recursively done for all subsheets.

As an unfortunate consequence matches on subsheet doc nodes do see the changes done by actions from enclosing sheets. This behaviour will hopefully change in future releases.

content

All child nodes of the target node are replaced by child nodes of the source node. This means that the text of the source tag with all tags it contains replaces the content of the target tag. If data is not a node, it is treated as text.

If no source node matched, the target node will be left unchanged.

replace

The child nodes of the source node replace the target node and all its content. THis means that the target tag including any content is replaced by the content of the subtag. This is equivalent to

<source>  content   <target> ;
true()    omit-tag  <target> ;

If no source node matched, the target node will be left unchanged.

omit-tag

The source node is used as a condition. If it exists and if its text content evaluates to true the target node is replaced by its children. This means that if the source tag exists and its content is not '' or 0 the target tag is removed while its content remains.

comment

The source nodes comntent is move into a comment node. This comment node is appended to the children of the target node. This can be useful for debugging and enables injection of SSI directives.

attribute

The syntax has an additional field atname

<source>  attribute   <target> <atname> ;

that holds the name of the attribute. If the source node exists, its content replaces or sets the value of the atname attribute of the target node. If the source node does not exist the attribute atname is removed from the target node.

condition

The source node is used as a condition. If it exists and if its text content evaluates to true nothing is done. Otherwise the target node and its children are removed. This means that the target tag is removed if the source tage does not exist or contains '', 0 or 0.0 while it is left untouched otherwise.

repeat

The repeat action is the CJS equivalent of a template engines loop. For each match of the source path the source node and the target node are used as root nodes for a sequence of actions. The syntax is

<source>  repeat   <target>  [condition] {
  <actions>
} ;

The optional condition is an xpath expression that is run in the context of the root node of a temporary document fragment. The fragment has two children, DOC and DATA which hold a subtree from a repeat doc respective data match. Only those combinations where the condition evaluates to true are used, all others are discarded.

Note that the repeat condition is an EXPERIMENTAL feature, it may well change.

XPATH FUNCTIONS

A small number of additional XPath functions have been implemented.

current()

This returns the context node. It behaves like the XSLT identically named XSLT function.

AUTHOR

Joachim Zobel <jz-2008@heute-morgen.de>

SEE ALSO

See Cindy/Sheet.pm for the RecDescent grammar for content injection sheets.

If you prefer a classic push template engine, that uses an API to fill the template from within the application see http://search.cpan.org/~tomita/Template-Semantic. This also uses xpath or css selectors to move data into unmodified templates.