NAME¶
WML Tutorial - Understanding WML step-by-step
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.
IMPLICIT MARKUP PROCESSING¶
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| <bar>
3| quux
Output:
1| foo
2| <bar>
3| quux
This is because per default there are neither definitions for symbols
"foo" or "quux" nor a defined HTML tag named
"<bar>". And because there are no unnecessary whitespaces in
this example, the input cannot be stripped in any case.
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 `"$(CC)"' was expanded to an empty string because IPP uses
the same syntax for variable interpolation like
make. To avoid this
just surround the critical part with the WML-internal
"<protect>" container tag.
Input:
1| foo: foo.c
2| <protect>$(CC)</protect> -o foo foo.c
Output:
1| foo: foo.c
2| $(CC) -o foo foo.c
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| <body>
2|
3| <img src = "file.gif" alt=" test " >
4| <pre>
5|
6| Preformatted Text
7| </pre>
8| Not Preformatted Text
9| </body>
Output:
1| <body>
2| <img src="file.gif" alt=" test ">
4| <pre>
5|
6| Preformatted Text
7| </pre>
8| Not Preformatted Text
9| </body>
Here we see that line 2 is completely removed because empty lines have no effect
in HTML. The whitespaces between the attribute "src" and its value
are removed, too. And all double whitespaces are replaced by a single
whitespace character. But not inside preformatted areas.
LESSON: Fixed And Adjusted Markup Code¶
Now assume that we have an
image.gif file containing a GIF image with a
size of 500x400 pixels and the following input page:
1| <body>
2| <center>
3| <font color=336699>Headline:</font><br>
4| <img src="image.gif">
5| </center>
6| </body>
Although this is valid HTML code, WML can enhance it to make it more portable,
speed up it rendering in the Webbrowser and make
Lynx users more happy.
So WML recognizes the "<img>" tag and automatically adds
missing information and replaces obsolete tags with up-to-date variants:
1| <body>
2| <div align=center>
3| <font color="#336699">Headline:</font><br>
4| <img src="image.gif" alt="" width="500" height="400">
5| </div>
6| </body>
As you can see, WML first replaced the proprietary "<center>"
tag with the HTML 3.2 pedant "<div align=center>", second it
fixed the "color" attribute of "<font>". And third
it added missing "alt" and "width"/"height"
attributes.
STRUCTURING THE MARKUP CODE¶
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
bar.wml...
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 "#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 `"$(bar:+set)$(bar:*unset)"' construct emulates the following
semantics:
if (isdefined(bar))
expandto("set")
if (not isdefined(bar))
expandto("unset")
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 `"\"', 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.
LESSON: Diverting To Locations¶
One of the most powerful features of WML is the ability to
divert data at
any point to
locations 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 "BAR" 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
wml::std::tags we also could
write the example above in a little bit more human readable way:
1| #use wml::std::tags
2| <divert BAR>this is</divert>
3| foo
4| <dump BAR>
5| quux
6| <divert BAR> bar</divert>
7| foobar
8| <dump BAR>
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
slices which later can be used to create the different output
files.
1| <html>
2| <head>
3| <title>[EN:Titleline:][DE:Titelzeile:]</title>
4| </head>
5| <body>
6| <h1>[EN:Headerline:][DE:Ueberschrift:]</h1>
7| </body>
8| </html>
Now assume the above page is in file
index.wml, then the command
$ wml -o UNDEF+EN:index.html.en \
-o UNDEF+DE:index.html.de index.wml
generates the output file "index.html.en" containing the union of all
undefined areas and the slices `"EN"'...
1| <html>
2| <head>
3| <title>Titleline</title>
4| </head>
5| <body>
6| <h1>Headerline</h1>
7| </body>
8| </html>
...and the output file "index.html.de" containing the union of all
undefined areas and the slices `"DE"':
1| <html>
2| <head>
3| <title>Titelzeile</title>
4| </head>
5| <body>
6| <h1>Ueberschrift</h1>
7| </body>
8| </html>
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
"<isolatin>" and "<url>" container tags from
wml::fmt::isolatin and
wml::fmt::url which are programmed this
way.
Input:
1| #use wml::fmt::isolatin
2| #use wml::fmt::url
3| <isolatin><url>
4| Some umlauts `oeaeueOeAess' and
5| a hyperlink http://foo.bar.com/
6| </url></isolatin>
Output:
1| Some umlauts `öäüÖÄß' and
2| a hyperlink <a href="http://foo.bar.com/">http://foo.bar.com/</a>
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
Plain Old Document (POD) format, second one
is written in
Simple Document Format (SDF).
Input:
1| #use wml::fmt::pod
2| #use wml::fmt::sdf
3| <html>
4| <pod notypo>
5| =head1 Headline1
6|
7| Foo
8|
9| =head2 Headline1.1
10|
11| Bar
12| </pod>
13|
14| <sdf notypo>
15| H1: Headline1
16|
17| Foo
18|
19| H2: Headline 1.1
20|
21| Bar
22| * Baz
23| - Foobar
24| - Quux
25| * Foo
26| </sdf>
27| </html>
Output:
1| <html>
2| <P>
3| <H1><A NAME="Headline1">Headline1
4| </A></H1>
5| Foo
6| <P>
7| <H2><A NAME="Headline1_1">Headline1.1
8| </A></H2>
9| Bar
10| <P>
11| <H1><A NAME="Headline1">1. Headline1</A></H1>
12| <P>Foo</P>
13| <H2><A NAME="Headline 1.1">1.1. Headline 1.1</A></H2>
14| <P>Bar</P>
15| <UL>
16| <LI>Baz<UL>
17| <LI>Foobar
18| <LI>Quux</UL>
19| <LI>Foo</UL>
20| </html>
Another point where the HTML markup code is unproductive and ugly is when it
comes to write some "<table>" structures. Here WML provides
two new container tags which make your live easier:
- <grid>
- 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 "<grid>" container
tag provides a nice feature for specifying the cell alignments.
Input:
1| #use wml::std::grid
2| <grid layout=2x3 align=lr valign=tbb border=1>
3| <cell>Header 1</cell> <cell>Header 2</cell>
4| <cell>Cell-A</cell> <cell>Cell-B</cell>
5| <cell>Cell-C</cell> <cell>Cell-D</cell>
6| </grid>
Output:
1| <table border="1" cellspacing="0" cellpadding="0">
2| <tr>
3| <td align=left valign=top>Header 1</td>
4| <td align=right valign=top>Header 2</td>
5| </tr>
6| <tr>
7| <td align=left valign=bottom>Cell-A</td>
8| <td align=right valign=bottom>Cell-B</td>
9| </tr>
10| <tr>
11| <td align=left valign=bottom>Cell-C</td>
12| <td align=right valign=bottom>Cell-D</td>
13| </tr>
14| </table>
- <xtable>
- This is the extended "<table>" container
tag which syntax is provided by the external freetable program. Its
goal is to provide a compact syntax for specifying a table. Again the same
example:
Input:
1| #use wml::fmt::xtable
2| <xtable border=1>
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| </xtable>
Output:
1| <table border="1">
2| <tr valign=top>
3| <td align=left>Header 1</td>
4| <td align=right>Header 2</td>
5| </tr>
6| <tr>
7| <td align=left valign=bottom>Cell-A</td>
8| <td align=right valign=bottom>Cell-B</td>
9| </tr>
10| <tr>
11| <td align=left valign=bottom>Cell-C</td>
12| <td align=right valign=bottom>Cell-D</td>
13| </tr>
14| </table>
Now it is time to enhance our markup language by defining new custom HTML tags.
There are two types of HTML tags:
- Simple Tags
- As an example let us define a "<me>" tag
which expands to my name abbreviation.
Input:
1| <define-tag me whitespace=delete>
2| rse@engelschall.com
3| </define-tag>
4|
5| This is <me>.
Output:
1| This is rse@engelschall.com.
- Container Tags
- As an example let us define a "<red>" tag
which changes its body text color to red.
Input:
1| <define-tag red endtag=required whitespace=delete>
2| <font color="#cc3333">%body</font>
3| </define-tag>
4|
5| This is <red>very important</red>.
Output:
1| This is <font color="#cc3333">very important</font>.
Because tags without attributes are not very flexible there is also a way to
define tags which can use these.
Input:
1| <define-tag me whitespace=delete>
2| <if "%0" "" "rse@engelschall.com">
3| <ifeq "%0" "engelschall" "rse@engelschall.com">
4| <ifeq "%0" "netsw" "rse@netsw.org">
5| <ifeq "%0" "apache" "rse@apache.org">
6| <ifeq "%0" "freebsd" "rse@freebsd.org">
7| <ifeq "%0" "sdm" "rse@sdm.de">
8| </define-tag>
9|
10| This is <me> and <me apache>.
Output:
1| This is rse@engelschall.com and rse@apache.org.
There is also a variant to use attributes of type "name=value":
Input:
2| <define-tag me whitespace=delete>
3| <preserve at>
4| <set-var %attributes>
5| <if "<get-var at>" "" "rse@engelschall.com">
6| <ifeq "<get-var at>" "engelschall" "rse@engelschall.com">
7| <ifeq "<get-var at>" "netsw" "rse@netsw.org">
8| <ifeq "<get-var at>" "apache" "rse@apache.org">
9| <ifeq "<get-var at>" "freebsd" "rse@freebsd.org">
10| <ifeq "<get-var at>" "sdm" "rse@sdm.de">
11| <restore at>
12| </define-tag>
13|
14| This is <me> and <me at=apache>.
Output:
1| This is rse@engelschall.com and rse@apache.org.
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| <define-tag br whitespace=delete>
2| <br*><br*>
4| </define-tag>
5|
6| Some Text<br>
7| Some more Text
Output:
1| Some Text<br><br>
2| Some more Text
One of the essential features in WML is that you can embed Perl code at any
point, just marked with `"<:"' and `":>"'
delimiters. This can be combined with the tag definitions by programming tags
in Perl.
Input:
1| #use wml::std::tags
2| <define-tag me whitespace=delete>
3| <preserve at>
4| <set-var %attributes>
5| <:{
6| my $at = qq/<get-var at>/;
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| <restore at>
17| </define-tag>
18|
19| This is <me> and <me at=apache>.
Output:
1| This is rse@engelschall.com and rse@apache.org.
ADVANCED FEATURES¶
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
template.wml.
1| # the template itself
2| <html>
3| <head>
4| <title>{#SUBJECT_LOC#}</title>
5| </head>
6| <body>
7| <h1>{#SUBJECT_LOC#}</h1>
8| <blockquote>
9| {#BODY#}
10| </blockquote>
11| </body>
12| </html>
13|
14| # way to insert the subject
15| <define-tag subject>
16| {#SUBJECT_LOC#:%0:##}
17| </define-tag>
18|
19| # per default we are in body
20| {#BODY#:
Input:
1| #include 'template.wml'
2|
3| <subject "Foo, Bar and Quux">
4|
5| This is about Foo, Bar and Quux...
Output:
1| <html>
2| <head>
3| <title>Foo, Bar and Quux</title>
4| </head>
5| <body>
6| <h1>Foo, Bar and Quux</h1>
7| <blockquote>
8| This is about Foo, Bar and Quux...
9| </blockquote>
10| </body>
11| </html>
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.
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| <lang:new id=en short>
8| <lang:new id=de short>
9|
10| <page>
11|
12| <h1><en: Welcome><de: Willkommen>!</h1>
13|
14| <a href="<lang:star: index2.*.html>">Index 2</a>
15|
16| <lang:area>
17| (en)This is a test page
18| (de)Dies ist eine Testseite
19| </lang:area>
After processing passes 1 to 8 ("wml -p1-8") the following is
internally generated by WML:
1| <html>
2| <head>
3| </head>
4| <body bgcolor="#ffffff" text="#000000" link="#333399" alink="#9999ff" vlink="#000066">
5| <h1>[LANG_EN:Welcome:][LANG_DE:Willkommen:]!</h1>
6| <a href="[LANG_EN:index2.en.html:][LANG_DE:index2.de.html:]">Index 2</a>
7| [LANG_EN:This is a test page
8| :][LANG_DE:Dies ist eine Testseite:]
9| </body>
10| </html>
And then after processing pass 9 with the initial WML magic cookie line
("#!wml -o...") the following two files are generated:
index.en.html:
1| <html>
2| <head>
3| </head>
4| <body bgcolor="#ffffff" text="#000000" link="#333399" alink="#9999ff" vlink="#000066">
5| <h1>Welcome!</h1>
6| <a href="index2.en.html">Index 2</a>
7| This is a test page
8|
9| </body>
10| </html>
index.de.html:
1| <html>
2| <head>
3| </head>
4| <body bgcolor="#ffffff" text="#000000" link="#333399" alink="#9999ff" vlink="#000066">
5| <h1>Willkommen!</h1>
6| <a href="index2.de.html">Index 2</a>
7| Dies ist eine Testseite
8| </body>
9| </html>
And these two pages then can be served by a content negotiation feature of the
webserver or by explicit references.
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).
SEE ALSO¶
wml_intro(7)
wml_p1_ipp(3),
mp4h(1),
eperl(1),
m4(1),
wml_p5_divert(3),
wml_p6_asubst(3),
wml_p7_htmlfix(3),
wml_p8_htmlstrip(3),
slice(1).
wml::all(3)