REBOL [
	Title:		"RebXML to XML Converter"
	Date:		02-Mar-2009
	Version:	1.3.1
	File:		%rebxml2xml.r
	Author:		"John Niclasen"
	Rights:		{Copyright © John Niclasen, NicomSoft 2005}
	Purpose:	{Converts a RebXML block structure to XML.}
	History: [
		1.3.1	[02-Mar-2009 "JN"  {Fixed potential bug in EmptyElemTag.}]
		1.3.0	[08-Nov-2005 "JN"  {Fixed bug with value in Attribute.
									Added Comment.}]
		1.2.0	[26-Feb-2005 "JN"  {Added support for utf-8.}]
		1.1.1	[24-Feb-2005 "JN"  {Changed EmptyElemTag from # to a slash: /}]
		1.1.0	[23-Feb-2005 "JN"  {Added improved build-tag.
									Added support for namespace-tags.
									Changed EmptyElemTag from "" to a number sign: #}]
		1.0.1	[31-Jan-2005 "JN" {Added replacements for #"&", #"<" and #">".}]
		1.0.0	[25-Jan-2005 "JN" {Created.}]
	]
	library: [
		level: 'intermediate
		platform: 'all
		type: 'tool
		domain: [markup parse xml]
		tested-under: none
		support: none
		license: 'BSD
		see-also: "xml2rebxml.r"
	]
]

; An improved build-tag is here, because the original build-tag within REBOL can't cope with some types of tags.
build-tag: func [
    "Generates a tag from a composed block." 
    values [block!] "Block of parens to evaluate and other data." 
    /local tag value-rule xml? name attribute value
][
    tag: make string! 7 * length? values 
    value-rule: [
        set value issue! (value: mold value) 
        | set value file! (value: replace/all copy value #" " " ") 
        | set value any-type!
    ] 
    xml?: false 
    parse compose values [
        [
            set name ['?xml (xml?: true) | word! | url!] (append tag name) 
            any [
                set attribute [word! | url!] value-rule (
                    repend tag [#" " attribute {="} value {"}]
                ) 
                | value-rule (repend tag [#" " value])
            ] 
            end (if xml? [append tag #"?"])
        ] 
        | 
        [set name refinement! to end (tag: mold name)]
    ] 
    to tag! tag
]

context [

lit-slash: to-lit-word "/"
mark: none
convert2utf-8: off

tag: []
stack: []
name:
att:
value: none
output: make string! 16384

iso2utf-8: func [
	data	[string!]
	/local c2chars c3chars iso8859 mark
][
	c2chars: charset [#"^(A0)" - #"^(BF)"]
	c3chars: charset [#"^(C0)" - #"^(FF)"]
	iso8859: [any [
		mark: c2chars (mark: insert mark #"^(C2)") :mark skip |
		mark: c3chars (
			change mark to-char mark/1 - #"^(40)"
			mark: insert mark #"^(C3)"
		) :mark skip |
		skip
	]]

	parse/all data iso8859
	data
]
 
document: [prolog element]

prolog: [
	(either convert2utf-8 [
		insert output {^/}
	][
		insert output {^/}
	])
	;any Comment
	any CharData
]

element: [
	EmptyElemTag
	| STag [CharData | into content] ETag
]

STag: [
	set name [word! | url!] (clear tag insert tag name) any Attribute (
		insert tail output build-tag tag
		insert tail stack name
	)
]

Attribute: [
	mark: lit-slash :mark break
	| set att [word! | url!] set value string! (
		value: copy value
		replace/all value #"&" "&"
		replace/all value #"<" "<"
		replace/all value #">" ">"
		replace/all value #"'" "'"
		replace/all value #"^"" """
		insert tail tag reduce [att value]
	)
]

ETag: [
	(insert tail output to tag! rejoin [#"/" last stack]
	remove back tail stack)
]

EmptyElemTag: [
	set name [word! | url!] (clear tag insert tag name)
			[lit-slash | any Attribute lit-slash] (
		insert tail tag #"/"
		insert tail output build-tag tag
	)
]

content: [
	;opt CharData any [Comment | element opt CharData]
	any [CharData | element]
]

CharData: [
	set value string! (
		either (copy/part value 4) = "