## ## WML Tutorial ## Copyright (c) 1997 Ralf S. Engelschall, All Rights Reserved. ## =head1 NAME WML Tutorial - Understanding WML step-by-step =head1 DESCRIPTION This tutorial gives you a step-by-step introduction to the features of WML, separated into tiny lessons. Each lesson shows one particular aspect or feature of WML. The order of lessons go from easy and trivial to hard and complex. =head1 IMPLICIT MARKUP PROCESSING =head2 LESSON: Plain Data Throughput In this lesson we first learn that WML is 95% of the time transparent to its input, i.e. we can pass through any data without corruption. Input: 1| foo 2| 3| quux Output: 1| foo 2| 3| quux This is because per default there are neither definitions for symbols C or C nor a defined HTML tag named CbarE>. And because there are no unnecessary whitespaces in this example, the input cannot be stripped in any case. =head2 LESSON: Protected Markup Code Sometimes situations can occur where some of your markup code or page contents conflicts with WML due to overlapping tagnames, etc. Here WML interprets some stuff you actually don't want to be interpreted. Input: 1| foo: foo.c 2| $(CC) -o foo foo.c Output: 1| foo: foo.c 2| -o foo foo.c Here the `C<$(CC)>' was expanded to an empty string because IPP uses the same syntax for variable interpolation like F. To avoid this just surround the critical part with the WML-internal CprotectE> container tag. Input: 1| foo: foo.c 2| $(CC) -o foo foo.c Output: 1| foo: foo.c 2| $(CC) -o foo foo.c =head2 LESSON: Stripped-Down Markup Code Now let's try an example which has unnecessary whitespaces. Be careful, `unnecessary' here means they can be stripped as long as the resulting Webpage displays the same in a Webbrowser as the original. Input: 1| 2| 3|   test  4|
 5|
 6|     Preformatted          Text  
 7| 
8| Not Preformatted Text 9| Output: 1| 2|  test 4|
 5|
 6|     Preformatted          Text  
 7| 
8| Not Preformatted Text 9| Here we see that line 2 is completely removed because empty lines have no effect in HTML. The whitespaces between the attribute C and its value are removed, too. And all double whitespaces are replaced by a single whitespace character. But not inside preformatted areas. =head2 LESSON: Fixed And Adjusted Markup Code Now assume that we have an F file containing a GIF image with a size of 500x400 pixels and the following input page: 1| 2|
3| Headline:
4| 5|
6| Although this is valid HTML code, WML can enhance it to make it more portable, speed up it rendering in the Webbrowser and make I users more happy. So WML recognizes the CimgE> tag and automatically adds missing information and replaces obsolete tags with up-to-date variants: 1| 2|
3| Headline:
4| 5|
6| As you can see, WML first replaced the proprietary CcenterE> tag with the HTML 3.2 pedant Cdiv align=centerE>, second it fixed the C attribute of CfontE>. And third it added missing C and C/C attributes. =head1 STRUCTURING THE MARKUP CODE =head2 LESSON: Using Include Files One of the most useful features of WML is the ability to move commonly used stuff into include files which can be selectively read in at later steps. Assume we have an include file F... 1| bar 2| The value of bar is: $(bar:-unknown) ...and the following input file: 1| foo 3| #include 'bar.wml' bar="FooBar" 2| #include 'bar.wml' 5| quux Then the output is: 1| foo 2| bar 3| The value of bar is: Foobar 4| bar 5| The value of bar is: unknown 6| quux As you can see, the C<#include> directive is replaced by the contents of the corresponding file. And this included contents can contain variables which are interpolated when they are defined, inclusive default values. There is also a way to create simple constructs similar to an if-then-else just by using variable interpolation: 1| The value of bar is $(bar:+set)$(bar:*unset). Here the `C<$(bar:+set)$(bar:*unset)>' construct emulates the following semantics: if (isdefined(bar)) expandto("set") if (not isdefined(bar)) expandto("unset") =head2 LESSON: Concatenating Lines Although HTML usually does not care about whitespaces and newlines, sometimes it is very frustrating to create preformatted areas or write own tags (see later) without the ability to spread the code over more than one line while it should be actually one single line. For this a lot of languages use a line concatenation/continuation character `C<\>', as does WML. Input: 1| foo\ 2| bar \ 3| quux Output: 1| foobar quux The line concatenation strips whitespaces from the begin of concatenated lines but preserves whitespaces at the end of them, i.e. you can use leading whitespaces for structuring your input nicely but still use appended whitespaces for real ones. =head2 LESSON: Diverting To Locations One of the most powerful features of WML is the ability to I data at any point to I defined at any other point. Input: 1| {#BAR#:this is:##} 2| foo 3| {#BAR#} 4| quux 5| {#BAR#: bar:##} 6| foobar 7| {#BAR#} Output: 1| foo 2| this is bar 3| quux 4| foobar 5| this is bar Here in line 3 the location C is already dumped, but filled at lines 1 and 5. And as you can see a location can be dumped at any point and even more than once. And you can accumulate the contents for a location by subsequent fills (line 1 and 5). This works because in WML first all locations are filled in a first pass and then dumped in a second pass. With the use of the high-level tags from F we also could write the example above in a little bit more human readable way: 1| #use wml::std::tags 2| this is 3| foo 4| 5| quux 6| bar 7| foobar 8| =head2 LESSON: Defining Output Slices Often one needs more than one output file. Usually although 90% of the contents is the same, one needs a way to select the remaining 10%. WML's approach here is to write these 10% directly in the input file but separate the variants by defining I which later can be used to create the different output files. 1| 2| 3| [EN:Titleline:][DE:Titelzeile:] 4| 5| 6|

[EN:Headerline:][DE:Ueberschrift:]

7| 8| Now assume the above page is in file F, then the command $ wml -o UNDEF+EN:index.html.en \ -o UNDEF+DE:index.html.de index.wml generates the output file C containing the union of all undefined areas and the slices `C'... 1| 2| 3| Titleline 4| 5| 6|

Headerline

7| 8| ...and the output file C containing the union of all undefined areas and the slices `C': 1| 2| 3| Titelzeile 4| 5| 6|

Ueberschrift

7| 8| =head1 FORMATTING =head2 LESSON: Area Substitution WML provides an area substitution feature which works by specifying the begin and end of the area and inserting some Perl substitution and translation commands. Input: 1| foo 2| {: [[s/foo/bar/g]] [[s/quux/foobar/g]] [[tr/[a-z]/[A-Z]/]] 3| this is foo and quux. 4| :} 5| quux Output: 1| foo 2| THIS IS BAR AND FOOBAR. 3| quux Because this seems useless, we go further and show an example of the CisolatinE> and CurlE> container tags from F and F which are programmed this way. Input: 1| #use wml::fmt::isolatin 2| #use wml::fmt::url 3| 4| Some umlauts `öäüÖÄß' and 5| a hyperlink http://foo.bar.com/ 6| Output: 1| Some umlauts `öäüÖÄß' and 2| a hyperlink http://foo.bar.com/ =head2 LESSON: Text Formatting HTML sucks when it comes to write more than one paragraph of text. So WML provides nice ways to format an area of input via other (externally available) markup language processors. Here is an example which used two embedded areas, the first one is written in I (POD) format, second one is written in I (SDF). Input: 1| #use wml::fmt::pod 2| #use wml::fmt::sdf 3| 4| 5| =head1 Headline1 6| 7| Foo 8| 9| =head2 Headline1.1 10| 11| Bar 12| 13| 14| 15| H1: Headline1 16| 17| Foo 18| 19| H2: Headline 1.1 20| 21| Bar 22| * Baz 23| - Foobar 24| - Quux 25| * Foo 26| 27| Output: 1| 2|

3|

Headline1 4|

5| Foo 6|

7|

Headline1.1 8|

9| Bar 10|

11|

1. Headline1

12|

Foo

13|

1.1. Headline 1.1

14|

Bar

15|
    16|
  • Baz
      17|
    • Foobar 18|
    • Quux
    19|
  • Foo
20| =head2 LESSON: Table Formatting Another point where the HTML markup code is unproductive and ugly is when it comes to write some CtableE> structures. Here WML provides two new container tags which make your live easier: =over 4 =item BgridE> The goal of this container tag is to provide a way to specify tables the same way you have it in your mind, i.e. as a 2-dimensional grid. So, a grid is created by specifying a grid-layout and then fill its cells. Additionally the CgridE> container tag provides a nice feature for specifying the cell alignments. Input: 1| #use wml::std::grid 2| 3| Header 1 Header 2 4| Cell-A Cell-B 5| Cell-C Cell-D 6| Output: 1| 2| 3| 4| 5| 6| 7| 8| 9| 10| 11| 12| 13| 14|
Header 1Header 2
Cell-ACell-B
Cell-CCell-D
=item BxtableE> This is the extended CtableE> container tag which syntax is provided by the external F program. Its goal is to provide a compact syntax for specifying a table. Again the same example: Input: 1| #use wml::fmt::xtable 2| 3| (*, 1) align=left 4| (*, 2) align=right 5| (1, *) valign=top 6| (2|3, *) valign=bottom 7| (1,1) 8| Header 1 9| (1,2) 10| Header 2 11| (2,1) 12| Cell-A 13| (2,2) 14| Cell-B 15| (3,1) 16| Cell-C 17| (3,2) 18| Cell-D 19| Output: 1| 2| 3| 4| 5| 6| 7| 8| 9| 10| 11| 12| 13| 14|
Header 1Header 2
Cell-ACell-B
Cell-CCell-D
=back =head1 DEFINITION OF OWN HTML TAGS =head2 LESSON: Simple Tags And Container Tags Now it is time to enhance our markup language by defining new custom HTML tags. There are two types of HTML tags: =over 4 =item B As an example let us define a CmeE> tag which expands to my name abbreviation. Input: 1| 2| rse@engelschall.com 3| 4| 5| This is . Output: 1| This is rse@engelschall.com. =item B As an example let us define a CredE> tag which changes its body text color to red. Input: 1| 2| %body 3| 4| 5| This is very important. Output: 1| This is very important. =back =head2 LESSON: Tags With Attributes Because tags without attributes are not very flexible there is also a way to define tags which can use these. Input: 1| 2| 3| 4| 5| 6| 7| 8| 9| 10| This is and . Output: 1| This is rse@engelschall.com and rse@apache.org. There is also a variant to use attributes of type C: Input: 2| 3| 4| 5| " "" "rse@engelschall.com"> 6| " "engelschall" "rse@engelschall.com"> 7| " "netsw" "rse@netsw.org"> 8| " "apache" "rse@apache.org"> 9| " "freebsd" "rse@freebsd.org"> 10| " "sdm" "rse@sdm.de"> 11| 12| 13| 14| This is and . Output: 1| This is rse@engelschall.com and rse@apache.org. =head2 LESSON: Overwriting Existing HTML Tags WML also provides a way to overwrite existing HTML tags, i.e. you can define a custom tag with the same name as an already known HTML tag and use the original HTML tag inside it. Input: 1| 2| 4| 5| 6| Some Text
7| Some more Text Output: 1| Some Text

2| Some more Text =head2 LESSON: Programming Tags In Perl One of the essential features in WML is that you can embed Perl code at any point, just marked with `C:>' and `C<:E>' delimiters. This can be combined with the tag definitions by programming tags in Perl. Input: 1| #use wml::std::tags 2| 3| 4| 5| <:{ 6| my $at = qq//; 7| my $addr; 8| $addr = "rse\@engelschall.com" if $at eq ''; 9| $addr = "rse\@engelschall.com" if $at eq 'engelschall'; 10| $addr = "rse\@netsw.org" if $at eq 'netsw'; 11| $addr = "rse\@apache.org" if $at eq 'apache'; 12| $addr = "rse\@freebsd.org" if $at eq 'freebsd'; 13| $addr = "rse\@sdm.de" if $at eq 'sdm'; 14| print $addr; 15| }:> 16| 17| 18| 19| This is and . Output: 1| This is rse@engelschall.com and rse@apache.org. =head1 ADVANCED FEATURES =head2 LESSON: Using Templates We've already seen how to divert data to a location. Because WML automatically closes still opened diversions at EndOfFile, we can use this feature to create templates. Assume we have the following template defined in the file F. 1| # the template itself 2| 3| 4| {#SUBJECT_LOC#} 5| 6| 7|

{#SUBJECT_LOC#}

8|
9| {#BODY#} 10|
11| 12| 13| 14| # way to insert the subject 15| 16| {#SUBJECT_LOC#:%0:##} 17| 18| 19| # per default we are in body 20| {#BODY#: Input: 1| #include 'template.wml' 2| 3| 4| 5| This is about Foo, Bar and Quux... Output: 1| 2| 3| Foo, Bar and Quux 4| 5| 6|

Foo, Bar and Quux

7|
8| This is about Foo, Bar and Quux... 9|
10| 11| You can even nest more than one template because the diversion mechanism in WML accepts location dumps and location fills at any point, even within other location fills. =head2 LESSON: Creating Multi-Lingual Pages The core languages of WML don't provide a dedicated facility to create multi-lingual pages, i.e. one or more output pages created out of a single input source, each one containing the same page information but in different human languages. But WML provides variants through ``slicing'' (Pass 9) and human languages are just a special case of general variants. So wml::std::lang exists which provides specialized multi-lingual support tags which are mapped to slices which then can be used to create the various output files. Let take an example: 1| #!wml -o (ALL-LANG_*)+LANG_EN:index.en.html \ 2| -o (ALL-LANG_*)+LANG_DE:index.de.html 3| 4| #use wml::std::page 5| #use wml::std::lang 6| 7| 8| 9| 10| 11| 12|

!

13| 14| Index 2 15| 16| 17| (en)This is a test page 18| (de)Dies ist eine Testseite 19| After processing passes 1 to 8 (C) the following is internally generated by WML: 1| 2| 3| 4| 5|

[LANG_EN:Welcome:][LANG_DE:Willkommen:]!

6| Index 2 7| [LANG_EN:This is a test page 8| :][LANG_DE:Dies ist eine Testseite:] 9| 10| And then after processing pass 9 with the initial WML magic cookie line (C<#!wml -o...>) the following two files are generated: index.en.html: 1| 2| 3| 4| 5|

Welcome!

6| Index 2 7| This is a test page 8| 9| 10| index.de.html: 1| 2| 3| 4| 5|

Willkommen!

6| Index 2 7| Dies ist eine Testseite 8| 9| And these two pages then can be served by a content negotiation feature of the webserver or by explicit references. =head1 MORE INFORMATION Now you've seen the various core languages of WML in action. For the gory details of what each language provides either read the all-in-one WML Introduction in wml_intro(7) or step through the particular manpages of the core languages. Start here with the frontend wml(1). Additionally can can step through the set of available standard include files WML ships with. Start with the top-level include file wml::all(3). =head1 SEEALSO wml_intro(7) wml_p1_ipp(1), wml_p2_mp4h(1), wml_p3_eperl(1), wml_p4_gm4(1), wml_p5_divert(1), wml_p6_asubst(1), wml_p7_htmlfix(1), wml_p8_htmlstrip(1), wml_p9_slice(1). wml::all(3) =cut ##EOF##