Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

Code Block
<div class="card-deck">
  <div class="card">
    <img class="card-img-top" src="...">
    <div class="card-body">
      <h5 class="card-title">Card title</h5>
      <p class="card-text">This is the firsta card.</p>
    </div>
  </div>
  <div class="card">
    <img class="card-img-top" src="...">
    <div class="card-body">
      <h5 class="card-title">Card title</h5>
      <p class="card-text">This is thea second card.</p>
    </div>
  </div>
  <div class="card">
    <img class="card-img-top" src="...">
    <div class="card-body">
      <h5 class="card-title">Card title</h5>
      <p class="card-text">This is the thirda card.</p>
    </div>
  </div>
</div>

...

Code Block
atomic_list_concat([
  '<h5 class="card-title">Card title</h5>',
  '<p class="card-text">This is the thirda card.</p>'], CardBodyContent)

...

Code Block
% Prolog query that generates HTML code for a three-card card deck
% First, we generate the content for the card body
atomic_list_concat([
  '<h5 class="card-title">Card title</h5>',
  '<p class="card-text">This is thea third card.</p>'], CardBodyContent),
% then we generate the card body element
div(CardBodyContent, 'card-body', '', CardBodyElement),
% then we generate the card image element
img('...', 'card-img-top', '', CardImage),
% and then we generate the content for the card deck
atomic_list_concat([CardImage, CardBodyElement], CardContent),
% We need three cards!
atomic_list_concat([CardContent, CardContent, CardContent], CardContent3Times),
div(CardContent3Times, 'card', '', CardDeckContent),
% so we can finally create the card deck html element
div(CardDeckContent, 'card-deck', '', Html).

% The Html output variable will return the complete card deck HTML code we showed above.

...

Defining new predicates for generating HTML elements

applyTemplate('Template String with ~a where you want to insert atom', Atom to Insert, Return Variable).

 When you inspect the code in the html.pl file, you will see that a returning pattern has been used to define Prolog predicates for corresponding HTML tags. The general pattern for a tag named tagname looks like this:

Code Block
% tagname/1 is used to introduce an HTML template with ~a to indicate placeholders for a 
%   tag tagname; in this example, there are just two placeholders and we assume that the tag
%   has a start <tagname> and end tag </tagname>
tagname('<tagname... ~a ...  >~a</tagname>')

One of the placeholders always should represent the content of the tagname element (which typically will appear last in the HTML template code, right between the start and end tag). Other placeholders could be used for class or other attributes. The second clause that defines the tagname predicate that generates the HTML code for the element should have N+1 arguments where N is the number of placeholders in the template. To generate the HTML code, we use the predefined applyTemplate(+Template, +ArgumentList, -Html) query for instantiating the placeholders in the HTML template. The typical pattern looks like this:

Code Block
% tagname/3 predicate for generating HTML code for the tag element;
% we suppose, as an example, that the other placeholder in the template is a class attribute
tagname(Content, Class, Html) :- 
    tagname(Template), applyTemplate(Template, [Class, Content], Html).

applyTemplate(+Template, +ArgumentList, -Html)

The predicate applyTemplate/3 replaces placeholders ~a in the HTML template Template input argument with values provided by the arguments listed in the input variable ArgumentList to generate the instatiated HTML code from the template. The ArgumentList should be a Prolog list [Arg1, ..., ArgN] where the number of arguments N matches the number of placeholders ~a in the template, and the order of these arguments matches the order in which these arguments are expected in the template.

Above, we suggested that we could also introduce a predicate for a paragraph with a class attribute, e.g. for HTML code that looks like <p class="card-text">SOME TEXT CONTENT</p>. Perhaps this is not that often needed in practice, but for illustrative purposes we will now show as an example how such a predicate can be defined.

The first thing we always need to do is to add a template for the HTML element. We will simply use the p/1 predicate in line with our convention to name the predicate the same as the HTML tag, which is convenient We want to be able to fill in the class attribute and the paragraph content, so we insert two placeholders ~a (one for each of these):

Code Block
% Paragraph template with class and content placeholders
p('<p class="~a">~a</p>').

To define a p/3 predicate p(Content, Class, Html) that allows for filling in a class attribute as well as content for the paragraph element, we use the template and the applyTemplate/3 predicate:

Code Block
% Rule for paragraph predicate p/3 for a paragraph element with a class attribute
p(Content, Class, Html) :- p(Template), applyTemplate(Template, [Class, Content], Html).

Note that by convention we put the Content argument first. This is just a convention but by sticking with it we keep our code consistent and avoid confusion about what the first argument of our predicates should be instantiated with. The elements in the list [Class, Content] fed to the applyTemplate predicate, however, should match the order of the placeholders ~a in the paragraph template we introduced above to make sure that they are substituted in the right order into this template.

As an example, we can now use our p/3 predicate to replace our quoted paragraph element '<p class="card-text">This is the third card.</p>' in our card deck example above as follows:

Code Block
p('This is a card.','card-text', ParagraphElement)

Note that we need to introduce an output argument variable name to retrieve the HTML code for the paragraph in.