/* xml_generation.pl : Document -> XML translation * * Copyright (C) 2001-2005 Binding Time Limited * Copyright (C) 2005-2011 John Fletcher * * Current Release: $Revision: 3.7 $ * * TERMS AND CONDITIONS: * * This program is offered free of charge, as unsupported source code. You may * use it, copy it, distribute it, modify it or sell it without restriction, * but entirely at your own risk. */ :- ensure_loaded( xml_utilities ). /* document_generation( +Format, +Document ) is a DCG generating Document * as a list of character codes. Format is true|false defining whether layouts, * to provide indentation, should be added between the element content of * the resultant "string". Note that formatting is disabled for elements that * are interspersed with pcdata/1 terms, such as XHTML's 'inline' elements. * Also, Format is over-ridden, for an individual element, by an explicit * 'xml:space'="preserve" attribute. */ document_generation( Format, xml(Attributes, Document) ) --> document_generation_body( Attributes, Format, Document ). document_generation_body( [], Format, Document ) --> generation( Document, "", Format, [], _Format1 ). document_generation_body( Attributes, Format, Document ) --> { Attributes = [_|_], xml_declaration_attributes_valid( Attributes ) }, "", indent( true, [] ), generation( Document, "", Format0, [], _Format1 ). generation( [], _Prefix, Format, _Indent, Format ) --> []. generation( [Term|Terms], Prefix, Format0, Indent, Format ) --> generation( Term, Prefix, Format0, Indent, Format1 ), generation( Terms, Prefix, Format1, Indent, Format ). generation( doctype(Name, External), _Prefix, Format, [], Format ) --> "". generation( instructions(Target,Process), _Prefix, Format, Indent, Format ) --> indent( Format, Indent ), "". generation( pcdata(Chars), _Prefix, Format0, _Indent, Format1 ) --> pcdata_generation( Chars ), {character_data_format( Chars, Format0, Format1 )}. generation( comment( Comment ), _Prefix, Format, Indent, Format ) --> indent( Format, Indent ), "". generation( namespace(URI, Prefix, element(Name, Atts, Content)), _Prefix0, Format, Indent, Format ) --> indent( Format, Indent ), "<", generated_prefixed_name( Prefix, Name ), generated_prefixed_attributes( Prefix, URI, Atts, Format, Format1 ), generated_content( Content, Format1, Indent, Prefix, Name ). generation( element(Name, Atts, Content), Prefix, Format, Indent, Format ) --> indent( Format, Indent ), "<", generated_prefixed_name( Prefix, Name ), generated_attributes( Atts, Format, Format1 ), generated_content( Content, Format1, Indent, Prefix, Name ). generation( cdata(CData), _Prefix, Format0, _Indent, Format1 ) --> "", {character_data_format( CData, Format0, Format1 )}. generated_attributes( [], Format, Format ) --> []. generated_attributes( [Name=Value|Attributes], Format0, Format ) --> {( Name == 'xml:space', Value="preserve" -> Format1 = false ; otherwise -> Format1 = Format0 )}, " ", generated_name( Name ), "=""", quoted_string( Value ), """", generated_attributes( Attributes, Format1, Format ). generated_prefixed_name( [], Name ) --> generated_name( Name ). generated_prefixed_name( Prefix, Name ) --> {Prefix = [_|_]}, chars( Prefix ), ":", generated_name( Name ). generated_content( [], _Format, _Indent, _Prefix, _Namespace ) --> " />". % Leave an extra space for XHTML output. generated_content( [H|T], Format, Indent, Prefix, Namespace ) --> ">", generation( H, Prefix, Format, [0' |Indent], Format1 ), generation( T, Prefix, Format1, [0' |Indent], Format2 ), indent( Format2, Indent ), "". generated_prefixed_attributes( [_|_Prefix], _URI, Atts, Format0, Format ) --> generated_attributes( Atts, Format0, Format ). generated_prefixed_attributes( [], URI, Atts, Format0, Format ) --> {atom_codes( URI, Namespace ), findall( Attr, (member(Attr, Atts), \+ Attr=(xmlns=_Val)), Atts1 ) }, generated_attributes( [xmlns=Namespace|Atts1], Format0, Format ). generated_name( Name, Plus, Minus ) :- atom_codes( Name, Chars ), append( Chars, Minus, Plus ). generated_external_id( local ) --> "". generated_external_id( local(Literals) ) --> " [", generated_doctype_literals( Literals ), " ]". generated_external_id( system(URL) ) --> " SYSTEM """, chars( URL ), """". generated_external_id( system(URL,Literals) ) --> " SYSTEM """, chars( URL ), """ [", generated_doctype_literals( Literals ), " ]". generated_external_id( public(URN,URL) ) --> " PUBLIC """, chars( URN ), """ """, chars( URL ), """". generated_external_id( public(URN,URL,Literals) ) --> " PUBLIC """, chars( URN ), """ """, chars( URL ), """ [", generated_doctype_literals( Literals ), " ]". generated_doctype_literals( [] ) --> "". generated_doctype_literals( [dtd_literal(String)|Literals] ) --> " ", generated_doctype_literals( Literals ). /* quoted_string( +Chars ) is a DCG representing Chars, a list of character * codes, as a legal XML attribute string. Any leading or trailing layout * characters are removed. &, " and < characters are replaced by &, " * and < respectively, . */ quoted_string( Raw, Plus, Minus ) :- quoted_string1( Raw, NoLeadingLayouts ), quoted_string2( NoLeadingLayouts, Layout, Layout, Plus, Minus ). quoted_string1( [], [] ). quoted_string1( [Char|Chars], NoLeadingLayouts ) :- ( Char > 32 -> NoLeadingLayouts = [Char|Chars] ; otherwise -> quoted_string1( Chars, NoLeadingLayouts ) ). quoted_string2( [], _LayoutPlus, _LayoutMinus, List, List ). quoted_string2( [Char|Chars], LayoutPlus, LayoutMinus, Plus, Minus ) :- ( Char =< " " -> Plus = Plus1, LayoutMinus = [Char|LayoutMinus1], LayoutPlus = LayoutPlus1 ; Char == 34 -> Plus = LayoutPlus, escaped_quote( LayoutMinus, Plus1 ), LayoutPlus1 = LayoutMinus1 ; Char == 39 -> Plus = LayoutPlus, apos( LayoutMinus, Plus1 ), LayoutPlus1 = LayoutMinus1 ; Char =< 127 -> Plus = LayoutPlus, pcdata_7bit( Char, LayoutMinus, Plus1 ), LayoutPlus1 = LayoutMinus1 ; legal_xml_unicode( Char ) -> Plus = LayoutPlus, number_codes( Char, Codes ), pcdata_8bits_plus( Codes, LayoutMinus, Plus1 ), LayoutPlus1 = LayoutMinus1 ; otherwise -> LayoutPlus = LayoutPlus1, LayoutMinus = LayoutMinus1, Plus = Plus1 ), quoted_string2( Chars, LayoutPlus1, LayoutMinus1, Plus1, Minus ). indent( false, _Indent ) --> []. indent( true, Indent ) --> [10], chars( Indent ). apos --> "'". escaped_quote --> """. /* pcdata_generation( +Chars ) is a DCG representing Chars, a list of character * codes as legal XML "Parsed character data" (PCDATA) string. Any codes * which cannot be represented by a 7-bit character are replaced by their * decimal numeric character entity e.g. code 160 (non-breaking space) is * represented as  . Any character codes disallowed by the XML * specification are not encoded. */ pcdata_generation( [], Plus, Plus ). pcdata_generation( [Char|Chars], Plus, Minus ) :- ( Char =< 127 -> pcdata_7bit( Char, Plus, Mid ) ; legal_xml_unicode( Char ) -> number_codes( Char, Codes ), pcdata_8bits_plus( Codes, Plus, Mid ) ; otherwise -> Plus = Mid ), pcdata_generation( Chars, Mid, Minus ). /* pcdata_7bit(+Char) represents the ascii character set in its * simplest format, using the character entities & < and >. */ pcdata_7bit( 0 ) --> "". pcdata_7bit( 1 ) --> "". pcdata_7bit( 2 ) --> "". pcdata_7bit( 3 ) --> "". pcdata_7bit( 4 ) --> "". pcdata_7bit( 5 ) --> "". pcdata_7bit( 6 ) --> "". pcdata_7bit( 7 ) --> "". pcdata_7bit( 8 ) --> "". pcdata_7bit( 9 ) --> [9]. pcdata_7bit( 10 ) --> [10]. pcdata_7bit( 11 ) --> "". pcdata_7bit( 12 ) --> "". pcdata_7bit( 13 ) --> [13]. pcdata_7bit( 14 ) --> "". pcdata_7bit( 15 ) --> "". pcdata_7bit( 16 ) --> "". pcdata_7bit( 17 ) --> "". pcdata_7bit( 18 ) --> "". pcdata_7bit( 19 ) --> "". pcdata_7bit( 20 ) --> "". pcdata_7bit( 21 ) --> "". pcdata_7bit( 22 ) --> "". pcdata_7bit( 23 ) --> "". pcdata_7bit( 24 ) --> "". pcdata_7bit( 25 ) --> "". pcdata_7bit( 26 ) --> "". pcdata_7bit( 27 ) --> "". pcdata_7bit( 28 ) --> "". pcdata_7bit( 29 ) --> "". pcdata_7bit( 30 ) --> "". pcdata_7bit( 31 ) --> "". pcdata_7bit( 32 ) --> " ". pcdata_7bit( 33 ) --> "!". pcdata_7bit( 34 ) --> [34]. pcdata_7bit( 35 ) --> "#". pcdata_7bit( 36 ) --> "$". pcdata_7bit( 37 ) --> "%". pcdata_7bit( 38 ) --> "&". pcdata_7bit( 39 ) --> "'". pcdata_7bit( 40 ) --> "(". pcdata_7bit( 41 ) --> ")". pcdata_7bit( 42 ) --> "*". pcdata_7bit( 43 ) --> "+". pcdata_7bit( 44 ) --> ",". pcdata_7bit( 45 ) --> "-". pcdata_7bit( 46 ) --> ".". pcdata_7bit( 47 ) --> "/". pcdata_7bit( 48 ) --> "0". pcdata_7bit( 49 ) --> "1". pcdata_7bit( 50 ) --> "2". pcdata_7bit( 51 ) --> "3". pcdata_7bit( 52 ) --> "4". pcdata_7bit( 53 ) --> "5". pcdata_7bit( 54 ) --> "6". pcdata_7bit( 55 ) --> "7". pcdata_7bit( 56 ) --> "8". pcdata_7bit( 57 ) --> "9". pcdata_7bit( 58 ) --> ":". pcdata_7bit( 59 ) --> ";". pcdata_7bit( 60 ) --> "<". pcdata_7bit( 61 ) --> "=". pcdata_7bit( 62 ) --> ">". % escaping necessary to prevent ']]>' sequences in pcdata. pcdata_7bit( 63 ) --> "?". pcdata_7bit( 64 ) --> "@". pcdata_7bit( 65 ) --> "A". pcdata_7bit( 66 ) --> "B". pcdata_7bit( 67 ) --> "C". pcdata_7bit( 68 ) --> "D". pcdata_7bit( 69 ) --> "E". pcdata_7bit( 70 ) --> "F". pcdata_7bit( 71 ) --> "G". pcdata_7bit( 72 ) --> "H". pcdata_7bit( 73 ) --> "I". pcdata_7bit( 74 ) --> "J". pcdata_7bit( 75 ) --> "K". pcdata_7bit( 76 ) --> "L". pcdata_7bit( 77 ) --> "M". pcdata_7bit( 78 ) --> "N". pcdata_7bit( 79 ) --> "O". pcdata_7bit( 80 ) --> "P". pcdata_7bit( 81 ) --> "Q". pcdata_7bit( 82 ) --> "R". pcdata_7bit( 83 ) --> "S". pcdata_7bit( 84 ) --> "T". pcdata_7bit( 85 ) --> "U". pcdata_7bit( 86 ) --> "V". pcdata_7bit( 87 ) --> "W". pcdata_7bit( 88 ) --> "X". pcdata_7bit( 89 ) --> "Y". pcdata_7bit( 90 ) --> "Z". pcdata_7bit( 91 ) --> "[". pcdata_7bit( 92 ) --> [92]. pcdata_7bit( 93 ) --> "]". pcdata_7bit( 94 ) --> "^". pcdata_7bit( 95 ) --> "_". pcdata_7bit( 96 ) --> "`". pcdata_7bit( 97 ) --> "a". pcdata_7bit( 98 ) --> "b". pcdata_7bit( 99 ) --> "c". pcdata_7bit( 100 ) --> "d". pcdata_7bit( 101 ) --> "e". pcdata_7bit( 102 ) --> "f". pcdata_7bit( 103 ) --> "g". pcdata_7bit( 104 ) --> "h". pcdata_7bit( 105 ) --> "i". pcdata_7bit( 106 ) --> "j". pcdata_7bit( 107 ) --> "k". pcdata_7bit( 108 ) --> "l". pcdata_7bit( 109 ) --> "m". pcdata_7bit( 110 ) --> "n". pcdata_7bit( 111 ) --> "o". pcdata_7bit( 112 ) --> "p". pcdata_7bit( 113 ) --> "q". pcdata_7bit( 114 ) --> "r". pcdata_7bit( 115 ) --> "s". pcdata_7bit( 116 ) --> "t". pcdata_7bit( 117 ) --> "u". pcdata_7bit( 118 ) --> "v". pcdata_7bit( 119 ) --> "w". pcdata_7bit( 120 ) --> "x". pcdata_7bit( 121 ) --> "y". pcdata_7bit( 122 ) --> "z". pcdata_7bit( 123 ) --> "{". pcdata_7bit( 124 ) --> "|". pcdata_7bit( 125 ) --> "}". pcdata_7bit( 126 ) --> [126]. pcdata_7bit( 127 ) --> "". pcdata_8bits_plus( Codes ) --> "&#", chars( Codes ), ";". /* character_data_format( +Chars, +Format0, ?Format1 ) holds when Format0 and * Format1 are the statuses of XML formatting before and after Chars - * which may be null. */ character_data_format( [], Format, Format ). character_data_format( [_Char|_Chars], _Format, false ). /* cdata_generation( +Chars ) is a DCG representing Chars, a list of character * codes as a legal XML CDATA string. Any character codes disallowed by the XML * specification are not encoded. */ cdata_generation( [] ) --> "". cdata_generation( [Char|Chars] ) --> ( {legal_xml_unicode( Char )}, !, [Char] ; "" ), cdata_generation( Chars ). legal_xml_unicode( 9 ). legal_xml_unicode( 10 ). legal_xml_unicode( 13 ). legal_xml_unicode( Code ) :- Code >= 32, Code =< 55295. legal_xml_unicode( Code ) :- Code >= 57344, Code =< 65533. legal_xml_unicode( Code ) :- Code >= 65536, Code =< 1114111.