library(http/html_write) 
libraryProducing output for the web in the form of an HTML document is a requirement for many Prolog programs. Just using format/2 is not satisfactory as it leads to poorly readable programs generating poor HTML. This library is based on using DCG rules.
The library(http/html_write) structures the generation 
of HTML from a program. It is an extensible library, providing a DCG 
framework for generating legal HTML under (Prolog) program control. It 
is especially useful for the generation of structured pages (e.g. tables) 
from Prolog data structures.
The normal way to use this library is through the DCG html//1. This non-terminal provides the central translation from a structured term with embedded calls to additional translation rules to a list of atoms that can then be printed using print_html/[1,2].
//[]
\List
\Term
\Term but allows for invoking grammar rules in 
external packages.
&<Entity>; or &#<Entity>; 
if Entity is an integer. SWI-Prolog atoms and strings are 
represented as Unicode. Explicit use of this construct is rarely needed 
because code-points that are not supported by the output encoding are 
automatically converted into character-entities.
Tag(Content)
Tag(Attributes, Content)Name(Value) or
Name=Value. Value is the atomic 
attribute value but allows for a limited functional notation:
encode(Atom)location_by_id(ID)#(ID)location_by_id(ID).Name(Value). Values are encoded as in the encode option 
described above.NAMES). Each value 
in list is separated by a space. This is particularly useful for setting 
multiple class attributes on an element. For example:
        ...
        span(class([c1,c2]), ...),
The example below generates a URL that references the predicate
set_lang/1 in 
the application with given parameters. The http_handler/3 
declaration binds /setlang to the predicate set_lang/1 
for which we provide a very simple implementation. The code between ... 
is part of an HTML page showing the English flag which, when pressed, 
calls set_lang(Request) where Request contains 
the search parameter lang = en. Note that the 
HTTP location (path) /setlang can be moved without 
affecting this code.
:- http_handler('/setlang', set_lang, []).
set_lang(Request) :-
        http_parameters(Request,
                        [ lang(Lang, [])
                        ]),
        http_session_retractall(lang(_)),
        http_session_assert(lang(Lang)),
        reply_html_page(title('Switched language'),
                        p(['Switch language to ', Lang])).
        ...
        html(a(href(location_by_id(set_lang) + [lang(en)]),
               img(src('/www/images/flags/en.png')))),
        ...
//DOCTYPE declaration. HeadContent are elements to 
be placed in the head element and BodyContent 
are elements to be placed in the body element.
To achieve common style (background, page header and footer), it is 
possible to define DCG non-terminals head//1 and/or body//1. 
Non-terminal page//1 checks for the definition of these non-terminals in 
the module it is called from as well as in the user module. 
If no definition is found, it creates a head with only the HeadContent 
(note that the
title is obligatory) and a body with bgcolor 
set to white and the provided BodyContent.
Note that further customisation is easily achieved using html//1 directly as page//2 is (besides handling the hooks) defined as:
page(Head, Body) -->
        html([ \['<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 4.0//EN">\n'],
               html([ head(Head),
                      body(bgcolor(white), Body)
                    ])
             ]).
//DOCTYPE and the HTML 
element. Contents is used to generate both the head and body 
of the page.//
        html_begin(table)
        html_begin(table(border(2), align(center)))
This predicate provides an alternative to using the
\Command syntax in the html//1 specification. 
The following two fragments are the same. The preferred solution depends 
on your preferences as well as whether the specification is generated or 
entered by the programmer.
table(Rows) -->
        html(table([border(1), align(center), width('80%')],
                   [ \table_header,
                     \table_rows(Rows)
                   ])).
% or
table(Rows) -->
        html_begin(table(border(1), align(center), width('80%'))),
        table_header,
        table_rows,
        html_end(table).
//
The non-terminal html//1 translates a specification into a list of 
atoms and layout instructions. Currently the layout instructions are 
terms of the format nl(N), requesting at least N 
newlines. Multiple consecutive nl(1) terms are combined to 
an atom containing the maximum of the requested number of newline 
characters.
To simplify handing the data to a client or storing it into a file, the following predicates are available from this library:
reply_html_page(default, Head, Body).library(http_wrapper) 
(CGI-style). Here is a simple typical example:
reply(Request) :-
        reply_html_page(title('Welcome'),
                        [ h1('Welcome'),
                          p('Welcome to our ...')
                        ]).
The header and footer of the page can be hooked using the 
grammar-rules user:head//2 and user:body//2. The first argument passed 
to these hooks is the Style argument of reply_html_page/3 
and the second is the 2nd (for head//2) or 3rd (for body//2) argument of reply_html_page/3. 
These hooks can be used to restyle the page, typically by embedding the 
real body content in a div. E.g., the following code 
provides a menu on top of each page of that is identified using the 
style
myapp.
:- multifile
        user:body//2.
user:body(myapp, Body) -->
        html(body([ div(id(top), \application_menu),
                    div(id(content), Body)
                  ])).
Redefining the head can be used to pull in scripts, but 
typically html_requires//1 provides a more modular approach for pulling 
scripts and CSS-files.
DOCTYPE 
header,
html, head or body. It is 
intended for JavaScript handlers that request a partial document and 
insert that somewhere into the existing page DOM. See reply_html_page/3 
to reply with a complete (valid) HTML page.Content-length 
field of an HTTP reply-header.
Modern HTML commonly uses CSS and Javascript. This requires <link> elements in the HTML <head> element or <script> elements in the <body>. Unfortunately this seriously harms re-using HTML DCG rules as components as each of these components may rely on their own style sheets or JavaScript code. We added a‘mailing’system to reposition and collect fragments of HTML. This is implemented by html_post//2, html_receive//1 and html_receive//2.
//\-commands are executed by mailman/1 
from print_html/1 or html_print_length/2. 
These commands are called in the calling context of the html_post//2 
call.
A typical usage scenario is to get required CSS links in the document head in a reusable fashion. First, we define css//1 as:
css(URL) -->
        html_post(css,
                  link([ type('text/css'),
                         rel('stylesheet'),
                         href(URL)
                       ])).
Next we insert the unique CSS links, in the pagehead using the following call to reply_html_page/2:
        reply_html_page([ title(...),
                          \html_receive(css)
                        ],
                        ...)
////phrase(Handler, PostedTerms, HtmlTerms, Rest)
Typically, Handler collects the posted terms, creating a term suitable for html//1 and finally calls html//1.
The library predefines the receiver channel head at the 
end of the
head element for all pages that write the html head 
through this library. The following code can be used anywhere inside an 
HTML generating rule to demand a javascript in the header:
js_script(URL) -->
        html_post(head, script([ src(URL),
                                 type('text/javascript')
                               ], [])).
This mechanism is also exploited to add XML namespace (xmlns) 
declarations to the (outer) html element using xhml_ns//2:
//xmlns 
channel. Rdfa (http://www.w3.org/2006/07/SWD/RDFa/syntax/), 
embedding RDF in (x)html provides a typical usage scenario where we want 
to publish the required namespaces in the header. We can define:
rdf_ns(Id) -->
        { rdf_global_id(Id:'', Value) },
        xhtml_ns(Id, Value).
After which we can use rdf_ns//1 as a 
normal rule in html//1 to publish 
namespaces from library(semweb/rdf_db). Note that this 
macro only has effect if the dialect is set to xhtml. In
html mode it is silently ignored.
The required xmlns receiver is installed by html_begin//1 
using the html tag and thus is present in any document that 
opens the outer html environment through this library.
In some cases it is practical to extend the translations imposed by 
html//1. We used this technique to define translation rules for the 
output of the SWI-Prolog library(sgml) package.
The html//1 non-terminal first calls the multifile ruleset html_write:expand//1.
////<&>.//<&>".
Though not strictly necessary, the library attempts to generate reasonable layout in SGML output. It does this only by inserting newlines before and after tags. It does this on the basis of the multifile predicate html_write:layout/3
-empty, 
telling the library that the element has declared empty content. In this 
case the close-tag is not emitted either, but in addition html//1 
interprets Arg in Tag(Arg) as a list of 
attributes rather than the content.
A tag that does not appear in this table is emitted without additional layout. See also print_html/[1,2]. Please consult the library source for examples.
In the following example we will generate a table of Prolog predicates we find from the SWI-Prolog help system based on a keyword. The primary database is defined by the predicate predicate/5 We will make hyperlinks for the predicates pointing to their documentation.
:- use_module(library(http/html_write)).
:- use_module(library(pldoc/man_index)).
:- use_module(library(uri)).
html_apropos(Kwd) :-
    findall(Pred, apropos_predicate(Kwd, Pred), Matches),
    phrase(apropos_page(Kwd, Matches), Tokens),
    print_html(Tokens).
%       emit page with title, header and table of matches
apropos_page(Kwd, Matches) -->
    page([ title(['Predicates for ', Kwd])
         ],
         [ h2(align(center),
              ['Predicates for ', Kwd]),
           table([ align(center),
                   border(1),
                   width('80%')
                 ],
                 [ tr([ th('Predicate'),
                        th('Summary')
                      ])
                 | \apropos_rows(Matches)
                 ])
         ]).
%       emit the rows for the body of the table.
apropos_rows([]) -->
    [].
apropos_rows([pred(Name, Arity, Summary)|T]) -->
    html([ tr([ td(\predref(Name/Arity)),
                td(em(Summary))
              ])
         ]),
    apropos_rows(T).
%!  predref(Name/Arity)//
%
%   Emit Name/Arity as a hyperlink to
%
%           /cgi-bin/plman?name=Name&arity=Arity
predref(Name/Arity) -->
    { uri_edit([search([name=Name,arity=Arity])],
               '/cgi-bin/plman', Href)
    },
    html(a(href(Href), [Name, /, Arity])).
%       Find predicates from a keyword.
apropos_predicate(Pattern, pred(Name, Arity, Summary)) :-
    man_object_property(Name/Arity, summary(Summary)),
    (   sub_atom_icasechk(Name, _, Pattern)
    ->  true
    ;   sub_atom_icasechk(Summary, _, Pattern)
    ).
library(http/html_write) libraryThis library is the result of various attempts to reach at a more satisfactory and Prolog-minded way to produce HTML text from a program. We have been using Prolog for the generation of web pages in a number of projects. Just using format/2 never was not a real option, generating error-prone HTML from clumsy syntax. We started with a layer on top of format/2, keeping track of the current nesting and thus always capable of properly closing the environment.
DCG based translation however, naturally exploits Prolog's term-rewriting primitives. If generation fails for whatever reason it is easy to produce an alternative document (for example holding an error message).
In a future version we will probably define a goal_expansion/2 
to do compile-time optimisation of the library. Quotation of known text 
and invocation of sub-rules using the \RuleSet 
and
<Module>:<RuleSet> operators are 
costly operations in the analysis that can be done at compile-time.