WebMetaLecture - a lecture about Website Meta Language


1. Introduction


2. Why Static HTML?

Why Static HTML?

Server-side-generated HTML is:

  1. Necessarily slower than static HTML.
  2. Prune to bugs, security holes and security breaches. (eval($q->param("code")) anyone?)
  3. For many sites, whose content does not change very often, it is completely unnecessary.

Static HTML Done Right

Maintaining static HTML by hand is painful. Usually it creates crammy sites, which either don't have a navigation bar or have one that has to be maintained across all pages. Some sites put all the pages into one directory to simplify cross-referencing them. Cascading Style Sheets can help a bit here, but they are not a panacea.

Another option is to use WYSIWYG Content-Management Systems such as Microsoft FrontPage. This is known to create bloated or browser-dependant HTML, and you are often limited by the functionality that was built into the CMS.

Yet another option is to create your own ad-hoc content management system. (e.g: a perl script that will render your pages) However, this will have to be extended in time, and you'll probably invent something that is not as good as Website Meta Language which is already very mature and complete. I remember writing something like that myself in PHP for an older incarnation of the IGLU site, and know other people who created similar solutions for their own need. None of them was as good or as versatile as Website Meta Language.

Finally, Website Meta Language and pre-rendered XSL stylesheets give you fine control on the HTML generated while allowing you to do anything Turing Complete. Website Meta Language has been around longer than XSL. By virtue of integrating Perl it can do anything Perl does, while XSL is a virtual machine without much capabilities of interaction with the outside world. I also think WML has a better human-factors engineering, but that's a matter of state.


3. The WML Methodology

  1. Source Reading and Include File Expansion (ipp)
  2. HTML Macro Construct Expansion (mp4h) (Meta-tags, conditionals, etc)
  3. Perl 5 Programming Construct Expansion (eperl)
  4. M4 Macro Construct Expansion (gm4)
  5. Diversion Filter (divert) - diverting text to different locations
  6. Character and String Substitution (asubst)
  7. HTML Fix-up (htmlfix)
  8. Line Stripping and Output Fix-up (htmlstrip)
  9. Output Splitting and Final Writing (slice)

4. HTML is WML!


5. Example 1 : Common Look and Feel


5.1. The Template File

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
<head>
<title>{#SUBJECT_LOC#}</title>
<meta charset="utf-8" />
<link rel="stylesheet" href="$(ROOT)/style.css" type="text/css" />
</head>
<body>

<table class="layout">
<tr>
<td class="navbar">
<a href="$(ROOT)/">Main</a><br />
<a href="$(ROOT)/download.html">Download</a><br />
<a href="$(ROOT)/links.html">Links</a><br />
<br />
<a href="mailto:webmaster@mysite.org">Webmaster</a><br />
</td>
<td class="main">
<h1>{#SUBJECT_LOC#}</h1>
{#BODY#}
</td>
</tr>
</table>

</body>
</html>

<define-tag subject>
{#SUBJECT_LOC#:%0:##}
</define-tag>

#   per default we are in body
{#BODY#:

5.2. The Individual Pages

index.html.wml

#include 'template.wml'

<subject "Foo Site" />

<p>
Welcome visitors to my humble site. You can find downloads in the
<a href="$(ROOT)/download.html">downloads section</a> and links in the
<a href="$(ROOT)/links.html">links section</a>.
</p>

links.html.wml

#include 'template.wml'

<subject "Links" />

<p>
<a href="http://linuxclub.il.eu.org/">The Haifa Linux Club</a>
</p>

<p>
<a href="http://www.google.com/">Google</a>
</p>

<p>
<a href="http://thewml.org/">The Website Meta Language</a>
</p>

download.html.wml

#include 'template.wml'

<subject "Downloads" />

<p>
<a href="my-non-existent-archive.tar.gz">A polynomial solution for the
travelling salesman problem.</a>
</p>

<p>
<a href="my-document.pdf">Proof of the Goldbach Conjecture</a>
</p>

Explanation


5.3. The Makefile

D = dest

TARGETS = $(D)/index.html $(D)/links.html $(D)/download.html
IMAGES = $(D)/style.css

all: $(TARGETS) $(IMAGES)

# This flag makes sure WML generates XHTML output
WML_FLAGS = --passoption=2,-X

# This flag sets ROOT to be the current directory
WML_FLAGS += -D ROOT~.

$(TARGETS) :: $(D)/% : %.wml template.wml
	wml $(WML_FLAGS) -DFILENAME="$(notdir $@)" $< > $@

$(IMAGES) :: $(D)/% : %
	cp -f $< $@

5.4. The Final Site

Check here .


6. Example 2 : Bolding the NavBar entry of the Existing Page


6.1. The New Template File

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
<head>
<title>{#SUBJECT_LOC#}</title>
<meta charset="utf-8" />
<link rel="stylesheet" href="$(ROOT)/style.css" type="text/css" />
</head>
<body>

<table class="layout">
<tr>
<td class="navbar">
<ifneq "$(FILENAME)" "index.html"
    "<a href="$(ROOT)/">Main</a>"
    "<b>Main</b>"
    />
<br />
<ifneq "$(FILENAME)" "download.html"
    "<a href="$(ROOT)/download.html">Download</a>"
    "<b>Download</b>"
    />
<br />
<ifneq "$(FILENAME)" "links.html"
    "<a href="$(ROOT)/links.html">Links</a>"
    "<b>Links</b>"
    />
<br />

<br />

<a href="mailto:webmaster@mysite.org">Webmaster</a><br />
</td>
<td class="main">
<h1>{#SUBJECT_LOC#}</h1>
{#BODY#}
</td>
</tr>
</table>

</body>
</html>

<define-tag subject>
{#SUBJECT_LOC#:%0:##}
</define-tag>

#   per default we are in body
{#BODY#:

Explanation

<ifneq ...> compares its first two arguments - if they are not equal, it expands to its third argument, else it expands to its fourth. There's also <ifeq ... >.


6.2. The New Final Site

Check here .


7. Example 3 : Creating a Meta-Tag


7.1. The New Template File

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
<head>
<title>{#SUBJECT_LOC#}</title>
<meta charset="utf-8" />
<link rel="stylesheet" href="$(ROOT)/style.css" type="text/css" />
</head>
<body>

<table class="layout">
<tr>
<td class="navbar">

<define-tag navbarlink>
<if
    ;;; Determine if %0 matches this document
    <ifeq "$(FILENAME)" "%0"
        "1"
        <ifeq "$(FILENAME)" "%0index.html"
            "1"
            ""
        />

    />
    ;;; If so - bolds the text
    "<b>%1</b>"
    ;;; If not - makes a hyperlink
    "<a href="$(ROOT)/%0">%1</a>"
/><br />
</define-tag>

<navbarlink "" "Main" />
<navbarlink "download.html" "Downloads" />
<navbarlink "links.html" "Links" />

<br />

<a href="mailto:webmaster@mysite.org">Webmaster</a><br />
</td>
<td class="main">
<h1>{#SUBJECT_LOC#}</h1>
{#BODY#}
</td>
</tr>
</table>

</body>
</html>

<define-tag subject>
{#SUBJECT_LOC#:%0:##}
</define-tag>

#   per default we are in body
{#BODY#:

Explanation


7.2. The Final Site

Check here .


8. Example 4 : Frames-Enabled and Non-Frames-Enabled Sites


8.1. The Modified Makefile

D = dest

TARGETS = $(D)/index.html $(D)/links.html $(D)/download.html
IMAGES = $(D)/style.css $(D)/frames.html

all: $(TARGETS) $(IMAGES) $(D)/navbar-frame.html

# This flag makes sure WML generates XHTML output
WML_FLAGS = --passoption=2,-X

# This flag sets ROOT to be the current directory
WML_FLAGS += -D ROOT~.

$(D)/navbar-frame.html : navbar-frame.html.wml
	wml $(WML_FLAGS) -o $@ $<

$(TARGETS) :: $(D)/% : %.wml template.wml
	wml $(WML_FLAGS) -o UNDEF+NOFRAMES:$@ -o UNDEF+FRAMES:$@.frames.html -DFILENAME="$(notdir $@)" $<

$(IMAGES) :: $(D)/% : %
	cp -f $< $@

Explanation

From each file we generate two files. One with a regular extension in which the slice NOFRAMES is defined. The other with a .frames.html extension with the slice FRAMES defined.


8.2. New File: navbar.wml

<navbarlink "" "Main" />
<navbarlink "download.html" "Downloads" />
<navbarlink "links.html" "Links" />

<br />

<a href="mailto:webmaster@mysite.org">Webmaster</a><br />

8.3. The Modified Template

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
<head>
<title>{#SUBJECT_LOC#}</title>
<meta charset="utf-8" />
<link rel="stylesheet" href="$(ROOT)/style.css" type="text/css" />
</head>
<body>

[FRAMES::]
[NOFRAMES:
<table class="layout">
<tr>
<td class="navbar">

<define-tag navbarlink>
<if
    ;;; Determine if %0 matches this document
    <ifeq "$(FILENAME)" "%0"
        "1"
        <ifeq "$(FILENAME)" "%0index.html"
            "1"
            ""
        />

    />
    ;;; If so - bolds the text
    "<b>%1</b>"
    ;;; If not - makes a hyperlink
    "<a href="$(ROOT)/%0">%1</a>"
/><br />
</define-tag>

#include 'navbar.wml'

<br />
<a href="$(ROOT)/frames.html">Frames Enabled Site</a><br />

</td>
<td class="main">
:]
<h1>{#SUBJECT_LOC#}</h1>
{#BODY#}
[FRAMES::]
[NOFRAMES:
</td>
</tr>
</table>
:]
</body>
</html>

<define-tag subject>
{#SUBJECT_LOC#:%0:##}
</define-tag>

#   per default we are in body
{#BODY#:

Explanation


8.4. navbar-frame.html.wml

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
<head>
<title>Navigation Bar</title>
<meta charset="utf-8" />
<link rel="StyleSheet" href="$(ROOT)/style.css" />
</head>
<body>
<define-tag navbarlink>
# Check if we are an index page and define suffix accordingly
<if <match "%0" "(/$)|(^$)" action="report" />
    <set-var suffix="index.html" />
    <set-var suffix="" />
    />
<a href="%0<get-var suffix />.frames.html">%1</a>
<br />
</define-tag>

<p>
#include 'navbar.wml'

<br />
<a href="$(ROOT)">No Frames Version</a><br />
</p>

</body>
</html>

Explanation

One can see her use of variables - <set-var ... > and <get-var ... >.


8.5. The Final Site

Check here .


9. Example 5 : An FAQ List


9.1. questions.wml - the data

<define-tag mytitle>
The Pi FAQ - <if <get-var render-body /> "Answers" "Table of Contents" />
</define-tag>
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
<head>
<title><mytitle /></title>
<meta charset="utf-8" />
<link rel="stylesheet" href="$(ROOT)/style.css" type="text/css" />
</head>
<body>

<h1><mytitle /></h1>

<if "<get-var render-body />"
    ""
    "<p>"
    />

<question anchor="what_is" title="What is Pi?">

<p>
Pi is the sum of the infinite series 1 - 1/3 + 1/5 - 1/7 + 1/9 - 1/11...
multiplied by 4.
</p>

</question>

<question anchor="how_much" title="How much is Pi, approximately?">
<p>
The value of Pi varies according to the radius of the circle, so it's
hard to tell.
</p>
</question>

<question anchor="approx" title="Approximating Pi">
</question>

<promote />

<question anchor="when_zeroes"
          title="How many digits will I have to produce to reach a state of all-zeroes?">

<p>
It was proven that after a number between 1.345698 and 1.74 times 10 ** 12
digits, Pi is all zeros.
</p>

</question>

<question anchor="complexity" title="What is the fastest algorithm for approximating Pi?">

<p>
Approximating Pi was found to be NP-Complete.
</p>

</question>

<demote />

<question anchor="Uses" title="What can I do with Pi?">

<p>
The most common use of Pi is to generate random sequences. A far less common
use is for geometrical and trigonometrical calculations.
</p>

</question>

<if "<get-var render-body />"
    ""
    "</p>"
    />

</body>
</html>

9.2. api.wml - the code

<:{
use vars qw(@question_number);

@question_number=(0);
}:>

;;; Perl code here:
<define-tag next-question><:{
    my $temp = pop(@question_number)+1;
    push @question_number, $temp;
    my $qn_text = join(".", @question_number);
    print $qn_text;
}:></define-tag>

;;; Perl code here:
<define-tag promote><:{
    push @question_number, 0;
}:></define-tag>

;;; Perl code here:
<define-tag demote><:{
    pop(@question_number);
}:></define-tag>



<define-tag question endtag="required">
;;; Define anchor to be the first argument
<preserve anchor />
;;; Define title to be the second argument
<preserve title />

;;; This statement is required to actually set
;;; anchor and title to a proper value
<set-var %attributes />

;;; next-question is defined above
<set-var question-number="<next-question />" />

<if <get-var render-body />
;;; If the question should be rendered.
        "
        <p id="<get-var anchor />"><b><get-var question-number />. <get-var title /></b></p>
        %body
        "
;;; If not
    "<a href="answers.html#<get-var anchor />"><get-var question-number />. <get-var title /></a><br />"
    />
;;; Restore their previous values
<restore title />
<restore anchor />
</define-tag>

9.3. index.html.wml and answers.html.wml

index.html.wml

#include "api.wml"

#include "questions.wml"

answers.html.wml

#include "api.wml"

<set-var render-body="yes" />

#include "questions.wml"

9.4. The Result

You can see the result here


10. Demonstrating Some APIs


10.1. grid

#use wml::std::grid
<grid layout=2x3 align=lr valign=tbb border=1>
    <cell>Header 1</cell> <cell>Header 2</cell>
    <cell>Cell-A</cell>   <cell>Cell-B</cell>
    <cell>Cell-C</cell>   <cell>Cell-D</cell>
</grid>

10.2. toc

#use wml::std::toc
#use wml::std::page

<page />
<h1>My Page</h1>

<p>
This is my page
</p>

<h2>Section 1</h2>

<p>
This is section 1
</p>

<h2>Section 2</h2>

<p>
This is section 2
</p>

<h3>Sub-section 2.1</h3>

<p>
This is a subsection
</p>

<toc />