Creating webpages with the MMBase Tag Library


In this tutorial we try to give page designers a hands-on overview of the capabilities of the MMBase Tag Library. This technology, shipped with the MMBase content management system, enables page designers in developing web pages that retrieve their content from the MMBase system. After reading this tutorial and working your way through the examples we hope that share our enthusiasm for the MMBase system and the possibilities it offers to page designers.

If you find a mistake in this tutorial, please inform us about it at documentation@mmbase.org.

If you have additional questions please contact one of the companies that support MMBase. You will find a complete listing of supporting companies on the MMBase website. Point your browser to:

http://www.mmbase.org

Furthermore, you can subscribe to several mailing lists where users and developers exchange information. Good chance you'll find someone there willing to help you out.

When you're developing websites with MMBase as the underlying content management system, your pages will need access to the content that is stored in MMBase. Content in MMBase is stored in a cloud. Within the cloud you'll find nodes. The nodes are the actual pieces of content in MMBase. Nodes are organized in content types and relations between content types. For example, if you define that every news item you publish on your website would contain the news text and an image, then you would have two content types in your cloud: content type "news" and content type "images". Furthermore you would define a relation between the content types news and image to support displaying images with newsitems.

For a very basic website you'll need no more than a handful of content types. The standard MMBase distribution is supplied with all necessary node types for a basic website.

Now let's have a look at how we can access the cloud from within the default J2EE templating facility, e.g. Java Server Pages or short JSP's. To access the content cloud, MMBase supplies developers with a tag library. We assume you are familiar with the concepts of such a library and will not elaborate on it here.

Every tag library uses it's own namespace. The namespace is there to help the system distinguish between different tags from different libraries. MMBase tags are all prefixed by default with the string "mm". You are free to choose another prefix, however this usage is very common across MMBase developers.

To prepare your pages to work with MMBase tag libraries the first thing you'll have todo is to declare the MMBase tag library in your page. The MMBase tag library is declared by the following statement:

<%@ taglib uri="http://www.mmbase.org/mmbase-taglib-2.0"
    prefix="mm" %>

Or if you are using JSPX:

      <anyxmlelement xmlns:mm="http://www.mmbase.org/mmbase-taglib-2.0" />
    

In this declaration you tell the JSP compiler that you will be using the MMBase taglibrary and that the tags used by this library are prefixed by "mm". The value for the uri attribute, in this case "http://www.mmbase.org/mmbase-taglib-2.0" is the identification of the MMBase tag library. There is also a version 1-0, which differences in a few details only (but it more backwards compatible with older mmbase taglib versions, and doesn't use features which e.g. are not available in Tomcat 4).

We may omit this declaration in further examples, but don't forget that it must always be there.

The MMBase taglib is implemented in a file 'mmbase-taglib-2.jar' which must be present in the WEB-INF/lib directory of your web application.

To start with this tutorial, we will first start the actual MyNews application. Find the URL on the examples screen and click it to startup MyNews. MyNews should present you it's first screen.

[todo:screendump]

This first screen shows the magazine that's available in the demo setup of MMBase, together with the news items associated with that magazine and (full right) a link you can click to read the actual news item. As you can see, the layout is straightforward without graphics. We'll focus on developing this page first, then you can add graphics and layout to your liking.

Below, in the lefthand corner of the screen, you'll find two links. Clicking the last link will show you the source of this page.

The MyNews application runs with a simple database with a single magazine in it. The designers of the database have labeled this magazine with a default alias named "default.mags". To use this default magazine we import it into our page by using the <mm:import> tag. The <mm:import> tag uses a special environment, called a context. Into this context, the developer can store identifiers and their values (Java developers can compare a context to a Map-like structure).

<%@taglib uri="http://www.mmbase.org/mmbase-taglib-2.0" prefix="mm" %>
<mm:import id="magid" externid="magid">default.mags</mm:import>

When this page would be called with the parameter magid in the request then the value of magid would be passed to the id magid. For example if index.jsp is called with index.jsp?magid=210 then the id magid would have the value 210. For this to work you will for example have to create a page with links to all available magazines, like <a href="index.jsp?magid=210">The default magazine</a>. In the "Working with related nodes" section we will see how you can create such page by using the <mm:url /> tag.

If the externid and id attbributes are the same, then the id attribute can be omitted, so often you'd see simply this:

<mm:import id="magid" externid="magid">default.mags</mm:import>

Any webpage that tries to access content from MMBase will first have to initialize access to the cloud. For cloud initialization the <mm:cloud> tag is available. Besides a number of exceptions, the <mm:cloud> tag encapsulates most other MMBase tags you want to use. This means that all other MMBase tags you'll want to use, must appear between the <mm: cloud> and </mm:cloud> tags. Note that you may get runtime errors when you place tags which need a cloud, outside the cloud tag.


Through the tag in the previous chapter, the <mm:cloud> tag, we gained access to the MMBase cloud. Next we want access to our magazine, a node in the MMBase cloud.

Now to access our magazine, you'll have to tell MMBase which node you wish to access. Every node within MMBase is automatically assigned a unique number to distinguish it from other nodes.

To retrieve a node from MMBase you use the <mm:node> tag.

To retrieve our magazine we obviously have several alternate approaches. We can use the number of the node, we can use the alias that is linked to our magazine, or we can use an id which contains the node number or the alias as its value. From the previous paragraph we know that our magazine has a default alias of "default.mags". We'll use that to access it in our JSP. Add the following to our JSP:

<mm:cloud>
  <mm:import externid="magid">default.mags</mm:import>
  <mm:node number="$magid">
  </mm:node>
</mm:cloud>

Using the <mm:node> tag we actually are accessing the node of which we imported the alias or node number earlier into our page, using the <mm:import> tag. By using the $ directive, MMBase knows that the value between quotes is not an actual value of an alias, but an imported variable within the context of this page.

Another approach, if our database would ever only contain one default magazine, would be to lookup its node number in MMBase and refer it directly in our page. For example, assume we one magazine in our database with number 210, we could do:

<mm:cloud>
  <mm:node number="210">
  </mm:node>
</mm:cloud>

The obvious drawback of this structure is that the magazine number is now hardcoded into our page, which means we can only show this specific magazine.

An alternative to working with <mm:import externid="magid" /> is to use a little Java scriplet inside your template which distills the node number from the request.

<%
  String magid = (String) request.getAttribute("magid");
%>

<mm:cloud>
  <mm:node number="<%= magid%>">
  </mm:node>
</mm:cloud>

You could also use 'Expression language', which makes it even simpler.

<mm:cloud>
  <mm:node number="${param.magid}>">
  </mm:node>
</mm:cloud>

These are all alternatives to the solution presented in the sample MMBase application MyNews. Your actual choice depends on your application needs and your personal liking. For this tutorial we will stick to the default implementation as presented in the MMBase distribution.

MMBase organizes its content into nodes. Each node consists of several fields, containing the actual content of the node. Each field can be of a specific type. To access the fields within a node, MMBase offers the <mm:field> tag. To access the title and the subtitle of the magazine, we tell MMBase to display it by using this tag.

In our first page we'll now use the <mm:field> tag to display fields from the default magazine. Create a table and within the table, create two rows. The first row displays the title and the subtitle of the default magazine. The second row display the intro and the body of the magazine. Your page should now look something like the listing below.

<mm:import externid="magid">default.mags</mm:import>
<mm:cloud>
  <mm:node number="$magid" id="mag">
    <h1><mm:field name="title" escape="inline" /></h1>
    <h2><mm:field name="subtitle" escape="inline" /></h2>
    <p><mm:field  name="intro" /></p>
    <mm:field  name="body" escape="p" />
  </mm:node>
</mm:cloud>

Note that we used the <mm:field> tag to display the title and the subtitle of the magazine. As a simple formatting option we added <h1> and <h2> tags to create the impression of titles. Also notice that all MMBase tags are well formed. This means that opening and closing tags should always be in balance. JSP compilers are not as forgiving as browsers. If your tags are not well formed, you will definitely see compile errors (also in your log). If you see them, correct the errors and try compiling the page again.

The escape-attribute is used to ensure that the content produced by the field-tags does not break the HTML.

Your page is now ready for a first test and should display the title, subtitle, intro and body of the default magazine from the MMBase content cloud.

The <mm:node> tag offers more options than the one shown in this tutorial. Please refer to the full documentation for more information on the use of this tag.

Next we want to display the news items that can be found in our magazine. Refer back to the content model we displayed earlier in this tutorial. One related node from magazine is news. As we have the magazine available in our page, we should be able to access its related news nodes.

To retrieve related nodes from a specific node, MMBase supplies the <mm:relatednodes> tag (and also an 'mm:related' tag). Within this tag you can use several interesting options to control the way MMBase retrieves the related nodes. Refer to the full reference documentation to review all possible options to control retrieval of related nodes. For now we add an entry to our JSP where we tell MMBase to travel a path between our magazine and its news using the posrel relation. As we are only interested in the sequence of the relation and the title of each news item in our magazine, we tell MMBase to only use the "pos" field from the posrel relation and the title from the magazine node. We conclude by telling MMBase to order all results by the value in the "pos" field, thus retrieving each news node in same sequence as it was entered.

<mm:relatednodes role="posrel" type="news" orderby="posrel.pos">

When you add the above entry, your JSP should now look something like below. Note that we also added a <tr> </tr> entry, so that for each found related node from magazine to news, a new row in our table will be created.

<mm:import externid="magid">default.mags</mm:import>
<mm:cloud>
  <mm:node number="$magid">
    <h1><mm:field name="title" escape="inline" /></h1>
    <h2><mm:field name="subtitle" escape="inline" /></h2>
    <mm:field  name="intro" escape="p"/><
    <mm:field  name="body" escape="p" />
    <ul>
      <mm:relatednodes role="posrel" type="news" orderby="posrel.pos">
       <li>
        <field name="title" escape="text/html" />
       </li>
      </mm:related>
      </ul>
  </mm:node>
</mm:cloud>

We've now setup the basic structure that will create rows for each news node found by MMBase. It would be nice though, if these values were presented with a heading for each column. We want this heading to appear just once before MMBase start writing out the first news node. To support this behavior, MMBase has a tag <mm:first> that fires upon the first entry in the list.

<mm:import externid="magid">default.mags</mm:import>
<mm:cloud>
  <mm:node number="$magid">
    <h1><mm:field name="title"/></h1>
    <h2><mm:field name="subtitle"/></h2>
    <mm:field  name="intro" escape="p"/>
    <mm:field  name="body" escape="p" />
    <table>
       <mm:related path="posrel,news" fields="news.title" orderby="posrel.pos">
         <mm:first>
             <tr>
               <td>Title</td>
               <td/>
            </tr>
            </mm:first>
            <tr>
            </tr>
            </mm:related>
     </table>
  </mm:node>
</mm:cloud>

To complete our JSP, we now have to add the title field followed by an URL to the next JSP that will display our actual news. Displaying the title is achieved by using the <mm:field> tag again. Remember we used this tag to display the some fields from the default magazine.

<%@taglib uri="http://www.mmbase.org/mmbase-taglib-2.0" prefix="mm" %>
<mm:import externid="magid">default.mags</mm:import>
<mm:cloud>
  <mm:node number="$magid" id="mag">
  <h1><mm:field name="title"/></h1><
  <h2><mm:field name="subtitle"/></h2>
  <mm:field  name="intro" escape="p"/>
  <mm:field  name="body" escape="p"/>
  <table>
    <mm:related path="posrel,news" fields="posrel.pos,news.title" orderby="posrel.pos">
      <mm:first>
        <tr>
          <td>Title</td>
        </tr>
      </mm:first>
      <tr>
         <td><mm:field name="title"/></td>
      </tr>
     </mm:related>
   </table>
  </mm:node>
</mm:cloud>

The construction of the URL to access the content of the news items may seem a bit obscure and needs some additional explanation. First we start creation of a default URL by using the <a> tag. In stead of hardcoding our "href", we use data from MMBase by letting MMBase create the URL use by using the <mm:url> tag. Read the full documentation on this tag to get more information on the possibilities of this tag. In this situation the URL is pointing to the JSP named "newsitem.jsp". Within the <mm:url> tag we use the <mm:param> tag to pass necessary information to our "newsitem.jsp", namely the number or id of the newsitem we wish to read.

The resulting URL will appear as follows in our browser:

http://yourhostname/mmbase-webapp/mmexamples/jsp/mynews/newsitem.jsp?magid=default.mags&newsid=59

When we run our JSP in our browser we should see the following page appear [TO DO add screenshot]:

We've completed the first part of our sample application. Next we will expand our sample application with a second page that's capable of presenting the news item selected from the first page. First we add some familiar stuff like the reference to the MMBase tag library. You should incorporate this on every page, otherwise the MMBase tags will definitely not work. In this page you see a new feature: the usage of an error page. This has nothing to do with MMBase, but is a typical feature of the JSP specs. Using an error page, you can create a more elegant way to trap unforeseen situations. In stead of presenting the user with a stack trace, we can now present an error page where we handle the error more gracefully. Building the error page is not within the scope of this tutorial, so please review the page yourself if you want to find out more about this technique.

<%@page errorPage="error.jsp" language="java" contentType="text/html; charset=UTF-8" %>
<%@taglib uri="http://www.mmbase.org/mmbase-taglib-2.0" prefix="mm" %>

<mm:cloud>
  <mm:import externid="newsid" required="true" />

  <html>
    <head>
      <link rel="stylesheet" type="text/css" href="style.css" />
    </head>

    <mm:node number="$newsid">
    </mm:node>

  </html>
</mm:cloud>

We import the id of the selected news item from the previous page. This value was passed to our new page through the <mm:param> tag and the <mm:import> tags retrieves it again.

Next we use the <mm:node> tag to be able to process the news item that we wish to display. Remember that by using the $ directive we don't actually use that value as the node id, but are referring to a variable with that name inside the context.

Next we'll add the title for our browser window and build the basic html structure that will display our news item.

<%@page errorPage="error.jsp" language="java" contentType="text/html; charset=UTF-8" %>
<%@taglib uri="http://www.mmbase.org/mmbase-taglib-2.0" prefix="mm" %>
<mm:content type="text/html" language="en" >
<mm:cloud>
  <mm:import externid="newsid" required="true" />
  <mm:node number="$newsid">
 
    <html>
      <head>
        <link rel="stylesheet" type="text/css" href="style.css" />
        <title><mm:field  name="title"/></title>
      </head>

      <body>
      <h1><mm:field  name="title"/></h1>
      <mm:field name="subtitle">
        <mm:isnotempty>
          <h2><mm:write /></h2>
        </mm:isnotempty>
      </mm:field>
    </html>
  </mm:node>
</mm:cloud>
</mm:content>

We see here also the 'isnotempty' tag. The 'isnotempty' tag searches for a parent tag of the type 'Writer'. Every tag that can produce content, is a Writer tag. The field tag is a simple example of a Writer tag. The isnotempy tag now checks if the content produced by this parent 'writer' tag is empty, and in that case it does not evaluate its body.

We should be aware that a writer tag does not write anything to the page by itself if it has a body. The idea is that the tags in the body do something with the content provided by the writer then.

So, in this case the content is checked for emptyness, and if not, '<h2><mm:write /></h2>' is performed. A write-tag without attributes, searches for a parent 'writer' and writes the content to the page (unless, of course, it has a body, because a write-tag is a writer too).

But in this case, the write-tag does not have a body, so it writes the field. The whole exercise was only done to avoid writing empty h2-tags to the page if by chance the subtitle field of the news items is empty. As you saw, this happens because those h2 tags are inside the isnotempty-tag too, so will be skipped if the parent writer tag (the field) is empty.

The next step is to complete our full news item in this page.

<%@page errorPage="error.jsp" language="java" contentType="text/html; charset=UTF-8" %>
<%@taglib uri="http://www.mmbase.org/mmbase-taglib-2.0" prefix="mm" %>
<mm:content language="en">
<mm:cloud>
  <mm:import externid="newsid" required="true" />
  <mm:node number="$newsid">
 
    <html>
      <head>
        <link rel="stylesheet" type="text/css" href="style.css" />
        <title><mm:field  name="title"/></title>
      </head>

      <body>
        <h1><mm:field  name="title"/></h1>
        <mm:field name="subtitle">
          <mm:isnotempty>
            <h2><mm:write /></h2>
          </mm:isnotempty>
        </mm:field>
      <div class="intro"><mm:field name="intro" escape="p" /></div>
      <mm:field  name="body" escape="p"/>
    </html>
  </mm:node>
</mm:cloud>
</mm:content>

This new code prints out the intro of the news item. As you can see from the actual page, this intro appears in bold formatting to make it stand out more. Next we write the body of the item. Notice that we use a escape attribute here. This makes the tag escape the value of body in a special way to allow for the creation of HTML from plain text. Many different escapers are available for all kind of different goals. A overview is available in the taglib reference. They are pluggable too, and any MMBase 'applications' can provide new escapers.

If we go back to our cloud design we know that any news item can be related to quite a few other nodes of different types, like magazines and authors. It's important to evaluate the design of your template, so that you provide solutions for any possible related node. For example, it would be a bad design if your model expresses a relation between a picture and a news item while your template is not capable of displaying the picture (unless of course this is your explicit decision and your user agrees with you).

From our cloud design it appears that any news item could possibly have relations with attachments, images, people, URL's and MMEvents. For this example we will support relations to images, authors (people) and URL's. Other node types are ignored.

<%@page errorPage="error.jsp" language="java" contentType="text/html; charset=UTF-8" %>
<%@taglib uri="http://www.mmbase.org/mmbase-taglib-2.0" prefix="mm" %>
<mm:content>
<mm:cloud>
  <mm:import externid="newsid" required="true" />
  <mm:node number="$newsid">
 
    <html>
      <head>
        <link rel="stylesheet" type="text/css" href="style.css" />
        <title><mm:field  name="title"/></title>
      </head>

      <body>
      <h1><mm:field  name="title"/></h>
      <mm:field name="subtitle">
        <mm:isnotempty>
          <h2><mm:write /></h2>
        </mm:isnotempty>
      </mm:field>
      <div class="intro"><mm:field  name="intro"/></div>
      <mm:field  name="body" escape="p"/>

      <mm:relatednodes type="images" max="3">
        <mm:first>
          <h3>Related images</h3>
        </mm:first>
        <mm:image template="s(x200)" mode="img" />
        <mm:last inverse="true">, </mm:last>
      </mm:relatednodes>

      <mm:relatednodes type="urls">
        <mm:first>
          <h3>Related url</h3>
        </mm:first>
        <a href="<mm:field name="url"/>"><mm:field name="description"/></a>
        <mm:last inverse="true">, </mm:last>
      </mm:relatednodes>

      <mm:relatednodes type="people">
        <mm:first>
          <h3>Authors</h3>
        </mm:first>
        <em><mm:field name="firstname" /> <mm:field name="lastname" /></em>
        <mm:last inverse="true">, </mm:last>
      </mm:relatednodes>
    </html>
  </mm:node>
</mm:cloud>

Here we added the <mm:relatednodes> tag to support retrieval of our relevant related nodes. Note the usage of the <mm:last> tag to get a comma after each related nodes but the last one.

After you completed this step, check your page in your development environment. Your page should look something like below figure if all went well.[TODO include screenshot ]

In this tutorial we showed how to build a sample MMBase application. Obviously we have only tipped the possibilities that MMBase offers to page designers. There are several things you can do from here:

In this tutorial we have seen that tags can cooperate, and work together. It is good to know a bit about the abstraction behind this.

The first tag which we encountered was the 'cloud' tag. Every tag that wraps functionality needing a cloud must be inside such a cloud tag. Those tags are named 'cloudreferrers' (see the taglib reference for an overview of all cloud referrers).

The cloud tag itself of course then is a 'CloudProvider'. That seems a bit silly at first, because perhaps you cannot think of something else that could provide a cloud. If you look 'cloudprovider' up in the reference you see however that there is one other cloudprovider, namely the 'transaction'-tag. A transaction is a special kind of cloud.

This same scheme can be applied to several other concepts. The next one of course is the 'node provider' with its counterpart the 'node referrer'.

Node referrers are many. The most obvious one is of course the field tag. When presenting a field, the field tag of course needs a reference to a node variable where the actual field value belongs to. Other examples of node referrer tags are the 'related' tag and the 'relatednodes' tag, which list nodes related to the node to which they refer as a node referrer.

These relatednodes tags are of course also node providers. They provide nodes, based on the reference to another node.

For node referrer tags it does not matter which tag exactly is the node provider, they only search for the abstract thing which is a 'node provider'. That's why a field-tag can be used inside a node-tag or a nodelist-tag and so on.

Sometimes it will occur that a node referrer (like a field-tag) §is actually in more then one node-provider tag at the same time. For example:

<mm:node number="123">
   <mm:relatednodes type="urls">
      <mm:field name="title" />
   </mm:relatednodes>
</mm:node>
Both 'node' and 'relatednodes' are node providers, the field tag is in the body of both. So how does it know now of which node provider it should write the 'title' field?

The answer is that on default it will use the direct parent, so in this case the 'relatednodes' node provider.

If however this is not what you want then you need to know the following. Every tag, so also every node provider, can have an 'id' attribute, and every node referrer tag can have the 'node' attribute. So perhaps you understand already, but the example will make it clear if not:

<mm:node id="abc" number="123">
  <mm:relatednodes type="urls">
      <mm:field node="abc" name="title" />
  </mm:relatednodes>
</mm:node>        
You see, now the field searches for a node-provider with id 'abc', and that happens to be the mm:node tag. It still has to be inside though.

This mechanisms work for every provider/referrer pair. So cloud-referrers have a 'cloud' attribute, node-referrers have a 'node' attribute and field-referrers have a 'field' attribute.

The 'id' attributes of tags are also used for something else. Namely to construct 'taglib variables' about which we will elaborate in the section Taglib variables.

But first we will tell a bit about another very basic provider/referrer pair, namely the writers and writer referrers.

Another name for 'writer' tags could perhaps have been 'content providers'. These concepts were introduced after the observation that there are really two kind of tags. There are tags such as the cloud tag and node tag, which do nothing by themselves, they merely provide an environment for other tags. On the other hand, there are also tags which can actually write something to the page, like the field tag, they actually provide content, so to say. (hence the chosen name 'Writer' and the 'content provider' suggestion I just did).

Sometimes we do not want to write the content provided by a writer tag to the page, but we want something else. Perhaps we first want to check if the content is correct, or perhaps we want to store the content in a jsp-variable, or perhaps yet something else.

So here the concept of writerreferrer tags comes in. It works precisely the same as the other referrers we talked about. Writer referrers work in the body of 'writer' tags. Because of this, 'Writer' tags behave a bit different if they have a body, because only then they start being real 'providers', otherwise they simply provide the content to the writer-referrers. But if the writer-tag does not have a body, then the most sensible thing is done with the content: it is written to the page. This default behavior of writer tags can be overriden by their 'write' attribute. Using this attribute you can perform tricks as 'silent' field tags, or field tags that write also when they have a body.

The most simple example of a writer-tag is the write-tag.

<mm:write value="hello world" />
This will for example just write 'hello world' on your page. This is a silly thing to do of course, because you could as well have used no tag at all for this. In the section about taglib variables you will however find out that even the 'value' attribute of the write-tag can come in useful.

But the write-tag is also a writer referrer tag. Of course, when the write-tag works as a writer-referrer tag, it simply takes the content of the 'writer' tag it refers to and uses that as its own content.

<mm:field name="title">
  <mm:write />
</mm:field>
So this will simply write the value of the 'title' field. The field tag itself did not write because it has a body, and the write tag inside it referred to it, and wrote it to the page.

In the previous section we already mentioned the fact that the 'id' attribute is also used to create 'taglib variables'. We will now demonstrate what those are.

Taglib variables originated from the need to pass around information between tags that are not 'inside' each other. There is for example a tag that creates a relation between two nodes. So, this 'createrelation' tag would need to refer to two nodes, and not to one. It would be silly to demand that the createrelation tag be in two nodeproviders. So we came up with this:

<mm:node id="firstnode" number="123" />
<mm:node id="secondnode" number="456" />
<mm:createrelation role="related" source="firstnode" destination="secondnode" />

Now, the two nodes under concern are stored somewhere, and the createrelation tag uses it. Perhaps it is a good idea to reveal immediately where they are stored. They are stored in a 'context'.

So now what happens if we assign an id to a writer tag? Then of course the obvious thing will happen, namely that the associated writer content is written to the context. This can be picked up later. So now you can understand what this will do:

<mm:field id="title" name="title" />
<mm:write referid="title" />
Yes, this will write the title field twice.

It can happen you want to use the value of some writer in the attribute of another tag. This would be the natural thing to do:

<mm:field id="type" name="type" />
<mm:listnodes type="<mm:write referid="type" />"> <!-- THIS IS NOT POSSIBLE -->
   ..
</mm:listnodes>
This can however not be done in taglib (of course because tags cannot be used inside attributes in XML).

To solve this, we came up with the dollar-sign notation:

<mm:field id="type" name="type" />
<mm:listnodes type="$type"> 
   ..
</mm:listnodes>
Dollar signs are often used to indicate that something should be interpreted as the name of a variable, e.g. in XML based languages like XSL and Ant. Also in script languages like Perl this is common practice.

It is also more or less the notation of EL, though there it is obligated to use also curly brackets (they used to be optional in MMBase Taglib).

This will write out the field 'title' six times:

<mm:field id="title" name="title" /> simple
<mm:write referid="title" />         referid
<mm:write value="$title" />          MMBase dollar sign notation
<mm:write value="${title}" />        MMBase dollar sign notation with curly brackets, or EL if available
<mm:write value="$[title]" />        MMBase dollar sign notation with square brackets (introduced to provide way to avoid collisions with EL)
${title}

Do you understand the difference between the 'value' and the 'referid' attributes?

Dollar-sign variables can be used in nearly all attributes. It can also be combined with other text:

<mm:field id="title" name="title" />
<mm:listnodes type="news" constraints="title LIKE '$title'"> 
   ..
</mm:listnodes>
Sometimes it is needed to use curly brackets to indicate where the name of the variable ends:
<mm:field id="firstname" name="firstname" />
<mm:field id="lastname" name="lastname" />
<mm:listnodes type="news" constraints="title LIKE '${firstname}${lastname}'"> 
   ..
</mm:listnodes>

Also other objects in the context can be used with a dollar-sign variable, and usually something sensible happens then. For example the dollar-sign value of a node is its number. You can use this for example to create an url:

<mm:listnodes id="article" type="news">
    <a href="<mm:url page="newsitem.jsp?article=$article" />"><mm:field name="title" /></a>
</mm:listnodes>
The url-tag has more features. Please use the reference documentation to learn more about it.

We have seen the most natural way to put something in the 'context', which is using an 'id' on some tag. Putting explicitly something in the context could therefore be done like this:

<mm:write value="hello world" id="hello" write="false" />

There is a variant of the write-tag of which the only goal is putting things in the context. This is the 'import' tag, which you have seen before. It is in some way also the inverse of the write tag; the write tag is to get things out the context (but by chance can also be used to put things in it), but the import tag is meant to put things in the context. Therefore the import-tag is not a 'writer' itself. The function of the value attribute of the write tag is taken by the body of the import tag.

<mm:import id="hello">hello world</mm:import>

The body of the import tag is only optional though. Normally the import-tag will import from somewhere else in the context. Very often, it will be used to 'import' a request parameter.

<mm:import externid="greeting" from="parameters" id="hello" />
This will put the value of the request parameter 'greeting' into the taglib variable 'hello'.

Very often you will be content with a taglib variable with the same name, so the 'id' attribute is optional if you use the externid attribute:

<mm:import externid="greeting" from="parameters"/>
This will put the value of the request parameter 'greeting' into the taglib variable 'greeting'.

These are the basics of the import tag. We refer to the taglib reference documentation for a full description.

In MMBase taglib there are two dollar sign variable with a special meaning, which can be very convenient. If you happen to know Perl, you will know from where this syntax was borrowed.

Often it is a bit cumbersome to use an id attribute on some writer, because that will often also introduce a context tag (when you are in a list), and things get a bit messy. So, you can also use the $_-variable which is the equivalent of <mm:write />, but then inside an attribute.

<mm:listnodes type="news">
  <mm:field name="title">
    <mm:listnodes type="news" constraints="title LIKE '$_'"> 
      ..
    </mm:listnodes>
  </mm:field>
</mm:listnodes>
This finds news articles with the same title.

Something similar goes for 'nodes' which are the core of any MMBase code, and also in taglib you may often want to refer to the 'current' node. As you can refer to the current writer with a nude <mm:write /> tag, so you can refer to the current node with a nude <node /> tag. The associated $-variable is $_node.

In that way you e.g. also easily use field values in attributes.

<mm:listnodes type="news">  
  <div class="${_node.className}">
  </mm:div>
</mm:listnodes>

Note

Also mmbase taglib escaping is available in attributes, using EL functions.

<mm:listnodes type="news">  
  <div title="${mm:escape('text/html/attribute', _node.title)}">
  </mm:div>
</mm:listnodes>
Where something like <div title="<mm:field name="title" escape="text/html/attribute" />" > happened, but in a XML (and JSPX) compliant way.

Sometimes the MMBase taglib will not provide enough functionality. Since a taglib is always used in a JSP page (this is not so per definition, but in practice, this is always so), it would be only logical to implement the more complicated things in Java.

For this to be possible most MMBase tags (I think the exceptions are only the 'condition' tags) have the 'jspvar' attribute. With this, a java variable, of which the name is defined by the the value of the jspvar attribute, will be instantiated, and can be used in the body of the tag. There is for example (in taglib 1.0.1) no taglib way to get user information:

<mm:cloud jspvar="cloud">
  logged in as <%=  cloud.getUser().getIdentifier() %>
</mm:cloud>

Sometimes the type of the variable which must be declared is not defined well by the tag. Then a jspvar of type 'Object' will be declared, which can be inconvenient because then normally you will have to cast to the desired type.

Therefore the tags to which this applies (most noticeably all 'writer' tags) also feature the 'vartype' attribute.

<mm:field name="size" jspvar="size" vartype="float">
  Size of the object: <%= size.floatValue() * 1000 %> millimeters.
</mm:field>

The 'jspvar' and 'vartype' attributes are probably the only mmbase taglib attribute which do not accept taglib dollar-sign variables. This is fundamentally impossible, because the values of those attributes need to be known at compile time.

The 'import' tag is the only tag which does not create the jsp-variable in its body (because that is used already for something else). The jspvar of an import tag is available after the tag. So the import tag provides you a way to create global jsp-variables on your page. Global variables are considered bad practice.


This is part of the MMBase documentation.

For questions and remarks about this documentation mail to: documentation@mmbase.org