Did you know ... Search Documentation:
html_write.pl -- Write HTML text
PublicShow source

Most code doesn't need to use this directly; instead use library(http/http_server), which combines this library with the typical HTTP libraries that most servers need.

The purpose of this library is to simplify writing HTML pages. Of course, it is possible to use format/3 to write to the HTML stream directly, but this is generally not very satisfactory:

  • It is a lot of typing
  • It does not guarantee proper HTML syntax. You have to deal with HTML quoting, proper nesting and reasonable layout.
  • It is hard to use satisfactory abstraction

This module tries to remedy these problems. The idea is to translate a Prolog term into an HTML document. We use DCG for most of the generation.

International documents

The library supports the generation of international documents, but this is currently limited to using UTF-8 encoded HTML or XHTML documents. It is strongly recommended to use the following mime-type.

Content-type: text/html; charset=UTF-8

When generating XHTML documents, the output stream must be in UTF-8 encoding.

Source html_set_options(+Options) is det
Set options for the HTML output. Options are stored in prolog flags to ensure proper multi-threaded behaviour where setting an option is local to the thread and new threads start with the options from the parent thread. Defined options are:
One of html4, xhtml or html5 (default). For compatibility reasons, html is accepted as an alias for html4.
Set the <|DOCTYPE DocType > line for page//1 and page//2.
Set the Content-type for reply_html_page/3

Note that the doctype and content_type flags are covered by distinct prolog flags: html4_doctype, xhtml_doctype and html5_doctype and similar for the content type. The Dialect must be switched before doctype and content type.

Source html_current_option(?Option) is nondet
True if Option is an active option for the HTML generator.
Source init_options is det[private]
Initialise the HTML processing options.
Source xml_header(-Header)[private]
First line of XHTML document. Added by print_html/1.
Source ns(?Which, ?Atom)[private]
Namespace declarations
Source page(+Content:dom)// is det
Source page(+Head:dom, +Body:dom)// is det
Generate a page including the HTML <!DOCTYPE> header. The actual doctype is read from the option doctype as defined by html_set_options/1.
Source doctype//[private]
Emit the <DOCTYPE ... header. The doctype comes from the option doctype(DOCTYPE) (see html_set_options/1). Setting the doctype to '' (empty atom) suppresses the header completely. This is to avoid a IE bug in processing AJAX output ...
Source html(+Content:dom)// is det
Generate HTML from Content. Generates a token sequence for print_html/2.
Source raw(+List, +Module)// is det[private]
Emit unquoted (raw) output used for scripts, etc.
Source html_begin(+Env)// is det
Source html_end(+End)// is det
For html_begin//1, Env is a term Env(Attributes); for html_end//1 it is the plain environment name. Used for exceptional cases. Normal applications use html//1. The following two fragments are identical, where we prefer the first as it is more concise and less error-prone.
        html(table(border=1, \table_content))
Source xhtml_empty(+Env, +Attributes)// is det[private]
Emit element in xhtml mode with empty content.
Source xhtml_ns(+Id, +Value)//
Demand an xmlns:id=Value in the outer html tag. This uses the html_post/2 mechanism to post to the 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.

Source html_root_attribute(+Name, +Value)//
Add an attribute to the HTML root element of the page. For example:
    html_root_attribute(lang, en),
Source attributes(+Env, +Attributes)// is det[private]
Emit attributes for Env. Adds XHTML namespace declaration to the html tag if not provided by the caller.
 attribute_value(+Value) is det[private]
Print an attribute value. Value is either atomic or one of the following terms:
  • A+B Concatenation of A and B
  • encode(V) Emit URL-encoded version of V. See www_form_encode/2.
  • An option list Emit ?Name1=encode(Value1)&Name2=encode(Value2) ...
  • A term Format-Arguments Use format/3 and emit the result as quoted value.

The hook expand_attribute_value//1 can be defined to provide additional `function like' translations. For example, http_dispatch.pl defines location_by_id(ID) to refer to a location on the current server based on the handler id. See http_location_by_id/2.

Source attribute_value_m(+List)//[private]
Used for multi-valued attributes, such as class-lists. E.g.,
      body(class([c1, c2]), Body)

Emits <body class="c1 c2"> ...

Source html_quoted(Text)// is det
Quote the value for normal (CDATA) text. Note that text appearing in the document structure is normally quoted using these rules. I.e. the following emits properly quoted bold text regardless of the content of Text:
To be done
- Assumes UTF-8 encoding of the output.
Source html_quoted_attribute(+Text)// is det
Quote the value according to the rules for tag-attributes included in double-quotes. Note that -like html_quoted//1-, attributed values printed through html//1 are quoted atomatically.
To be done
- Assumes UTF-8 encoding of the output.
Source cdata_element(?Element)[private]
True when Element contains declared CDATA and thus only </ needs to be escaped.
Source html_post(+Id, :HTML)// is det
Reposition HTML to the receiving Id. The html_post//2 call processes HTML using html//1. Embedded \-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) -->
                  link([ type('text/css'),

Next we insert the unique CSS links, in the pagehead using the following call to reply_html_page/2:

        reply_html_page([ title(...),
Source html_receive(+Id)// is det
Receive posted HTML tokens. Unique sequences of tokens posted with html_post//2 are inserted at the location where html_receive//1 appears.
See also
- The local predicate sorted_html//1 handles the output of html_receive//1.
- html_receive//2 allows for post-processing the posted material.
Source html_receive(+Id, :Handler)// is det
This extended version of html_receive//1 causes Handler to be called to process all messages posted to the channal at the time output is generated. Handler is called as below, where PostedTerms is a list of Module:Term created from calls to html_post//2. Module is the context module of html_post and Term is the unmodified term. Members in PostedTerms are in the order posted and may contain duplicates.
  phrase(Handler, PostedTerms, HtmlTerms, Rest)

Typically, Handler collects the posted terms, creating a term suitable for html//1 and finally calls html//1.

Source html_noreceive(+Id)// is det[private]
As html_receive//1, but discard posted messages.
Source mailman(+Tokens) is det[private]
Collect posted tokens and copy them into the receiving mailboxes. Mailboxes may produce output for each other, but not cyclic. The current scheme to resolve this is rather naive: It simply permutates the mailbox resolution order until it found a working one. Before that, it puts head and script boxes at the end.
Source html_token(?Token, +Tokens) is nondet[private]
True if Token is a token in the token set. This is like member, but the toplevel list may contain cdata(Elem, Tokens).
Source mailboxes(+Tokens, -MailBoxes) is det[private]
Get all mailboxes from the token set.
Source mail_handlers(+Boxes, -Handlers, -Posters) is det[private]
Collect all post(Module,HTML) into Posters and the remainder in Handlers. Handlers consists of accept(Handler, Tokens) and ignore(_,_).
Source sorted_html(+Content:list)// is det[private]
Default handlers for html_receive//1. It sorts the posted objects to create a unique list.
- Elements can differ just on the module. Ideally we should phrase all members, sort the list of list of tokens and emit the result. Can we do better?
Source head_html(+Content:list)// is det[private]
Handler for html_receive(head). Unlike sorted_html//1, it calls a user hook html_head_expansion/2 to process the collected head material into a term suitable for html//1.
To be done
- This has been added to facilitate html_head.pl, an experimental library for dealing with css and javascript resources. It feels a bit like a hack, but for now I do not know a better solution.
Source layout(+Tag, -Open, -Close) is det[multifile]
Define required newlines before and after tags. This table is rather incomplete. New rules can be added to this multifile predicate.
Tag- Name of the tag
Open- Tuple M-N, where M is the number of lines before the tag and N after.
Close- Either as Open, or the atom - (minus) to omit the close-tag or empty to indicate the element has no content model.
To be done
- Complete table
Source print_html(+List) is det
Source print_html(+Out:stream, +List) is det
Print list of atoms and layout instructions. Currently used layout instructions:
Use at minimum N newlines here.
mailbox(Id, Box)
Repositioned tokens (see html_post//2 and html_receive//2)
Source valid_cdata(+Env, +String) is det[private]
True when String is valid content for a CDATA element such as <script>. This implies it cannot contain </script/. There is no escape for this and the script generator must use a work-around using features of the script language. For example, when using JavaScript, "</script>" can be written as "<\/script>".
- domain_error(cdata, String)
See also
- write_json/2, js_arg//1.
Source html_print_length(+List, -Len) is det
Determine the content length of a token list produced using html//1. Here is an example on how this is used to output an HTML compatible to HTTP:
        phrase(html(DOM), Tokens),
        html_print_length(Tokens, Len),
        format('Content-type: text/html; charset=UTF-8~n'),
        format('Content-length: ~d~n~n', [Len]),
Source reply_html_page(:Head, :Body) is det
Source reply_html_page(+Style, :Head, :Body) is det
Provide the complete reply as required by http_wrapper.pl for a page constructed from Head and Body. The HTTP Content-type is provided by html_current_option/1.
Source html_meta(+Heads) is det
This directive can be used to declare that an HTML rendering rule takes HTML content as argument. It has two effects. It emits the appropriate meta_predicate/1 and instructs the built-in editor (PceEmacs) to provide proper colouring for the arguments. The arguments in Head are the same as for meta_predicate or can be constant html. For example:
:- html_meta

Re-exported predicates

The following predicates are re-exported from other modules

Source html(+Content, +Vars, +VarDict, -DOM) is det
The predicate html/4 implements HTML quasi quotations. These quotations produce a DOM term that is suitable for html//1 and other predicates that are declared to consume this format. The quasi quoter only accepts valid, but possibly partial HTML documents. The document must begin with a tag. The quoter replaces attributes or content whose value is a Prolog variable that appears in the argument list of the html indicator. If the variable defines content, it must be the only content. Here is an example, replacing both a content element and an attribute. Note that the document is valid HTML.
  html({|html(Name, URL)||
         <p>Dear <span class="name">Name</span>,

         <p>You can <a href="URL">download</a> the requested
         article now.

Undocumented predicates

The following predicates are exported, but not or incorrectly documented.

Source html_end(Arg1, Arg2, Arg3)
Source page(Arg1, Arg2, Arg3, Arg4, Arg5)
Source page(Arg1, Arg2, Arg3, Arg4)
Source reply_html_page(Arg1, Arg2, Arg3)
Source print_html(Arg1, Arg2)