625 | | '''TODO: explain''' |
| 625 | That contains a whole lot of things, so let's break it up into smaller pieces and go through the various aspects to clarify them. |
| 626 | |
| 627 | 1. '''The Document Element''' |
| 628 | |
| 629 | {{{ |
| 630 | #!genshi |
| 631 | <html xmlns="http://www.w3.org/1999/xhtml" |
| 632 | xmlns:py="http://genshi.edgewall.org/" py:strip=""> |
| 633 | }}} |
| 634 | |
| 635 | First, note that the root element of the template is an `<html>` tag. This is needed because markup templates are XML documents, and XML documents require a single root element (we also use it to attach our namespace declarations, but we just as as well do that on the nested `<py:match>` elements). However, because the page templates that include this file will also have `<html>` root elements, we add the `py:strip=""` directive so that this second `<html>` tag doesn't make it through into the output stream. |
| 636 | |
| 637 | 2. '''Match Template Definition''' |
| 638 | |
| 639 | {{{ |
| 640 | #!genshi |
| 641 | <py:match path="head" once="true"> |
| 642 | }}} |
| 643 | |
| 644 | Here we define the first match template. The `path` attribute contains the XPath pattern the specifies which elements this match template should be applied to. In this case, the XPath is very simple: it matches any element with the local name “head”, so it will be applied to the `<head>...</head>` element (whether it's in the XHTML namespace or not). We also add the `once="true"` attribute to tell Genshi that we only expect a single occurrence of the `<head>` element in the stream. Genshi can perform some optimizations based on this information. |
| 645 | |
| 646 | 3. '''Selecting Matched Content''' |
| 647 | |
| 648 | {{{ |
| 649 | #!genshi |
| 650 | <head py:attrs="select('@*')"> |
| 651 | }}} |
| 652 | |
| 653 | Inside match templates, you can use the special function `select(path)` to access the element that matched the pattern. Here we use that function in the `py:attrs` directive, which basically translates to “''get all attributes defined on the matched element, and add them to this element''”. So for example if your page template contained `<head id="foo">`, the element produced by this match template would also have the same `id="foo"` attribute. |
| 654 | |
| 655 | {{{ |
| 656 | #!genshi |
| 657 | <title py:with="title = list(select('title/text()'))"> |
| 658 | geddit<py:if test="title">: ${title}</py:if> |
| 659 | </title> |
| 660 | }}} |
| 661 | |
| 662 | This is a more complex example for selecting matched content: it fetches the text contained in the `<title>` element of the original `<head>` and prefixes it with the string “geddit: ”. But as page templates may not even contain a `<title>` element, we first check whether it exists, and only add the colon if it does. Thus, if the page has no title of its own, the result will be “geddit”. |
| 663 | |
| 664 | {{{ |
| 665 | #!genshi |
| 666 | ${select('*[local-name()!="title"]')} |
| 667 | }}} |
| 668 | |
| 669 | Finally, this is an example for using a more complex XPath pattern. This `select()` incantation here returns a stream that contains all child elements of the original `<head>`, except for those elements that have the local name “title”. If we didn't add that predicate, the output stream would contain two `<title>` tags, and we don't want that. |
| 670 | |
| 671 | If you've done a bit of XSLT, match templates should look familiar. Otherwise, you may want to familiarize yourself with the basics of XPath 1—note though that Genshi only implements a subset of the full spec as explained in [wiki:Documentation/xpath.html Using XPath in Genshi]. And just play around with match templates; at the core, the concept is actually very simple and consistent. |