BML

From Dreamwidth Notes
Revision as of 21:30, 31 March 2011 by Sophira (Talk | contribs)

Jump to: navigation, search

BML stands for either Better Markup language, or Brad's Markup Language, depending on who you talk to.

Basic Introduction

BML is essentially a templating system, which is used on LJ mainly to provide the backend support for the siteschemes. It's kind of a bastard hybrid of HTML::Template and HTML::Mason, except it was developed completely independently by Brad, and in fact was developed in 1997, long before either of those distributions were released on CPAN.

BML has been described as "the bastard shambling horror of the deep" by those who have had to work with it. Most of what it's used for could be replaced by CSS nowadays. (It's somewhat telling that one of the siteschemes on LiveJournal is "Lynx", which is designed for text browsers such as Lynx, hence the name.)

BML is gradually being replaced with Template Toolkit. It'll take a while, though. Another useful link: Routing and Template Toolkit

Files

BML is composed of two types of files -- *.bml files and *.look files. The former can be considered standard HTML files, except that before they're passed to a browser, the BML engine parses it for special tags beginning with <? and ending with ?>, and does things with them according to the .look file that's being used.

It's worth noting that older versions of BML used (= and =) instead of <? and ?>. Those versions are dead and buried, and are not used in either LiveJournal or Dreamwidth. Trust me, this is a good thing.

Single-line Blocks

The .look file being used will define blocks that define how these tags are replaced. Each block has a name and a value. For example, a simple block might be defined as:

sitename=>Dreamwidth

The name of this block is "sitename", and its value is "Dreamwidth". The => means that the following text, up to the end of the line, should be considered to be the block value. Then, you could use the following code in a BML file:

Welcome to <?sitename?>!

and when you combine the .look file and the .bml file together, the result is:

Welcome to Dreamwidth!

Multi-line Blocks

A block can span more than one line, but to do this you need to define the start and end points. To do this, you reverse the => part to become <= to define the start point:

introduction<=

and for the end point, you do the line again, but this time putting the block name after the symbols:

<=introduction

A good mnemonic is to think of the <= as pointing first to the name of the block, then to the value. A complete multi-line block might look like:

introduction<=
<p>Welcome to Dreamwidth!</p>
<p>We hope you enjoy your time here.</p>
<=introduction

As before, this could then be used in a normal BML page just by doing something like:

<h1>Introduction</h1>
<?introduction?>

Which would be parsed out to:

<h1>Introduction</h1>
<p>Welcome to Dreamwidth!</p>
<p>We hope you enjoy your time here.</p>

Passing data

It's possible to pass data into a block, depending on what's needed. For example, let's say you wanted to make a simple error page. Without passing data, you might define such an error page like this in the .look file:

errorpage<=
<h1>Error</h1>
<p>An error has occurred.</p>
<=errorpage

However, this is very generic. It would be nice to have a way to pass in the specific error.

Fortunately, this is easily done:

errorpage<=
<h1>Error</h1>
<p>An error has occurred: %%DATA%%</p>
<=errorpage

The name %%DATA%% is defined to mean everything that's in the BML tag by default. In order to use this, you can use this type of tag:

<?errorpage Invalid login. errorpage?>

This will pass "Invalid login." to the block as %%DATA%%, resulting in the following when parsed:

<h1>Error</h1>
<p>An error has occurred: Invalid login.</p>

Passing multiple pieces of data

Sometimes you want to pass more than one piece of data. For example, you may want to define a generic "page" tag to spit out a complete HTML document with one tag, defining the title and the body in the BML file. To do this, you have to define a block as "Full". To do this, you put the text {F} directly at the beginning of the definition. Once you've done this, you can name the data that gets passed in.

An example definition might look like:

page<=
{F}
<html>
<head>
<title>%%TITLE%%</title>
</head>
<body>
%%BODY%%
</body>
</html>
<=page

In this example you have two pieces of data -- %%TITLE%% and %%BODY%%.

Now, since the .look files already define bits of data by name (in this case, blocks), Brad decided to reuse that syntax for passing these named pieces of data into a block. In this case, you might do something like:

<?page
TITLE=>Homepage
BODY<=
<p>Welcome to Dreamwidth!</p>
<p>We hope you enjoy your time here.</p>
<=BODY
page?>

Don't be fooled into thinking these are defining blocks you can use later as tags - they're not, and you can't use <?TITLE?> or <?BODY?> to put them elsewhere in your BML file too. These are only used to pass data to the block that you're using, and the only BML-specific tags that are valid on the page are those defined in the .look file.

(Well, okay, as you'd expect with something called the shambling horror of the deep, there's an exception to this. But it's fairly easyish to understand, and in any case we're not going to go near that just yet, so don't panic.)

In this case, combining the .look file and the .bml file above would give:

<html>
<head>
<title>Homepage</title>
</head>
<body>
<p>Welcome to Dreamwidth!</p>
<p>We hope you enjoy your time here.</p>
</body>
</html>

By the way, if you thought that last example was eerily familiar, that's because this is the basic format used by the Dreamwidth BML files. Most of them simply have a 'page' tag with 'title' and 'body' data. The 'page' tag defined in the .look file being used for your current sitescheme then puts it all together into a coherent page.

The only real difference is that the Dreamwidth BML/look files use lower-case names like %%title%% rather than upper-case names like %%TITLE%%. This is sad, because upper-case names are easier to pick out, and using upper-case names for data also means you don't get them confused with blocks. Oh well, c'est la vie.

Blocks within blocks within blocks...

Of course, Brad being who he is, it's possible to combine these in lots of weird and wonderful ways. For example, here's a relatively simple .look file that contains a definition for a block named 'heading', that encloses its data in h1 HTML tags, and another block named 'para', that encloses its data in paragraph HTML tags:

heading=><h1>%%DATA%%</h1>
para=><p>%%DATA%%</p>

Hey, now we can modify the "errorpage" example above to use these blocks:

heading=><h1>%%DATA%%</h1>
para=><p>%%DATA%%</p>

errorpage<=
<?heading Error heading?>
<?para An error has occurred: %%DATA%% para?>
<=errorpage

Let's then say that actually, what we want to do is combine it with our "page" block above too. So we might end up with:

heading=><h1>%%DATA%%</h1>
para=><p>%%DATA%%</p>

page<=
{F}
<html>
<head>
<title>%%TITLE%%</title>
</head>
<body>
%%BODY%%
</body>
</html>
<=page

errorpage<=
<?page
TITLE=>Error
BODY<=
<?heading Error heading?>
<?para An error has occurred: %%DATA%% para?>
<=BODY
page?>
<=errorpage

As you can see, it can get convoluted very quickly if you're not careful.

You can also use tags within tags. For example, given the following .look file:

sitename=>Dreamwidth
heading=><h1>%%DATA%%</h1>

You can produce this BML snippet:

<?heading Welcome to <?sitename?>! heading?>

which would produce the following output:

<h1>Welcome to Dreamwidth!</h1>

So, now we've covered how ugly BML can (and does) get, let's return to some saner things.

Special blocks

Some blocks are predefined in BML. To distinguish them, their names always begin with an underscore. The most common of these blocks are presented here.

_code

The most obvious of these special blocks is _code, and you'll see this in pretty much every BML file. In fact, it's not uncommon to find that the whole 'body' data of the 'page' tag is in fact one giant _code tag.

A _code tag contains Perl code. Obviously, it's beyond the scope of this page to teach Perl, but one important thing is that the value of a _code tag is whatever the Perl code inside returns. For example, if you have a BML snippet as follows:

<p><?_code return 5 + 5; _code?></p>

it would be output as:

<p>10</p>

In short, this is your Perl equivalent to PHP, but instead of using <?php php?> and writing in PHP code, you use <?_code _code?> and write in Perl code.

_ml

The "ml" in _ml stands for Multi-Language, and it's BML's way of allowing for multiple translations. Instead of storing English text in a BML file, you instead include the text in an external file, and use this tag to include the text on the page. The process of moving English text to an external file in this way is referred to as English-stripping a page.

Because English-stripping and the translation system is a whole subject unto itself, I'm not going to cover it here. The whole process is covered in a separate page - click over to English-stripping to find out more.

_info

This block contains various miscellaneous data, none of which we care about here, except for one important one: localblocks.

Remember that I said above that the only BML-specific tags you can use on a BML page are those defined in the .look file? I also said that there was an exception. This is that exception.

The localblocks data value essentially defines a mini-.look file that you can only use on the same page as the one it appears on.

For example, you might have:

<?_info
localblocks<=
heading=><h1>%%DATA%%</h1>
para=><p>%%DATA%%</p>
<=localblocks
_info?>

If this appears confusing to you, don't worry, it is. Basically, this allows you to then use <?heading?> and <?para?> tags as normal in the same page as the place this was defined, but not in any other page. You'll occasionally see these floating about in the code.

_c

I decided to finish with an easy one. This defines a comment, and everything within a _c tag is ignored completely. For example:

<?_c This code sucks. Don't blame me, I didn't write it. _c?>

These comments aren't output at all, unlike standard HTML comments (that is, <!-- comments like this -->).

The others

There are other special blocks, but they're hardly ever used. You can find more info about them at the Core BML Blocks page on LJ.

End

And that's about it for this BML wiki documentation project. If you really want to know more, LJ hosts the BML Guide.

Resources