View source with raw comments or as raw
    1/*  Part of SWI-Prolog
    2
    3    Author:        Jan Wielemaker & Richard O'Keefe
    4    E-mail:        J.Wielemaker@vu.nl
    5    WWW:           http://www.swi-prolog.org
    6    Copyright (c)  2004-2016, University of Amsterdam
    7                              VU University Amsterdam
    8    All rights reserved.
    9
   10    Redistribution and use in source and binary forms, with or without
   11    modification, are permitted provided that the following conditions
   12    are met:
   13
   14    1. Redistributions of source code must retain the above copyright
   15       notice, this list of conditions and the following disclaimer.
   16
   17    2. Redistributions in binary form must reproduce the above copyright
   18       notice, this list of conditions and the following disclaimer in
   19       the documentation and/or other materials provided with the
   20       distribution.
   21
   22    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
   23    "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
   24    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
   25    FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
   26    COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
   27    INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
   28    BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
   29    LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
   30    CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   31    LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
   32    ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   33    POSSIBILITY OF SUCH DAMAGE.
   34*/
   35
   36:- module(sgml_write,
   37          [ html_write/2,               %          +Data, +Options
   38            html_write/3,               % +Stream, +Data, +Options
   39            sgml_write/2,               %          +Data, +Options
   40            sgml_write/3,               % +Stream, +Data, +Options
   41            xml_write/2,                %          +Data, +Options
   42            xml_write/3                 % +Stream, +Data, +Options
   43          ]).   44:- autoload(library(assoc),
   45	    [get_assoc/3,empty_assoc/1,put_assoc/4,list_to_assoc/2]).   46:- autoload(library(error),
   47	    [ must_be/2,
   48	      domain_error/2,
   49	      instantiation_error/1,
   50	      type_error/2
   51	    ]).   52:- autoload(library(gensym),[gensym/2]).   53:- autoload(library(lists),[select/3]).   54:- autoload(library(option),[option/3]).   55:- autoload(library(sgml),[dtd/2,dtd_property/2]).   56
   57:- predicate_options(xml_write/2, 2, [pass_to(xml_write/3, 3)]).   58:- predicate_options(xml_write/3, 3,
   59                     [ dtd(any),
   60                       doctype(atom),
   61                       public(atom),
   62                       system(atom),
   63                       header(boolean),
   64                       nsmap(list),
   65                       indent(nonneg),
   66                       layout(boolean),
   67                       net(boolean),
   68                       cleanns(boolean)
   69                     ]).   70
   71:- multifile
   72    xmlns/2.                        % NS, URI

XML/SGML writer module

This library provides the inverse functionality of the sgml.pl parser library, writing XML, SGML and HTML documents from the parsed output. It is intended to allow rewriting in a different dialect or encoding or to perform document transformation in Prolog on the parsed representation.

The current implementation is particularly keen on getting character encoding and the use of character entities right. Some work has been done providing layout, but space handling in XML and SGML make this a very hazardous area.

The Prolog-based low-level character and escape handling is the real bottleneck in this library and will probably be moved to C in a later stage.

See also
-
library(http/html_write) provides a high-level library for emitting HTML and XHTML. */
 xml_write(+Data, +Options) is det
 sgml_write(+Data, +Options) is det
 html_write(+Data, +Options) is det
 xml_write(+Stream, +Data, +Options) is det
 sgml_write(+Stream, +Data, +Options) is det
 html_write(+Stream, +Data, +Options) is det
Write a term as created by the SGML/XML parser to a stream in SGML or XML format. Options:
cleanns(Bool)
If true (default), remove duplicate xmlns attributes.
dtd(DTD)
The DTD. This is needed for SGML documents that contain elements with content model EMPTY. Characters which may not be written directly in the Stream's encoding will be written using character data entities from the DTD if at all possible, otherwise as numeric character references. Note that the DTD will NOT be written out at all; as yet there is no way to write out an internal subset, though it would not be hard to add one.
doctype(DocType)
Document type for the SGML document type declaration. If omitted it is taken from the root element. There is never any point in having this be disagree with the root element. A <!DOCTYPE> declaration will be written if and only if at least one of doctype(_), public(_), or system(_) is provided in Options.
public PubId
The public identifier to be written in the <!DOCTYPE> line.
system(SysId)
The system identifier to be written in the <!DOCTYPE> line.
header(Bool)
If Bool is 'false', do not emit the <xml ...> header line. (xml_write/3 only)
nsmap(Map:list(Id=URI))
When emitting embedded XML, assume these namespaces are already defined from the environment. (xml_write/3 only).
indent(Indent)
Indentation of the document (for embedding)
layout(Bool)
Emit/do not emit layout characters to make output readable.
net(Bool)
Use/do not use Null End Tags. For XML, this applies only to empty elements, so you get
    <foo/>      (default, net(true))
    <foo></foo> (net(false))

For SGML, this applies to empty elements, so you get

    <foo>       (if foo is declared to be EMPTY in the DTD)
    <foo></foo> (default, net(false))
    <foo//      (net(true))

and also to elements with character content not containing /

    <b>xxx</b>  (default, net(false))
    <b/xxx/     (net(true)).

Note that if the stream is UTF-8, the system will write special characters as UTF-8 sequences, while if it is ISO Latin-1 it will use (character) entities if there is a DTD that provides them, otherwise it will use numeric character references.

  176xml_write(Data, Options) :-
  177    current_output(Stream),
  178    xml_write(Stream, Data, Options).
  179
  180xml_write(Stream0, Data, Options) :-
  181    fix_user_stream(Stream0, Stream),
  182    (   stream_property(Stream, encoding(text))
  183    ->  set_stream(Stream, encoding(utf8)),
  184        call_cleanup(xml_write(Stream, Data, Options),
  185                     set_stream(Stream, encoding(text)))
  186    ;   new_state(xml, State),
  187        init_state(Options, State),
  188        get_state(State, nsmap, NSMap),
  189        add_missing_namespaces(Data, NSMap, Data1),
  190        emit_xml_encoding(Stream, Options),
  191        emit_doctype(Options, Data, Stream),
  192        write_initial_indent(State, Stream),
  193        emit(Data1, Stream, State)
  194    ).
  195
  196
  197sgml_write(Data, Options) :-
  198    current_output(Stream),
  199    sgml_write(Stream, Data, Options).
  200
  201sgml_write(Stream0, Data, Options) :-
  202    fix_user_stream(Stream0, Stream),
  203    (   stream_property(Stream, encoding(text))
  204    ->  set_stream(Stream, encoding(utf8)),
  205        call_cleanup(sgml_write(Stream, Data, Options),
  206                     set_stream(Stream, encoding(text)))
  207    ;   new_state(sgml, State),
  208        init_state(Options, State),
  209        write_initial_indent(State, Stream),
  210        emit_doctype(Options, Data, Stream),
  211        emit(Data, Stream, State)
  212    ).
  213
  214
  215html_write(Data, Options) :-
  216    current_output(Stream),
  217    html_write(Stream, Data, Options).
  218
  219html_write(Stream, Data, Options) :-
  220    sgml_write(Stream, Data,
  221               [ dtd(html)
  222               | Options
  223               ]).
  224
  225fix_user_stream(user, user_output) :- !.
  226fix_user_stream(Stream, Stream).
  227
  228
  229init_state([], _).
  230init_state([H|T], State) :-
  231    update_state(H, State),
  232    init_state(T, State).
  233
  234update_state(dtd(DTD), State) :-
  235    !,
  236    (   atom(DTD)
  237    ->  dtd(DTD, DTDObj)
  238    ;   DTDObj = DTD
  239    ),
  240    set_state(State, dtd, DTDObj),
  241    dtd_character_entities(DTDObj, EntityMap),
  242    set_state(State, entity_map, EntityMap).
  243update_state(nsmap(Map), State) :-
  244    !,
  245    set_state(State, nsmap, Map).
  246update_state(cleanns(Bool), State) :-
  247    !,
  248    must_be(boolean, Bool),
  249    set_state(State, cleanns, Bool).
  250update_state(indent(Indent), State) :-
  251    !,
  252    must_be(integer, Indent),
  253    set_state(State, indent, Indent).
  254update_state(layout(Bool), State) :-
  255    !,
  256    must_be(boolean, Bool),
  257    set_state(State, layout, Bool).
  258update_state(doctype(_), _) :- !.
  259update_state(public(_),  _) :- !.
  260update_state(system(_),  _) :- !.
  261update_state(net(Bool), State) :-
  262    !,
  263    must_be(boolean, Bool),
  264    set_state(State, net, Bool).
  265update_state(header(Bool), _) :-
  266    !,
  267    must_be(boolean, Bool).
  268update_state(Option, _) :-
  269    domain_error(xml_write_option, Option).
  270
  271%       emit_xml_encoding(+Stream, +Options)
  272%
  273%       Emit the XML fileheader with   encoding information. Setting the
  274%       right encoding on the output stream  must be done before calling
  275%       xml_write/3.
  276
  277emit_xml_encoding(Out, Options) :-
  278    option(header(Hdr), Options, true),
  279    Hdr == true,
  280    !,
  281    stream_property(Out, encoding(Encoding)),
  282    (   (   Encoding == utf8
  283        ;   Encoding == wchar_t
  284        )
  285    ->  format(Out, '<?xml version="1.0" encoding="UTF-8"?>~n~n', [])
  286    ;   Encoding == iso_latin_1
  287    ->  format(Out, '<?xml version="1.0" encoding="ISO-8859-1"?>~n~n', [])
  288    ;   domain_error(xml_encoding, Encoding)
  289    ).
  290emit_xml_encoding(_, _).
 emit_doctype(+Options, +Data, +Stream)
Emit the document-type declaration. There is a problem with the first clause if we are emitting SGML: the SGML DTDs for HTML up to HTML 4 do not allow any 'version' attribute; so the only time this is useful is when it is illegal!
  300emit_doctype(_Options, Data, Out) :-
  301    (   Data = [_|_], memberchk(element(html,Att,_), Data)
  302    ;   Data = element(html,Att,_)
  303    ),
  304    memberchk(version=Version, Att),
  305    !,
  306    format(Out, '<!DOCTYPE HTML PUBLIC "~w">~n~n', [Version]).
  307emit_doctype(Options, Data, Out) :-
  308    (   memberchk(public(PubId), Options) -> true
  309    ;   PubId = (-)
  310    ),
  311    (   memberchk(system(SysId), Options) -> true
  312    ;   SysId = (-)
  313    ),
  314    \+ (PubId == (-),
  315        SysId == (-),
  316        \+ memberchk(doctype(_), Options)
  317    ),
  318    (   Data = element(DocType,_,_)
  319    ;   Data = [_|_], memberchk(element(DocType,_,_), Data)
  320    ;   memberchk(doctype(DocType), Options)
  321    ),
  322    !,
  323    write_doctype(Out, DocType, PubId, SysId).
  324emit_doctype(_, _, _).
  325
  326write_doctype(Out, DocType, -, -) :-
  327    !,
  328    format(Out, '<!DOCTYPE ~w []>~n~n', [DocType]).
  329write_doctype(Out, DocType, -, SysId) :-
  330    !,
  331    format(Out, '<!DOCTYPE ~w SYSTEM "~w">~n~n', [DocType,SysId]).
  332write_doctype(Out, DocType, PubId, -) :-
  333    !,
  334    format(Out, '<!DOCTYPE ~w PUBLIC "~w">~n~n', [DocType,PubId]).
  335write_doctype(Out, DocType, PubId, SysId) :-
  336    format(Out, '<!DOCTYPE ~w PUBLIC "~w" "~w">~n~n', [DocType,PubId,SysId]).
 emit(+Element, +Out, +State, +Options)
Emit a single element
  343emit(Var, _, _) :-
  344    var(Var),
  345    !,
  346    instantiation_error(Var).
  347emit([], _, _) :- !.
  348emit([H|T], Out, State) :-
  349    !,
  350    emit(H, Out, State),
  351    emit(T, Out, State).
  352emit(CDATA, Out, State) :-
  353    atomic(CDATA),
  354    !,
  355    sgml_write_content(Out, CDATA, State).
  356emit(Element, Out, State) :-
  357    \+ \+ emit_element(Element, Out, State).
  358
  359emit_element(pi(PI), Out, State) :-
  360    !,
  361    get_state(State, entity_map, EntityMap),
  362    write(Out, <?),
  363    write_quoted(Out, PI, '', EntityMap),
  364    (   get_state(State, dialect, xml) ->
  365        write(Out, ?>)
  366    ;   write(Out, >)
  367    ).
  368emit_element(element(Name, Attributes, Content), Out, State) :-
  369    !,
  370    must_be(list, Attributes),
  371    must_be(list, Content),
  372    (   get_state(State, dialect, xml)
  373    ->  update_nsmap(Attributes, CleanAttrs, State),
  374        (   get_state(State, cleanns, true)
  375        ->  WriteAttrs = CleanAttrs
  376        ;   WriteAttrs = Attributes
  377        )
  378    ;   WriteAttrs = Attributes
  379    ),
  380    att_length(WriteAttrs, State, Alen),
  381    (   Alen > 60,
  382        get_state(State, layout, true)
  383    ->  Sep = nl,
  384        AttIndent = 4
  385    ;   Sep = sp,
  386        AttIndent = 0
  387    ),
  388    put_char(Out, '<'),
  389    emit_name(Name, Out, State),
  390    (   AttIndent > 0
  391    ->  \+ \+ ( inc_indent(State, AttIndent),
  392                attributes(WriteAttrs, Sep, Out, State)
  393              )
  394    ;   attributes(WriteAttrs, Sep, Out, State)
  395    ),
  396    content(Content, Out, Name, State).
  397emit_element(E, _, _) :-
  398    type_error(xml_dom, E).
  399
  400attributes([], _, _, _).
  401attributes([H|T], Sep, Out, State) :-
  402    (   Sep == nl
  403    ->  write_indent(State, Out)
  404    ;   put_char(Out, ' ')
  405    ),
  406    attribute(H, Out, State),
  407    attributes(T, Sep, Out, State).
  408
  409attribute(Name=Value, Out, State) :-
  410    emit_name(Name, Out, State),
  411    put_char(Out, =),
  412    sgml_write_attribute(Out, Value, State).
  413
  414att_length(Atts, State, Len) :-
  415    att_length(Atts, State, 0, Len).
  416
  417att_length([], _, Len, Len).
  418att_length([A0|T], State, Len0, Len) :-
  419    alen(A0, State, AL),
  420    Len1 is Len0 + 1 + AL,
  421    att_length(T, State, Len1, Len).
  422
  423alen(ns(NS, _URI):Name=Value, _State, Len) :-
  424    !,
  425    atom_length(Value, AL),
  426    vlen(Name, NL),
  427    atom_length(NS, NsL),
  428    Len is AL+NL+NsL+3.
  429alen(URI:Name=Value, State, Len) :-
  430    !,
  431    atom_length(Value, AL),
  432    vlen(Name, NL),
  433    get_state(State, nsmap, Nsmap),
  434    (   memberchk(NS=URI, Nsmap)
  435    ->  atom_length(NS, NsL)
  436    ;   atom_length(URI, NsL)
  437    ),
  438    Len is AL+NL+NsL+3.
  439alen(Name=Value, _, Len) :-
  440    atom_length(Name, NL),
  441    vlen(Value, AL),
  442    Len is AL+NL+3.
  443
  444vlen(Value, Len) :-
  445    is_list(Value),
  446    !,
  447    vlen_list(Value, 0, Len).
  448vlen(Value, Len) :-
  449    atom_length(Value, Len).
  450
  451vlen_list([], L, L).
  452vlen_list([H|T], L0, L) :-
  453    atom_length(H, HL),
  454    (   L0 == 0
  455    ->  L1 is L0 + HL
  456    ;   L1 is L0 + HL + 1
  457    ),
  458    vlen_list(T, L1, L).
  459
  460
  461emit_name(Name, Out, _) :-
  462    atom(Name),
  463    !,
  464    write(Out, Name).
  465emit_name(ns(NS,_URI):Name, Out, _State) :-
  466    !,
  467    (  NS == ''
  468    -> write(Out, Name)
  469    ;  format(Out, '~w:~w', [NS, Name])
  470    ).
  471emit_name(URI:Name, Out, State) :-
  472    get_state(State, nsmap, NSMap),
  473    memberchk(NS=URI, NSMap),
  474    !,
  475    (   NS == []
  476    ->  write(Out, Name)
  477    ;   format(Out, '~w:~w', [NS, Name])
  478    ).
  479emit_name(Term, Out, _) :-              % error?
  480    write(Out, Term).
 update_nsmap(+Attributes, -Attributes1, !State)
Modify the nsmap of State to reflect modifications due to xmlns arguments.
Arguments:
Attributes1- is a copy of Attributes with all redundant namespace attributes deleted.
  490update_nsmap(Attributes, Attributes1, State) :-
  491    get_state(State, nsmap, Map0),
  492    update_nsmap(Attributes, Attributes1, Map0, Map),
  493    set_state(State, nsmap, Map).
  494
  495update_nsmap([], [], Map, Map).
  496update_nsmap([xmlns:NS=URI|T], Attrs, Map0, Map) :-
  497    !,
  498    (   memberchk(NS=URI, Map0)
  499    ->  update_nsmap(T, Attrs, Map0, Map)
  500    ;   set_nsmap(NS, URI, Map0, Map1),
  501        Attrs = [xmlns:NS=URI|Attrs1],
  502        update_nsmap(T, Attrs1, Map1, Map)
  503    ).
  504update_nsmap([xmlns=URI|T], Attrs, Map0, Map) :-
  505    !,
  506    (   memberchk([]=URI, Map0)
  507    ->  update_nsmap(T, Attrs, Map0, Map)
  508    ;   set_nsmap([], URI, Map0, Map1),
  509        Attrs = [xmlns=URI|Attrs1],
  510        update_nsmap(T, Attrs1, Map1, Map)
  511    ).
  512update_nsmap([H|T0], [H|T], Map0, Map) :-
  513    !,
  514    update_nsmap(T0, T, Map0, Map).
  515
  516set_nsmap(NS, URI, Map0, Map) :-
  517    select(NS=_, Map0, Map1),
  518    !,
  519    Map = [NS=URI|Map1].
  520set_nsmap(NS, URI, Map, [NS=URI|Map]).
 content(+Content, +Out, +Element, +State, +Options)
Emit the content part of a structure as well as the termination for the content. For empty content we have three versions: XML style '/>', SGML declared EMPTY element (nothing) or normal SGML element (we must close with the same element name).
  530content([], Out, Element, State) :-    % empty element
  531    !,
  532    (   get_state(State, net, true)
  533    ->  (   get_state(State, dialect, xml) ->
  534            write(Out, />)
  535        ;   empty_element(State, Element) ->
  536            write(Out, >)
  537        ;   write(Out, //)
  538        )
  539    ;/* get_state(State, net, false) */
  540        write(Out, >),
  541        (   get_state(State, dialect, sgml),
  542            empty_element(State, Element)
  543        ->  true
  544        ;   emit_close(Element, Out, State)
  545        )
  546    ).
  547content([CDATA], Out, Element, State) :-
  548    atomic(CDATA),
  549    !,
  550    (   get_state(State, dialect, sgml),
  551        get_state(State, net, true),
  552        \+ sub_atom(CDATA, _, _, _, /),
  553        write_length(CDATA, Len, []),
  554        Len < 20
  555    ->  write(Out, /),
  556        sgml_write_content(Out, CDATA, State),
  557        write(Out, /)
  558    ;   verbatim_element(Element, State)
  559    ->  write(Out, >),
  560        write(Out, CDATA),
  561        emit_close(Element, Out, State)
  562    ;/* XML or not NET */
  563            write(Out, >),
  564        sgml_write_content(Out, CDATA, State),
  565        emit_close(Element, Out, State)
  566    ).
  567content(Content, Out, Element, State) :-
  568    get_state(State, layout, true),
  569    /* If xml:space='preserve' is present, */
  570        /* we MUST NOT tamper with white space at all. */
  571        \+ (Element = element(_,Atts,_),
  572        memberchk('xml:space'=preserve, Atts)
  573    ),
  574    element_content(Content, Elements),
  575    !,
  576    format(Out, >, []),
  577    \+ \+ (
  578        inc_indent(State),
  579        write_element_content(Elements, Out, State)
  580    ),
  581    write_indent(State, Out),
  582    emit_close(Element, Out, State).
  583content(Content, Out, Element, State) :-
  584    format(Out, >, []),
  585    write_mixed_content(Content, Out, Element, State),
  586    emit_close(Element, Out, State).
  587
  588verbatim_element(Element, State) :-
  589    verbatim_element(Element),
  590    get_state(State, dtd, DTD),
  591    DTD \== (-),
  592    dtd_property(DTD, doctype(html)).
  593
  594verbatim_element(script).
  595verbatim_element(style).
  596
  597emit_close(Element, Out, State) :-
  598    write(Out, '</'),
  599    emit_name(Element, Out, State),
  600    write(Out, '>').
  601
  602
  603write_mixed_content([], _, _, _).
  604write_mixed_content([H|T], Out, Element, State) :-
  605    write_mixed_content_element(H, Out, State),
  606    write_mixed_content(T, Out, Element, State).
  607
  608write_mixed_content_element(H, Out, State) :-
  609    (   atom(H)
  610    ->  sgml_write_content(Out, H, State)
  611    ;   string(H)
  612    ->  sgml_write_content(Out, H, State)
  613    ;   functor(H, element, 3)
  614    ->  emit(H, Out, State)
  615    ;   functor(H, pi, 1)
  616    ->  emit(H, Out, State)
  617    ;   var(H)
  618    ->  instantiation_error(H)
  619    ;   H = sdata(Data)             % cannot be written without entity!
  620    ->  print_message(warning, sgml_write(sdata_as_cdata(Data))),
  621        sgml_write_content(Out, Data, State)
  622    ;   type_error(sgml_content, H)
  623    ).
  624
  625
  626element_content([], []).
  627element_content([element(Name,Atts,C)|T0], [element(Name,Atts,C)|T]) :-
  628    !,
  629    element_content(T0, T).
  630element_content([Blank|T0], T) :-
  631    atom(Blank),
  632    atom_codes(Blank, Codes),
  633    all_blanks(Codes),
  634    element_content(T0, T).
  635
  636all_blanks([]).
  637all_blanks([H|T]) :-
  638    code_type(H, space),
  639    all_blanks(T).
  640
  641write_element_content([], _, _).
  642write_element_content([H|T], Out, State) :-
  643    write_indent(State, Out),
  644    emit(H, Out, State),
  645    write_element_content(T, Out, State).
  646
  647
  648                 /*******************************
  649                 *           NAMESPACES         *
  650                 *******************************/
 add_missing_namespaces(+DOM0, +NsMap, -DOM)
Add xmlns:NS=URI definitions to the toplevel element(s) to deal with missing namespaces.
  657add_missing_namespaces([], _, []) :- !.
  658add_missing_namespaces([H0|T0], Def, [H|T]) :-
  659    !,
  660    add_missing_namespaces(H0, Def, H),
  661    add_missing_namespaces(T0, Def, T).
  662add_missing_namespaces(Elem0, Def, Elem) :-
  663    Elem0 = element(Name, Atts0, Content),
  664    !,
  665    missing_namespaces(Elem0, Def, Missing),
  666    (   Missing == []
  667    ->  Elem = Elem0
  668    ;   add_missing_ns(Missing, Atts0, Atts),
  669        Elem = element(Name, Atts, Content)
  670    ).
  671add_missing_namespaces(DOM, _, DOM).    % CDATA, etc.
  672
  673add_missing_ns([], Atts, Atts).
  674add_missing_ns([H|T], Atts0, Atts) :-
  675    generate_ns(H, NS),
  676    add_missing_ns(T, [xmlns:NS=H|Atts0], Atts).
 generate_ns(+URI, -NS) is det
Generate a namespace (NS) identifier for URI.
  682generate_ns(URI, NS) :-
  683    xmlns(NS, URI),
  684    !.
  685generate_ns(URI, NS) :-
  686    default_ns(URI, NS),
  687    !.
  688generate_ns(_, NS) :-
  689    gensym(xns, NS).
 xmlns(?NS, ?URI) is nondet
Hook to define human readable abbreviations for XML namespaces. xml_write/3 tries these locations:
  1. This hook
  2. Defaults (see below)
  3. rdf_db:ns/2 for RDF-DB integration

Default XML namespaces are:

xsihttp://www.w3.org/2001/XMLSchema-instance
xshttp://www.w3.org/2001/XMLSchema
xhtmlhttp://www.w3.org/1999/xhtml
soap11http://schemas.xmlsoap.org/soap/envelope/
soap12http://www.w3.org/2003/05/soap-envelope
See also
- xml_write/2, rdf_register_ns/2.
  710:- multifile
  711    rdf_db:ns/2.  712
  713default_ns('http://www.w3.org/2001/XMLSchema-instance', xsi).
  714default_ns('http://www.w3.org/2001/XMLSchema',          xs).
  715default_ns('http://www.w3.org/1999/xhtml',              xhtml).
  716default_ns('http://schemas.xmlsoap.org/soap/envelope/', soap11).
  717default_ns('http://www.w3.org/2003/05/soap-envelope',   soap12).
  718default_ns(URI, NS) :-
  719    rdf_db:ns(NS, URI).
 missing_namespaces(+DOM, +NSMap, -Missing)
Return a list of URIs appearing in DOM that are not covered by xmlns definitions.
  726missing_namespaces(DOM, Defined, Missing) :-
  727    missing_namespaces(DOM, Defined, [], Missing).
  728
  729missing_namespaces([], _, L, L) :- !.
  730missing_namespaces([H|T], Def, L0, L) :-
  731    !,
  732    missing_namespaces(H, Def, L0, L1),
  733    missing_namespaces(T, Def, L1, L).
  734missing_namespaces(element(Name, Atts, Content), Def, L0, L) :-
  735    !,
  736    update_nsmap(Atts, _, Def, Def1),
  737    missing_ns(Name, Def1, L0, L1),
  738    missing_att_ns(Atts, Def1, L1, L2),
  739    missing_namespaces(Content, Def1, L2, L).
  740missing_namespaces(_, _, L, L).
  741
  742missing_att_ns([], _, M, M).
  743missing_att_ns([Name=_|T], Def, M0, M) :-
  744    missing_ns(Name, Def, M0, M1),
  745    missing_att_ns(T, Def, M1, M).
  746
  747missing_ns(ns(NS, URI):_, Def, M0, M) :-
  748    !,
  749    (  memberchk(NS=URI, Def)
  750    -> M = M0
  751    ;  NS == ''
  752    -> M = M0
  753    ;  M = [URI|M0]
  754    ).
  755missing_ns(URI:_, Def, M0, M) :-
  756    !,
  757    (   (   memberchk(_=URI, Def)
  758        ;   memberchk(URI, M0)
  759        ;   URI = xml               % predefined ones
  760        ;   URI = xmlns
  761        )
  762    ->  M = M0
  763    ;   M = [URI|M0]
  764    ).
  765missing_ns(_, _, M, M).
  766
  767                 /*******************************
  768                 *         QUOTED WRITE         *
  769                 *******************************/
  770
  771sgml_write_attribute(Out, Values, State) :-
  772    is_list(Values),
  773    !,
  774    get_state(State, entity_map, EntityMap),
  775    put_char(Out, '"'),
  776    write_quoted_list(Values, Out, '"<&\r\n\t', EntityMap),
  777    put_char(Out, '"').
  778sgml_write_attribute(Out, Value, State) :-
  779    is_text(Value),
  780    !,
  781    get_state(State, entity_map, EntityMap),
  782    put_char(Out, '"'),
  783    write_quoted(Out, Value, '"<&\r\n\t', EntityMap),
  784    put_char(Out, '"').
  785sgml_write_attribute(Out, Value, _State) :-
  786    number(Value),
  787    !,
  788    format(Out, '"~w"', [Value]).
  789sgml_write_attribute(_, Value, _) :-
  790    type_error(sgml_attribute_value, Value).
  791
  792write_quoted_list([], _, _, _).
  793write_quoted_list([H|T], Out, Escape, EntityMap) :-
  794    write_quoted(Out, H, Escape, EntityMap),
  795    (   T == []
  796    ->  true
  797    ;   put_char(Out, ' '),
  798        write_quoted_list(T, Out, Escape, EntityMap)
  799    ).
  800
  801
  802sgml_write_content(Out, Value, State) :-
  803    is_text(Value),
  804    !,
  805    get_state(State, entity_map, EntityMap),
  806    write_quoted(Out, Value, '<&>\r', EntityMap).
  807sgml_write_content(Out, Value, _) :-
  808    write(Out, Value).
  809
  810is_text(Value) :- atom(Value), !.
  811is_text(Value) :- string(Value), !.
  812
  813write_quoted(Out, Atom, Escape, EntityMap) :-
  814    atom(Atom),
  815    !,
  816    atom_codes(Atom, Codes),
  817    writeq(Codes, Out, Escape, EntityMap).
  818write_quoted(Out, String, Escape, EntityMap) :-
  819    string(String),
  820    !,
  821    string_codes(String, Codes),
  822    writeq(Codes, Out, Escape, EntityMap).
  823write_quoted(_, String, _, _) :-
  824    type_error(atom_or_string, String).
 writeq(+Text:codes, +Out:stream, +Escape:atom, +Escape:assoc) is det
  829writeq([], _, _, _).
  830writeq([H|T], Out, Escape, EntityMap) :-
  831    (   char_code(HC, H),
  832        sub_atom(Escape, _, _, _, HC)
  833    ->  write_entity(H, Out, EntityMap)
  834    ;   H >= 256
  835    ->  (   stream_property(Out, encoding(Enc)),
  836            unicode_encoding(Enc)
  837        ->  put_code(Out, H)
  838        ;   write_entity(H, Out, EntityMap)
  839        )
  840    ;   put_code(Out, H)
  841    ),
  842    writeq(T, Out, Escape, EntityMap).
  843
  844unicode_encoding(utf8).
  845unicode_encoding(wchar_t).
  846unicode_encoding(unicode_le).
  847unicode_encoding(unicode_be).
  848
  849write_entity(Code, Out, EntityMap) :-
  850    (   get_assoc(Code, EntityMap, EntityName)
  851    ->  format(Out, '&~w;', [EntityName])
  852    ;   format(Out, '&#x~16R;', [Code])
  853    ).
  854
  855
  856                 /*******************************
  857                 *          INDENTATION         *
  858                 *******************************/
  859
  860write_initial_indent(State, Out) :-
  861    (   get_state(State, indent, Indent),
  862        Indent > 0
  863    ->  emit_indent(Indent, Out)
  864    ;   true
  865    ).
  866
  867write_indent(State, _) :-
  868    get_state(State, layout, false),
  869    !.
  870write_indent(State, Out) :-
  871    get_state(State, indent, Indent),
  872    emit_indent(Indent, Out).
  873
  874emit_indent(Indent, Out) :-
  875    Tabs is Indent // 8,
  876    Spaces is Indent mod 8,
  877    format(Out, '~N', []),
  878    write_n(Tabs, '\t', Out),
  879    write_n(Spaces, ' ', Out).
  880
  881write_n(N, Char, Out) :-
  882    (   N > 0
  883    ->  put_char(Out, Char),
  884        N2 is N - 1,
  885        write_n(N2, Char, Out)
  886    ;   true
  887    ).
  888
  889inc_indent(State) :-
  890    inc_indent(State, 2).
  891
  892inc_indent(State, Inc) :-
  893    state(indent, Arg),
  894    arg(Arg, State, I0),
  895    I is I0 + Inc,
  896    setarg(Arg, State, I).
  897
  898
  899                 /*******************************
  900                 *         DTD HANDLING         *
  901                 *******************************/
 empty_element(+State, +Element)
True if Element is declared with EMPTY content in the (SGML) DTD.
  908empty_element(State, Element) :-
  909    get_state(State, dtd, DTD),
  910    DTD \== (-),
  911    dtd_property(DTD, element(Element, _, empty)).
 dtd_character_entities(+DTD, -Map)
Return an assoc mapping character entities to their name. Note that the entity representation is a bit dubious. Entities should allow for a wide-character version and avoid the &#..; trick.
  919dtd_character_entities(DTD, Map) :-
  920    empty_assoc(Empty),
  921    dtd_property(DTD, entities(Entities)),
  922    fill_entity_map(Entities, DTD, Empty, Map).
  923
  924fill_entity_map([], _, Map, Map).
  925fill_entity_map([H|T], DTD, Map0, Map) :-
  926    (   dtd_property(DTD, entity(H, CharEntity)),
  927        atom(CharEntity),
  928        (   sub_atom(CharEntity, 0, _, _, '&#'),
  929            sub_atom(CharEntity, _, _, 0, ';')
  930        ->  sub_atom(CharEntity, 2, _, 1, Name),
  931            atom_number(Name, Code)
  932        ;   atom_length(CharEntity, 1),
  933            char_code(CharEntity, Code)
  934        )
  935    ->  put_assoc(Code, Map0, H, Map1),
  936        fill_entity_map(T, DTD, Map1, Map)
  937    ;   fill_entity_map(T, DTD, Map0, Map)
  938    ).
  939
  940
  941
  942                 /*******************************
  943                 *            FIELDS            *
  944                 *******************************/
  945
  946state(indent,     1).                   % current indentation
  947state(layout,     2).                   % use layout (true/false)
  948state(dtd,        3).                   % DTD for entity names
  949state(entity_map, 4).                   % compiled entity-map
  950state(dialect,    5).                   % xml/sgml
  951state(nsmap,      6).                   % defined namespaces
  952state(net,        7).                   % Should null end-tags be used?
  953state(cleanns,    8).                   % Remove duplicate xmlns declarations
  954
  955new_state(Dialect,
  956    state(
  957        0,              % indent
  958        true,           % layout
  959        -,              % DTD
  960        EntityMap,      % entity_map
  961        Dialect,        % dialect
  962        [],             % NS=Full map
  963        Net,            % Null End-Tags?
  964        true            % Remove duplicate xmlns declarations
  965    )) :-
  966    (   Dialect == sgml
  967    ->  Net = false,
  968        empty_assoc(EntityMap)
  969    ;   Net = true,
  970        xml_entities(EntityMap)
  971    ).
  972
  973get_state(State, Field, Value) :-
  974    state(Field, Arg),
  975    arg(Arg, State, Value).
  976
  977set_state(State, Field, Value) :-
  978    state(Field, Arg),
  979    setarg(Arg, State, Value).
  980
  981term_expansion(xml_entities(map),
  982               xml_entities(Map)) :-
  983    list_to_assoc([ 0'< - lt,
  984                    0'& - amp,
  985                    0'> - gt,
  986                    0'\' - apos,
  987                    0'\" - quot
  988                  ], Map).
  989xml_entities(map).
  990
  991                 /*******************************
  992                 *            MESSAGES          *
  993                 *******************************/
  994
  995:- multifile
  996    prolog:message/3.  997
  998prolog:message(sgml_write(sdata_as_cdata(Data))) -->
  999    [ 'SGML-write: emitting SDATA as CDATA: "~p"'-[Data] ]