1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857
|
<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="generator" content="Docutils 0.3.7: http://docutils.sourceforge.net/" />
<title>Kid Language Specification</title>
<meta name="author" content="Ryan Tomayko" />
<meta name="date" content="2005-03-06 08:45:29 -0500 (Sun, 06 Mar 2005)" />
<meta name="copyright" content="2005, Ryan Tomayko" />
<link rel="stylesheet" href="custom.css" type="text/css" />
</head>
<body>
<div class="document" id="kid-language-specification">
<h1 class="title">Kid Language Specification</h1>
<table class="docinfo" frame="void" rules="none">
<col class="docinfo-name" />
<col class="docinfo-content" />
<tbody valign="top">
<tr><th class="docinfo-name">Author:</th>
<td><a class="first last reference" href="http://naeblis.cx/rtomayko/">Ryan Tomayko</a></td></tr>
<tr><th class="docinfo-name">Contact:</th>
<td><a class="first last reference" href="mailto:rtomayko@gmail.com">rtomayko@gmail.com</a></td></tr>
<tr><th class="docinfo-name">Revision:</th>
<td>4</td></tr>
<tr><th class="docinfo-name">Date:</th>
<td>2005-03-06 08:45:29 -0500 (Sun, 06 Mar 2005)</td></tr>
<tr><th class="docinfo-name">Copyright:</th>
<td>2005, Ryan Tomayko</td></tr>
<tr class="field"><th class="docinfo-name">Other Formats:</th><td class="field-body"><a class="reference" href="language.txt">Text</a></td>
</tr>
</tbody>
</table>
<!-- -*- mode: rst; encoding: utf-8 -*- -->
<p>Kid is a simple XML based template language that uses embedded <a class="reference" href="http://www.python.org/">Python</a> to do
cool stuff. The syntax was inspired by a number of existing template
languages, namely <a class="reference" href="http://www.w3.org/TR/xslt">XSLT</a>, <a class="reference" href="http://www.zope.org/Wikis/DevSite/Projects/ZPT/TAL">TAL</a>, and <a class="reference" href="http://www.php.net/">PHP</a>.</p>
<p>This document describes the template language and will be most useful as
reference to those developing Kid templates. For information about using
templates from Python, the command line, or in web environments, see the
<a class="reference" href="guide.html">User's Guide</a>.</p>
<div class="warning">
<p class="first admonition-title">Warning</p>
<p class="last">This software is in very early stages of development and will change
significantly before a 1.0 stable release. Most of the usage described in
this document will change. No promises are being made toward backward
compatibility between versions at this point.</p>
</div>
<div class="contents topic" id="contents">
<p class="topic-title first"><a name="contents">Contents</a></p>
<ul class="auto-toc simple">
<li><a class="reference" href="#synopsis" id="id7" name="id7">1 Synopsis</a></li>
<li><a class="reference" href="#the-kid-namespace" id="id8" name="id8">2 The Kid Namespace</a></li>
<li><a class="reference" href="#embedding-code-blocks-python" id="id9" name="id9">3 Embedding Code Blocks (<tt class="docutils literal"><span class="pre"><?python?></span></tt>)</a></li>
<li><a class="reference" href="#content-producing-constructs" id="id10" name="id10">4 Content Producing Constructs</a></li>
<li><a class="reference" href="#python-expression-substitution-expr" id="id11" name="id11">5 Python Expression Substitution (<tt class="docutils literal"><span class="pre">${expr}</span></tt>)</a><ul class="auto-toc">
<li><a class="reference" href="#identifier-shortcut-name" id="id12" name="id12">5.1 Identifier Shortcut (<tt class="docutils literal"><span class="pre">$name</span></tt>)</a></li>
<li><a class="reference" href="#escaping" id="id13" name="id13">5.2 Escaping (<tt class="docutils literal"><span class="pre">$$</span></tt>)</a></li>
</ul>
</li>
<li><a class="reference" href="#default-imports" id="id14" name="id14">6 Default Imports</a><ul class="auto-toc">
<li><a class="reference" href="#xml-function" id="id15" name="id15">6.1 <tt class="docutils literal"><span class="pre">XML()</span></tt> function</a></li>
<li><a class="reference" href="#document-function" id="id16" name="id16">6.2 <tt class="docutils literal"><span class="pre">document()</span></tt> function</a></li>
</ul>
</li>
<li><a class="reference" href="#attribute-language" id="id17" name="id17">7 Attribute Language</a><ul class="auto-toc">
<li><a class="reference" href="#repetition-iteration-py-for" id="id18" name="id18">7.1 Repetition/Iteration (<tt class="docutils literal"><span class="pre">py:for</span></tt>)</a></li>
<li><a class="reference" href="#conditionals-py-if" id="id19" name="id19">7.2 Conditionals (<tt class="docutils literal"><span class="pre">py:if</span></tt>)</a></li>
<li><a class="reference" href="#dynamic-content-py-content" id="id20" name="id20">7.3 Dynamic Content (<tt class="docutils literal"><span class="pre">py:content</span></tt>)</a></li>
<li><a class="reference" href="#replacing-content-py-replace" id="id21" name="id21">7.4 Replacing Content (<tt class="docutils literal"><span class="pre">py:replace</span></tt>)</a></li>
<li><a class="reference" href="#stripping-tags-py-strip" id="id22" name="id22">7.5 Stripping Tags (<tt class="docutils literal"><span class="pre">py:strip</span></tt>)</a></li>
<li><a class="reference" href="#dynamic-attributes-py-attrs" id="id23" name="id23">7.6 Dynamic Attributes (<tt class="docutils literal"><span class="pre">py:attrs</span></tt>)</a></li>
<li><a class="reference" href="#named-template-functions-py-def" id="id24" name="id24">7.7 Named Template Functions (<tt class="docutils literal"><span class="pre">py:def</span></tt>)</a></li>
<li><a class="reference" href="#match-templates-py-match" id="id25" name="id25">7.8 Match Templates (<tt class="docutils literal"><span class="pre">py:match</span></tt>)</a></li>
<li><a class="reference" href="#template-reuse-py-extends" id="id26" name="id26">7.9 Template Reuse (<tt class="docutils literal"><span class="pre">py:extends</span></tt>)</a></li>
</ul>
</li>
<li><a class="reference" href="#processing-order" id="id27" name="id27">8 Processing Order</a></li>
<li><a class="reference" href="#revision-history" id="id28" name="id28">9 Revision History</a><ul class="auto-toc">
<li><a class="reference" href="#revision-4-kid-v0-6" id="id29" name="id29">9.1 Revision 4 (Kid v0.6)</a></li>
<li><a class="reference" href="#revision-3-kid-v0-5" id="id30" name="id30">9.2 Revision 3 (Kid v0.5)</a></li>
<li><a class="reference" href="#revision-2" id="id31" name="id31">9.3 Revision 2</a></li>
<li><a class="reference" href="#revision-1" id="id32" name="id32">9.4 Revision 1</a></li>
</ul>
</li>
</ul>
</div>
<div class="section" id="synopsis">
<h1><a class="toc-backref" href="#id7" name="synopsis">1 Synopsis</a></h1>
<pre class="literal-block">
<?python
title = "A Kid Test Document"
fruits = ["apple", "orange", "kiwi", "M&M"]
from platform import system
?>
<html xmlns:py="http://purl.org/kid/ns#">
<head>
<title py:content="title">This is replaced.</title>
</head>
<body>
<p>These are some of my favorite fruits:</p>
<ul>
<li py:for="fruit in fruits">
I like ${fruit}s
</li>
</ul>
<p py:if="system() == 'Linux'">
Good for you!
</p>
</body>
</html>
</pre>
<p>Yields something like this:</p>
<pre class="literal-block">
<?xml version="1.0" encoding="utf-8"?>
<html>
<head>
<title>A Kid Test Document</title>
</head>
<body>
<p>These are some of my favorite fruits:</p>
<ul>
<li>I like apples</li>
<li>I like oranges</li>
<li>I like kiwis</li>
<li>I like M&amp;Ms</li>
</ul>
<p>
Good for you!
</p>
</body>
</html>
</pre>
</div>
<div class="section" id="the-kid-namespace">
<h1><a class="toc-backref" href="#id8" name="the-kid-namespace">2 The Kid Namespace</a></h1>
<p>All attributes described in this document must belong to the following
namespace:</p>
<pre class="literal-block">
http://purl.org/kid/ns#
</pre>
<p>The namespace prefix <tt class="docutils literal"><span class="pre">py</span></tt> is used throughout this document to indicate
that an item belongs to the Kid/Python namespace.</p>
</div>
<div class="section" id="embedding-code-blocks-python">
<h1><a class="toc-backref" href="#id9" name="embedding-code-blocks-python">3 Embedding Code Blocks (<tt class="docutils literal"><span class="pre"><?python?></span></tt>)</a></h1>
<p>The <tt class="docutils literal"><span class="pre"><?python?></span></tt> processing instruction (PI) contains Python code and
<em>MAY</em> occur anywhere that is legal for processing instructions to occur in an
XML document.</p>
<p>The rules for executing code found in a <tt class="docutils literal"><span class="pre"><?python?></span></tt> PI is as follows:</p>
<blockquote>
<ol class="arabic simple">
<li><tt class="docutils literal"><span class="pre"><?python?></span></tt> PIs located outside of the document element (e.g. root
element) contain <em>Document Level</em> code. This code <em>SHOULD</em> be executed
in a global, shared scope for the document. The code <em>SHOULD</em> be
executed once when the template is loaded and shared between multiple
invocations of the template.</li>
<li><tt class="docutils literal"><span class="pre"><?python?></span></tt> PIs located within the document element contain <em>Local
Level</em> code. This code is executed each time the document is processed
with a local scope specific to the invocation and the shared document
level global scope.</li>
</ol>
</blockquote>
<p><em>Document Level</em> and <em>Local Level</em> code work exactly like <em>Module Level</em> and
<em>Function Level</em> code in normal Python modules. For example, the following
Kid template:</p>
<pre class="literal-block">
<?python
x = 0
y = 0
?>
<html xmlns:py="http://purl.org/kid/ns#">
<?python
x = 1
if x == 1:
x = 10
?>
<p py:content="x"/>
<?python
global y
y = 30
?>
<p py:content="y"/>
</html>
</pre>
<p>May be considered equivalent to the following Python module:</p>
<pre class="literal-block">
x = 0
y = 0
def expand(handler):
handler.startDocument()
handler.startElement('html')
x = 1
if x == 1:
x = 10
handler.element('p', content=x) # output p element with x as value
global y
y = 30
handler.element('p', content=y) # output p element with value of y
handler.endElement('html')
handler.endDocument()
</pre>
<p><tt class="docutils literal"><span class="pre"><?python?></span></tt> PIs may contain any legal Python language construct including
functions, classes, lamda forms, etc.</p>
<pre class="literal-block">
<?python
class Adder:
def __init__(self, x, y):
self.x = x
self.y = y
def doit(self):
return self.x + self.y
foo = Adder(x=400, y=20)
x = foo.doit()
?>
</pre>
<p>Single line <tt class="docutils literal"><span class="pre"><?python?></span></tt> PIs are okay too:</p>
<pre class="literal-block">
<?python x = 10 ?>
</pre>
<a class="target" id="content-producing-construct" name="content-producing-construct"></a></div>
<div class="section" id="content-producing-constructs">
<h1><a class="toc-backref" href="#id10" name="content-producing-constructs">4 Content Producing Constructs</a></h1>
<p>There are multiple methods of generating content output from a template:
<tt class="docutils literal"><span class="pre">py:content</span></tt>, <tt class="docutils literal"><span class="pre">py:replace</span></tt>, <tt class="docutils literal"><span class="pre">py:attrs</span></tt>, and <tt class="docutils literal"><span class="pre">${}</span></tt> substitution. Each
of these syntaxes have the same rules for what types of objects may result
from the Python expression they contain.</p>
<dl class="docutils">
<dt><tt class="docutils literal"><span class="pre">str</span></tt>, <tt class="docutils literal"><span class="pre">unicode</span></tt></dt>
<dd>The string is inserted as XML CDATA. That is, it is non-parsable
character data that does not contain markup. The following characters are
encoded as XML entities when serialized: '<', '&'. Attribute values
containing content also encode the quote character: '"'.</dd>
<dt><tt class="docutils literal"><span class="pre">ElementTree.Element</span></tt></dt>
<dd><p class="first">When an <tt class="docutils literal"><span class="pre">ElementTree.Element</span></tt> is referenced from a content producing
construct, the item is inserted into the document literally, i.e. it is
not encoded as text, but becomes part of the output structure.</p>
<p>The <tt class="docutils literal"><span class="pre">XML()</span></tt> and <tt class="docutils literal"><span class="pre">document()</span></tt> functions can be used to turn a string
into structured content and to retrieve an XML document from a URL,
respectively.</p>
<p class="last">Note that attribute values <em>MUST NOT</em> reference structured content. This
applies to <tt class="docutils literal"><span class="pre">py:attrs</span></tt> and using <tt class="docutils literal"><span class="pre">${}</span></tt> substitution in attribute values.</p>
</dd>
<dt><em>sequence</em></dt>
<dd>If a sequence type (<tt class="docutils literal"><span class="pre">list</span></tt>, <tt class="docutils literal"><span class="pre">tuple</span></tt>, or other iterable) is referenced,
the rules are applied to each of the items in the sequence. For example,
you could reference a list containing an <tt class="docutils literal"><span class="pre">Element</span></tt> and a string.</dd>
<dt>Other</dt>
<dd>If the result of evaluating the expression is any other type, an
attempt is made to coerce the value to unicode as if by calling
<tt class="docutils literal"><span class="pre">unicode(expr)</span></tt> and processing continues as if the object were a string
or unicode object initially.</dd>
</dl>
<a class="target" id="expression-substitution" name="expression-substitution"></a></div>
<div class="section" id="python-expression-substitution-expr">
<h1><a class="toc-backref" href="#id11" name="python-expression-substitution-expr">5 Python Expression Substitution (<tt class="docutils literal"><span class="pre">${expr}</span></tt>)</a></h1>
<p>Attributes not belonging to the Kid namespace and text content <em>MAY</em> embed
Python expressions by enclosing the expression within a dollar sign followed
by curly braces: <tt class="docutils literal"><span class="pre">${expr}</span></tt>. The result of evaluating the expression(s) is
substituted with the rest of the attribute value or text content following
rules defined for <a class="reference" href="#content-producing-constructs">Content Producing Constructs</a>.</p>
<pre class="literal-block">
<?python
verb = 'ran'
noun = 'store'
?>
<a title="I ${verb} to the ${noun}">...
</pre>
<p>... would result in:</p>
<pre class="literal-block">
<a title="I ran to the store">...
</pre>
<p>If an attribute value consists purely of substitution expressions and all
expressions evaluate to <tt class="docutils literal"><span class="pre">None</span></tt>, the attribute is removed. This can be
avoided by using <tt class="docutils literal"><span class="pre">expr</span> <span class="pre">or</span> <span class="pre">''</span></tt> to force a zero length string to be
returned instead of <tt class="docutils literal"><span class="pre">None</span></tt>. For example:</p>
<pre class="literal-block">
<?python
# set something to None
x = None
?>
<a title="${x}">...
</pre>
<p>... would result in:</p>
<pre class="literal-block">
<a>...
</pre>
<p>However, this:</p>
<pre class="literal-block">
<?python x = None?>
<a title="${x or ''}">...
</pre>
<p>... results in:</p>
<pre class="literal-block">
<a title="">...
</pre>
<div class="section" id="identifier-shortcut-name">
<h2><a class="toc-backref" href="#id12" name="identifier-shortcut-name">5.1 Identifier Shortcut (<tt class="docutils literal"><span class="pre">$name</span></tt>)</a></h2>
<p>For simple expressions consisting entirely variable names and object access
operators (.), the curly braces may be omitted:</p>
<pre class="literal-block">
<a href="http://example.com/$page" title="$title">
Dots are allowed too: $object.another.attribute
</a>
</pre>
<p>However, it is good practice to use the curly brace form as it sets the
substitution off from the other text a bit more providing a stronger visual
clue as to what's going on.</p>
</div>
<div class="section" id="escaping">
<h2><a class="toc-backref" href="#id13" name="escaping">5.2 Escaping (<tt class="docutils literal"><span class="pre">$$</span></tt>)</a></h2>
<p><tt class="docutils literal"><span class="pre">$$</span></tt> is an escape. <tt class="docutils literal"><span class="pre">$${bla}</span></tt> will output <tt class="docutils literal"><span class="pre">${bla}</span></tt>.</p>
</div>
</div>
<div class="section" id="default-imports">
<h1><a class="toc-backref" href="#id14" name="default-imports">6 Default Imports</a></h1>
<p>All templates have a few default imports for convenience.</p>
<div class="section" id="xml-function">
<h2><a class="toc-backref" href="#id15" name="xml-function">6.1 <tt class="docutils literal"><span class="pre">XML()</span></tt> function</a></h2>
<p><a class="reference" href="#expression-substitution">Expression substitution</a>, <a class="reference" href="#py-content">py:content</a>, and <a class="reference" href="#py-replace">py:replace</a> encode strings
as text. That is, text is encoded according to the rules of the XML
specification, which includes, among other things, replacing the literal
characters <tt class="docutils literal"><span class="pre"><</span></tt> and <tt class="docutils literal"><span class="pre">&</span></tt> with their encoded counterparts (<tt class="docutils literal"><span class="pre">&lt;</span></tt>
<tt class="docutils literal"><span class="pre">&amp;</span></tt>). If you have XML stored as a string and want it to be output as
XML and not encoded text, you need to pass the string to the <tt class="docutils literal"><span class="pre">XML</span></tt>
function.</p>
<p>For example, let's say there is a function, <tt class="docutils literal"><span class="pre">hello</span></tt>, that returns XML data
that should be embedded in template output (let's say it returns
<tt class="docutils literal"><span class="pre"><hello>world</hello></span></tt>). Consider the following:</p>
<pre class="literal-block">
<p>${hello()}</p>
</pre>
<p>The result would be:</p>
<pre class="literal-block">
<p>&lt;hello>world&lt;hello></p>
</pre>
<p>Calling the <tt class="docutils literal"><span class="pre">XML</span></tt> function would have given us the result we intended:</p>
<pre class="literal-block">
<p>${XML(hello())}</p>
</pre>
<pre class="literal-block">
<p><hello>world</hello></p>
</pre>
</div>
<div class="section" id="document-function">
<h2><a class="toc-backref" href="#id16" name="document-function">6.2 <tt class="docutils literal"><span class="pre">document()</span></tt> function</a></h2>
<p>The <tt class="docutils literal"><span class="pre">document</span></tt> function loads an XML document from a file or URL allowing
it to be embedded in template output:</p>
<pre class="literal-block">
<div py:content="document('header.html')"></div>
</pre>
<p>The document function resolves paths relative to the current template file
(if the template location is available).</p>
</div>
</div>
<div class="section" id="attribute-language">
<h1><a class="toc-backref" href="#id17" name="attribute-language">7 Attribute Language</a></h1>
<a class="target" id="py-for" name="py-for"></a><div class="section" id="repetition-iteration-py-for">
<h2><a class="toc-backref" href="#id18" name="repetition-iteration-py-for">7.1 Repetition/Iteration (<tt class="docutils literal"><span class="pre">py:for</span></tt>)</a></h2>
<pre class="literal-block">
<element py:for="target_list in expression_list" />
</pre>
<p>Works exactly like the <a class="reference" href="http://www.python.org/dev/doc/devel/ref/for.html">Python for statement</a>.</p>
<p>The <tt class="docutils literal"><span class="pre">py:for</span></tt> attribute <em>may</em> appear on any element to signify that the
element should be processed multiple times, once for each value in the
sequence specified:</p>
<pre class="literal-block">
<?python
bottles = range(1, 101)
bottles.reverse()
?>
<p py:for="num in bottles">
<span py:content="num">X</span> bottles of beer on the wall,
<span py:content="num">X</span> bottles of beer on the wall,
take one down, pass it around, <span py:content="num - 1">X - 1</span>
bottles of beer on the wall.
</p>
</pre>
<p>The <tt class="docutils literal"><span class="pre">py:for</span></tt> attribute is the first attribute to be processed if
present. All other <tt class="docutils literal"><span class="pre">py:</span></tt> attributes are processed for each iteration of
the loop.</p>
<a class="target" id="py-if" name="py-if"></a></div>
<div class="section" id="conditionals-py-if">
<h2><a class="toc-backref" href="#id19" name="conditionals-py-if">7.2 Conditionals (<tt class="docutils literal"><span class="pre">py:if</span></tt>)</a></h2>
<pre class="literal-block">
<element py:if="expr" />
</pre>
<p>The <tt class="docutils literal"><span class="pre">py:if</span></tt> attribute may appear on any element to signify that the
element and its decendant items should be output only if the boolean
expression specified evaluates to true in Python:</p>
<pre class="literal-block">
<p py:if="5 * 5 == 25">
Python seems to be handling multiplication okay.
</p>
</pre>
<p>The <tt class="docutils literal"><span class="pre">py:if</span></tt> attribute is processed after the <tt class="docutils literal"><span class="pre">py:for</span></tt> attribute and is
evaluated for each iteration. If the result of evaluating <tt class="docutils literal"><span class="pre">expr</span></tt> as a
boolean expression is false in Python, no further <tt class="docutils literal"><span class="pre">py:</span></tt> attributes
are processed for the current iteration or, if not in a <tt class="docutils literal"><span class="pre">py:for</span></tt>, at all.</p>
<div class="note">
<p class="first admonition-title">Note</p>
<p class="last">Evaluated as a boolean expression in Python,
<tt class="docutils literal"><span class="pre">None</span></tt>, <tt class="docutils literal"><span class="pre">False</span></tt>, <tt class="docutils literal"><span class="pre">[]</span></tt>, <tt class="docutils literal"><span class="pre">()</span></tt>, <tt class="docutils literal"><span class="pre">{}</span></tt>, <tt class="docutils literal"><span class="pre">0</span></tt>, and <tt class="docutils literal"><span class="pre">''</span></tt>
are all considered to be false.</p>
</div>
<a class="target" id="py-content" name="py-content"></a></div>
<div class="section" id="dynamic-content-py-content">
<h2><a class="toc-backref" href="#id20" name="dynamic-content-py-content">7.3 Dynamic Content (<tt class="docutils literal"><span class="pre">py:content</span></tt>)</a></h2>
<pre class="literal-block">
<element py:content="expr" />
</pre>
<p>This attribute <em>MAY</em> appear on any element to signify that the decendant
items of the element are to be replaced with the result of evaluating
<tt class="docutils literal"><span class="pre">expr</span></tt>.</p>
<pre class="literal-block">
<p py:content="time.strftime('%C %c')">The Time</p>
</pre>
<p>Results in:</p>
<pre class="literal-block">
<p>Tues, Jun 26, 2004 02:03:53 AM</p>
</pre>
<p><tt class="docutils literal"><span class="pre">py:content</span></tt> is a <a class="reference" href="#content-producing-construct">Content Producing Construct</a> and can output both
character and structured data.</p>
<a class="target" id="py-replace" name="py-replace"></a></div>
<div class="section" id="replacing-content-py-replace">
<h2><a class="toc-backref" href="#id21" name="replacing-content-py-replace">7.4 Replacing Content (<tt class="docutils literal"><span class="pre">py:replace</span></tt>)</a></h2>
<pre class="literal-block">
<element py:replace='expr' />
</pre>
<p><tt class="docutils literal"><span class="pre">py:replace</span></tt> is shorthand for specifying a <tt class="docutils literal"><span class="pre">py:content</span></tt> and a
<tt class="docutils literal"><span class="pre">py:strip="True"</span></tt> on the same element:</p>
<pre class="literal-block">
<?python
x = 10
?>
<p><span py:replace="x">...</span></p>
</pre>
<p>... results in:</p>
<pre class="literal-block">
<p>10</p>
</pre>
<p>... and is equivelant to specifying:</p>
<pre class="literal-block">
<?python #
x = 10
?>
<p><span py:strip="" py:content="x">...</span></p>
</pre>
<p>The <tt class="docutils literal"><span class="pre">py:replace</span></tt> attribute is processed after the <tt class="docutils literal"><span class="pre">py:for</span></tt> and <tt class="docutils literal"><span class="pre">py:if</span></tt>
attributes. <tt class="docutils literal"><span class="pre">py:strip</span></tt> and <tt class="docutils literal"><span class="pre">py:content</span></tt> attributes are not processed and
are discarded.</p>
<p><tt class="docutils literal"><span class="pre">py:replace</span></tt> is a <a class="reference" href="#content-producing-construct">Content Producing Construct</a> and can output both
character and structured data.</p>
<a class="target" id="py-strip" name="py-strip"></a></div>
<div class="section" id="stripping-tags-py-strip">
<h2><a class="toc-backref" href="#id22" name="stripping-tags-py-strip">7.5 Stripping Tags (<tt class="docutils literal"><span class="pre">py:strip</span></tt>)</a></h2>
<pre class="literal-block">
<element py:strip="expr" />
</pre>
<p>The <tt class="docutils literal"><span class="pre">py:strip</span></tt> attribute may apppear on any element to signify that the
containing element should not be output. If the attribute value is blank (no
<tt class="docutils literal"><span class="pre">expr</span></tt> at all) or if the result <tt class="docutils literal"><span class="pre">expr</span></tt> is a boolean expression that evaluates to true,
the element is not output, but all descendant elements are processed normally. If
<tt class="docutils literal"><span class="pre">expr</span></tt> is not blank and the result of evaluating <tt class="docutils literal"><span class="pre">expr</span></tt> as a boolean expression
is false, processing continues as if the attribute did not exist.</p>
<p>The <tt class="docutils literal"><span class="pre">py:strip</span></tt> attribute <em>MAY</em> appear on an element with any other kid
attribute. However, if both a <tt class="docutils literal"><span class="pre">py:replace</span></tt> and a <tt class="docutils literal"><span class="pre">py:strip</span></tt> exist on the
same element, the <tt class="docutils literal"><span class="pre">py:strip</span></tt> attribute is ignored and discarded.</p>
<p>The <tt class="docutils literal"><span class="pre">py:strip</span></tt> attribute is processed after the <tt class="docutils literal"><span class="pre">py:for</span></tt> and <tt class="docutils literal"><span class="pre">py:if</span></tt>
attributes. If omission is eminent, the <tt class="docutils literal"><span class="pre">py:content</span></tt> attribute is
processed normally but attribute interpolation does not occur.</p>
<a class="target" id="py-attrs" name="py-attrs"></a></div>
<div class="section" id="dynamic-attributes-py-attrs">
<h2><a class="toc-backref" href="#id23" name="dynamic-attributes-py-attrs">7.6 Dynamic Attributes (<tt class="docutils literal"><span class="pre">py:attrs</span></tt>)</a></h2>
<pre class="literal-block">
<element py:attrs="expr" />
</pre>
<p>The <tt class="docutils literal"><span class="pre">py:attrs</span></tt> attribute may appear on any element to specify a set of
attributes that should be set on the element when it is processed. The
expression specified MUST evaluate to one of the following types of values:</p>
<dl class="docutils">
<dt>dict</dt>
<dd>A dictionary with keys specifying attribute names and values specifying
attribute values. These are added to the attributes of the current element
by calling <tt class="docutils literal"><span class="pre">element.attrib.update(mapping)</span></tt>, where <tt class="docutils literal"><span class="pre">element</span></tt> is an
ElementTree Element object and <tt class="docutils literal"><span class="pre">mapping</span></tt> is the dictionary returned from
the expression. Outer curly braces are not necessary to write down.</dd>
<dt>list</dt>
<dd>A list of tuples of the form <tt class="docutils literal"><span class="pre">(name,</span> <span class="pre">value)</span></tt> is also acceptable. Each
item of the list is added to the current set of attributes by iterating
over the list and calling <tt class="docutils literal"><span class="pre">element.set(name,</span> <span class="pre">value)</span></tt>.</dd>
<dt>keyword arguments</dt>
<dd>The attributes can also be specified as comma separated keyword arguments
of the form <tt class="docutils literal"><span class="pre">name=value</span></tt>.</dd>
</dl>
<p>The following lines:</p>
<pre class="literal-block">
<elem py:attrs="{'a':1, 'ns:b':2}" />
<elem py:attrs="'a':1, 'ns:b':2" />
<elem py:attrs="(('a',1), ('ns:b',2))" />
<elem py:attrs="a=1, ns:b=2" />
</pre>
<p>will all produce the same output:</p>
<pre class="literal-block">
<elem a="1" ns:b="2" />
</pre>
<p>Note that attributes whose values are <tt class="docutils literal"><span class="pre">None</span></tt> will be removed. If a blank
attribute is desired, an empty string should be used.</p>
<p>If the expression specified is an empty dictionary or an empty list,
the attributes are not modified in any way.</p>
<p><tt class="docutils literal"><span class="pre">py:attrs</span></tt> is a <a class="reference" href="#content-producing-construct">Content Producing Construct</a>, but can output only
character data.</p>
<a class="target" id="py-def" name="py-def"></a><a class="target" id="named-template-functions" name="named-template-functions"></a></div>
<div class="section" id="named-template-functions-py-def">
<h2><a class="toc-backref" href="#id24" name="named-template-functions-py-def">7.7 Named Template Functions (<tt class="docutils literal"><span class="pre">py:def</span></tt>)</a></h2>
<pre class="literal-block">
<element py:def="template_name(arg_list)" />
</pre>
<p>The <tt class="docutils literal"><span class="pre">py:def</span></tt> attribute may appear on any element to create a "Named
Template Function". Markup contained within an <tt class="docutils literal"><span class="pre">py:def</span></tt> element is not
output during normal template expansion but can be referenced from other
<a class="reference" href="#content-producing-constructs">Content Producing Constructs</a> to insert the markup at the point
referenced.</p>
<p>Like normal Python functions, Named Template Functions have an optional
argument list that may use all of the jazzy features of Python argument
lists like variable and keyword arguments.</p>
<p>Named Template Functions are invoked exactly like normal Python
functions. They are generally invoked from <a class="reference" href="#content-producing-constructs">Content Producing Constructs</a>
like <tt class="docutils literal"><span class="pre">py:content</span></tt> or <tt class="docutils literal"><span class="pre">${}</span></tt> substitution.</p>
<pre class="literal-block">
<ul py:def="display_list(seq)">
<li py:for="item in seq" py:content="item" />
</ul>
<table py:def="display_dict(mapping)">
<tr>
<th>Key</th>
<th>Value</th>
</tr>
<tr py:for="key, value in mapping.items()">
<td py:content="key" />
<td py:content="value" />
</tr>
</table>
</pre>
<p>Here we've defined two Named Template Functions: <tt class="docutils literal"><span class="pre">display_list</span></tt> and
<tt class="docutils literal"><span class="pre">display_dict</span></tt>. The first function takes a sequence and the second a
mapping. We can invoke these functions from the same template by invoking
them from a content producing construct:</p>
<pre class="literal-block">
<body>
${display_list(['apple', 'orange', 'kiwi'])}
<div py:replace="display_dict({'x' : 'y', 'p' : 'q'})">
Key/Value Table replaces this text
</div>
</body>
</pre>
<a class="target" id="py-match" name="py-match"></a><a class="target" id="match-templates" name="match-templates"></a></div>
<div class="section" id="match-templates-py-match">
<h2><a class="toc-backref" href="#id25" name="match-templates-py-match">7.8 Match Templates (<tt class="docutils literal"><span class="pre">py:match</span></tt>)</a></h2>
<pre class="literal-block">
<element py:match="expr" />
</pre>
<p>The <tt class="docutils literal"><span class="pre">py:match</span></tt> attribute may appear on any element to create a "Match
Template". Markup contained within a Match Template element is not output
during normal template expansion. Instead, these constructs set up filters
for expansion output that are capable of transforming content as it is
generated.</p>
<p>Match Templates are generally used to insert content dynamically based on
patterns in template expansion or to provide "custom tag" functionality
similar to that found in JSP taglibs or XSLT.</p>
<p>A Match Template has two parts: the match expression part (<tt class="docutils literal"><span class="pre">expr</span></tt>) and the
body part (the element and it's descendants).</p>
<p>Match Templates are processed as follows:</p>
<blockquote>
<ol class="arabic simple">
<li>Each element that is output from a template goes through the Match
Template Filter.</li>
<li>The Match Template Filter visits each of the Match Templates defined in
the current template and the templates the current template <a class="reference" href="#extends">extends</a>
in the order that they are defined and evaluates the associated match
expression.</li>
<li>If the match expression returns true as a boolean expression, the match
template's body is expanded and replaces the original element and
all of its descendants.</li>
</ol>
</blockquote>
<p>In both the match expression and in the match template's body, the <tt class="docutils literal"><span class="pre">item</span></tt>
name is bound to the Element that is being output. However, there are some
limitations to what can be accessed at each phase:</p>
<blockquote>
<ol class="arabic simple">
<li>During match expression evaluation, only the <tt class="docutils literal"><span class="pre">item</span></tt> Element and none
of its descendants are available. This means that match expressions are
limited to testing matches based on the immediate Element's tag and
attributes <a class="footnote-reference" href="#id5" id="id4" name="id4">[1]</a>.</li>
<li>During match template expansion (that is, when the match expression
is true), the element's descendants <em>are</em> available and may be
referenced from <a class="reference" href="#content-producing-constructs">Content Producing Constructs</a> to output bits and
pieces of the matched items structure.</li>
</ol>
</blockquote>
<table class="docutils footnote" frame="void" id="id5" rules="none">
<colgroup><col class="label" /><col /></colgroup>
<tbody valign="top">
<tr><td class="label"><a class="fn-backref" href="#id4" name="id5">[1]</a></td><td>This is due to the streaming nature of the Kid processor. During
normal template expansion, the entire tree is never fully retained in
memory.</td></tr>
</tbody>
</table>
<div class="section" id="example">
<h3><a name="example">7.8.1 Example</a></h3>
<p>The following simple example shows how to create a custom tag <tt class="docutils literal"><span class="pre"><greeting></span></tt>
that outputs one of two provided values based on the time of day the
template is expanded:</p>
<pre class="literal-block">
<?xml version="1.0" encoding="utf-8"?>
<?python
from time import localtime
def timeofday():
"""Get time of day ('am' or 'pm')"""
return localtime().tm_hour < 12 and 'am' or 'pm'
?>
<html xmlns:py="http://purl.org/kid/ns#">
<!-- define the greeting match template -->
<span py:match="item.tag == 'greeting'"
py:replace="item.get(timeofday())">
</span>
<head>
<title>Time of day demo</title>
</head>
<body>
<p>
Good <greeting am="Morning!" pm="Afternoon" />
</p>
</body>
</html>
</pre>
<p>An important thing to note is that the <tt class="docutils literal"><span class="pre">py:match</span></tt> expression and the match
template body have access to the <tt class="docutils literal"><span class="pre"><greeting></span></tt> element via the variable
<tt class="docutils literal"><span class="pre">item</span></tt>. The <tt class="docutils literal"><span class="pre">item.get(timeofday())</span></tt> bit retrieves the value of the
<tt class="docutils literal"><span class="pre">am</span></tt> attribute or the <tt class="docutils literal"><span class="pre">pm</span></tt> attribute based on what is returned from the
<tt class="docutils literal"><span class="pre">timeofday</span></tt> function.</p>
<p>At 9:00 AM, output from this template would look like this:</p>
<pre class="literal-block">
<html>
<head>
<title>Time of day demo</title>
</head>
<body>
<p>
Good Morning!
</p>
</body>
</html>
</pre>
<p>The obvious question at this point is how to reuse Match Templates? The
example above demonstrates the use of a Match Template from the same main
template but it is often desirable to have "libraries" of Match Templates
that could be used by multiple individual templates. The answer is to have
the main template <a class="reference" href="#extend">extend</a> a common template containing the Match Templates
needed. We can rewrite the above example as two separate templates:
<tt class="docutils literal"><span class="pre">main.kid</span></tt> and <tt class="docutils literal"><span class="pre">common.kid</span></tt>.</p>
<p>The common template would look like this:</p>
<pre class="literal-block">
<?xml version="1.0" encoding="utf-8"?>
<?python
from time import localtime
def timeofday():
"""Get time of day ('am' or 'pm')"""
return localtime().tm_hour < 12 and 'am' or 'pm'
?>
<html xmlns:py="http://purl.org/kid/ns#">
<!-- define the greeting match template -->
<span py:match="item.tag == 'greeting'"
py:replace="item.get(timeofday())">
</span>
</html>
</pre>
<p>And the main template would look like this:</p>
<pre class="literal-block">
<?xml version="1.0" encoding="utf-8"?>
<html py:extends="'common.kid'">
<head>
<title>Time of day demo</title>
</head>
<body>
<p>
Good <greeting am="Morning!" pm="Afternoon" />
</p>
</body>
</html>
</pre>
<p>When a template <a class="reference" href="#extends">extends</a> another template (or set of templates), all of the
Match Templates and <a class="reference" href="#named-template-functions">Named Template Functions</a> of the extended templates
are available as if they were defined locally.</p>
<div class="warning">
<p class="first admonition-title">Warning</p>
<p class="last">Match templates are an experimental feature. Syntax and semantics may
change significantly or be removed entirely in future release. Actually,
this statement applies to many aspects of Kid but this one is especially
unstable.</p>
</div>
<a class="target" id="py-extends" name="py-extends"></a><a class="target" id="extends" name="extends"></a><a class="target" id="extend" name="extend"></a><a class="target" id="template-reuse" name="template-reuse"></a></div>
</div>
<div class="section" id="template-reuse-py-extends">
<h2><a class="toc-backref" href="#id26" name="template-reuse-py-extends">7.9 Template Reuse (<tt class="docutils literal"><span class="pre">py:extends</span></tt>)</a></h2>
<pre class="literal-block">
<root py:extends="template1, template2, ...">
</pre>
<p>The <tt class="docutils literal"><span class="pre">py:extends</span></tt> attribute may appear on the root element to specify that
the template should inherit the <a class="reference" href="#named-template-functions">Named Template Functions</a> and <a class="reference" href="#match-templates">Match
Templates</a> defined in another template (or set of templates). If a
<tt class="docutils literal"><span class="pre">py:extends</span></tt> attribute is specified, it MUST be on the root element of the
document.</p>
<p>The <tt class="docutils literal"><span class="pre">py:extends</span></tt> may contain a list of Python expressions separated by
commas that reference templates. The rules for what types of values may be
specified are:</p>
<blockquote>
<dl class="docutils">
<dt>string</dt>
<dd><p class="first">The name of a template file, relative to the current template file.</p>
<p>Example:</p>
<pre class="last literal-block">
<html py:extends="'common.kid'" />
</pre>
</dd>
<dt>module or Template class</dt>
<dd><p class="first">The <tt class="docutils literal"><span class="pre">py:extends</span></tt> variable references a module or a Template class. If a
module is referenced, an attempt is made to find a class named
<tt class="docutils literal"><span class="pre">Template</span></tt> belonging to the that module.</p>
<p>Example:</p>
<pre class="last literal-block">
<?python
import common
?>
<html py:extends="common" ...
</pre>
</dd>
</dl>
</blockquote>
<p>Multiple templates may be referenced by separating each by a comma. The
following example references templates <tt class="docutils literal"><span class="pre">common</span></tt> and <tt class="docutils literal"><span class="pre">forms</span></tt>, imported
using the import hooks and a template filename named <tt class="docutils literal"><span class="pre">other.kid</span></tt>:</p>
<pre class="literal-block">
<?python
import common, forms
?>
<html py:extends="common, forms, 'other.kid'" ...
</pre>
<div class="section" id="id6">
<h3><a name="id6">7.9.1 Example</a></h3>
<p>For example, there is a template named <tt class="docutils literal"><span class="pre">common.kid</span></tt> that defines a
template function, <tt class="docutils literal"><span class="pre">display_errors</span></tt>, and a match template that converts
<tt class="docutils literal"><span class="pre"><b></span></tt> elements to <tt class="docutils literal"><span class="pre"><strong></span></tt> elements with uppercase content:</p>
<pre class="literal-block">
<html xmlns:py="http://purl.org/kid/ns#">
<ul py:def="display_errors(errors)">
<li py:for="error in errors" py:content="error" />
</ul>
<strong py:match="item.tag == 'b'"
py:content="item.text.upper()" />
</html>
</pre>
<p>The functions and match templates may be imported into another template by
referencing them with <tt class="docutils literal"><span class="pre">py:extends</span></tt>:</p>
<pre class="literal-block">
<html py:extends="'common.kid'"
xmlns:py="http://purl.org/kid/ns#">
<head>
<title>Errors</title>
</head>
<body>
<p>The following <b>errors</b> were found:</p>
${ display_errors(["Field is required", "Must be phone number.."]) }
</body>
</html>
</pre>
<p>The <tt class="docutils literal"><span class="pre"><b>errors</b></span></tt> item is transformed to <tt class="docutils literal"><span class="pre"><strong>ERRORS</strong></span></tt>
and the error list is displayed. Both the match template and the named
template function are available in the derived template as if they were
defined locally.</p>
<a class="target" id="order" name="order"></a></div>
</div>
</div>
<div class="section" id="processing-order">
<h1><a class="toc-backref" href="#id27" name="processing-order">8 Processing Order</a></h1>
<p>The order that <tt class="docutils literal"><span class="pre">py:</span></tt> attributes are processed is as follows:</p>
<blockquote>
<ol class="arabic simple">
<li><tt class="docutils literal"><span class="pre">py:def</span></tt></li>
<li><tt class="docutils literal"><span class="pre">py:match</span></tt></li>
<li><tt class="docutils literal"><span class="pre">py:for</span></tt></li>
<li><tt class="docutils literal"><span class="pre">py:if</span></tt></li>
<li><tt class="docutils literal"><span class="pre">py:replace</span></tt></li>
<li><tt class="docutils literal"><span class="pre">py:strip</span></tt></li>
<li><tt class="docutils literal"><span class="pre">py:attrs</span></tt></li>
<li><tt class="docutils literal"><span class="pre">py:content</span></tt></li>
</ol>
</blockquote>
<p>Attribute substitution occurs after all other attributes are processed and
MUST NOT be processed for <tt class="docutils literal"><span class="pre">py:</span></tt> attributes.</p>
</div>
<div class="section" id="revision-history">
<h1><a class="toc-backref" href="#id28" name="revision-history">9 Revision History</a></h1>
<div class="section" id="revision-4-kid-v0-6">
<h2><a class="toc-backref" href="#id29" name="revision-4-kid-v0-6">9.1 Revision 4 (Kid v0.6)</a></h2>
<blockquote>
<ul class="simple">
<li>Add <tt class="docutils literal"><span class="pre">py:extends</span></tt>.</li>
<li>Add <tt class="docutils literal"><span class="pre">py:match</span></tt>.</li>
<li>Add <tt class="docutils literal"><span class="pre">py:attrs</span></tt>.</li>
<li><tt class="docutils literal"><span class="pre">py:omit</span></tt> renamed <tt class="docutils literal"><span class="pre">py:strip</span></tt>.</li>
<li>Kid namespace changed from <tt class="docutils literal"><span class="pre">http://nabelis.cx/ns/kid#</span></tt> to
<tt class="docutils literal"><span class="pre">http://purl.org/kid/ns#</span></tt>.</li>
<li>Removed requirement of <tt class="docutils literal"><span class="pre"><?python?></span></tt> blocks to start with a comment.</li>
<li>Expression substitution syntax changed from <tt class="docutils literal"><span class="pre">{}</span></tt> to <tt class="docutils literal"><span class="pre">${}</span></tt>.</li>
</ul>
</blockquote>
</div>
<div class="section" id="revision-3-kid-v0-5">
<h2><a class="toc-backref" href="#id30" name="revision-3-kid-v0-5">9.2 Revision 3 (Kid v0.5)</a></h2>
<blockquote>
<ul class="simple">
<li>Changed processing instruction from <tt class="docutils literal"><span class="pre"><?kid?></span></tt> to <tt class="docutils literal"><span class="pre"><?python?></span></tt>.</li>
<li>Changed namespace prefixes from <tt class="docutils literal"><span class="pre">kid:</span></tt> to <tt class="docutils literal"><span class="pre">py:</span></tt>.</li>
</ul>
</blockquote>
</div>
<div class="section" id="revision-2">
<h2><a class="toc-backref" href="#id31" name="revision-2">9.3 Revision 2</a></h2>
<blockquote>
<ul class="simple">
<li>Added detail for each attribute on when it is processed in relation to other attributes and whether the result of other attributes modify behavior.</li>
<li>Fixed a few minor typos and grammatical issues.</li>
<li>Added editorial notes where things are a bit shaky.</li>
</ul>
</blockquote>
</div>
<div class="section" id="revision-1">
<h2><a class="toc-backref" href="#id32" name="revision-1">9.4 Revision 1</a></h2>
<blockquote>
<ul class="simple">
<li>Initial public version.</li>
</ul>
</blockquote>
</div>
</div>
</div>
</body>
</html>
|