]> gitweb.factorcode.org Git - factor.git/commitdiff
moving xml.factor to httpd
authorDaniel Ehrenberg <microdan@gmail.com>
Thu, 3 Nov 2005 21:42:29 +0000 (21:42 +0000)
committerDaniel Ehrenberg <microdan@gmail.com>
Thu, 3 Nov 2005 21:42:29 +0000 (21:42 +0000)
contrib/httpd/xml.factor [new file with mode: 0644]
contrib/xml.factor [deleted file]

diff --git a/contrib/httpd/xml.factor b/contrib/httpd/xml.factor
new file mode 100644 (file)
index 0000000..20c5751
--- /dev/null
@@ -0,0 +1,419 @@
+USING: kernel math infix parser namespaces sequences strings prettyprint
+    errors lists hashtables vectors html io generic words ;
+IN: xml
+
+! * Simple SAX-ish parser
+
+!   -- Basic utility words
+
+SYMBOL: code #! Source code
+SYMBOL: spot #! Current index of string
+SYMBOL: version
+SYMBOL: line
+SYMBOL: column
+
+: set-code ( string -- ) ! for debugging
+    code set [ spot line column ] [ 0 swap set ] each ;
+
+: more? ( -- ? )
+    #! Return t if spot is not at the end of code
+    code get length spot get = not ;
+
+: char ( -- char/f )
+    more? [ spot get code get nth ] [ f ] if ;
+
+: incr-spot ( -- )
+    #! Increment spot.
+    spot [ 1 + ] change
+    char "\n\r" member? [
+        0 column set
+        line
+    ] [
+        column
+    ] if [ 1 + ] change ;
+
+: skip-until ( quot -- | quot: char -- ? )
+    more? [
+        char swap [ call ] keep swap [ drop ] [
+             incr-spot skip-until
+        ] if
+    ] [ drop ] if ; inline
+
+: take-until ( quot -- string | quot: char -- ? )
+    #! Take the substring of a string starting at spot
+    #! from code until the quotation given is true and
+    #! advance spot to after the substring.
+    spot get >r skip-until r>
+    spot get code get subseq ; inline
+
+: pass-blank ( -- )
+    #! Advance code past any whitespace, including newlines
+    [ blank? not ] skip-until ;
+
+: string-matches? ( string -- ? )
+    spot get dup pick length + code get subseq = ;
+
+DEFER: <xml-string-error>
+: (take-until-string) ( string -- n )
+    more? [
+        dup string-matches? [
+            drop spot get
+        ] [
+            incr-spot (take-until-string)
+        ] if
+    ] [ "Missing closing token" <xml-string-error> throw ] if ;
+
+: take-until-string ( string -- string )
+    [ >r spot get r> (take-until-string) code get subseq ] keep
+    length spot [ + ] change ;
+
+: in-range-seq? ( number { [[ min max ]] ... } -- ? )
+    [ uncons between? not ] all-with? not ;
+
+!   -- Error reporting
+
+TUPLE: xml-error line column ;
+C: xml-error ( -- xml-error )
+    [ line get swap set-xml-error-line ] keep
+    [ column get swap set-xml-error-column ] keep ;
+
+: xml-error. ( xml-error -- )
+    "XML error" print
+    "Line: " write dup xml-error-line .
+    "Column: " write xml-error-column . ;
+
+TUPLE: expected should-be was ;
+C: expected ( should-be was -- error )
+    [ <xml-error> swap set-delegate ] keep
+    [ set-expected-was ] keep
+    [ set-expected-should-be ] keep ;
+
+M: expected error.
+    dup xml-error.
+    "Token expected: " write dup expected-should-be print
+    "Token present: " write expected-was print ;
+
+TUPLE: no-entity thing ;
+C: no-entity ( string -- entitiy )
+    [ <xml-error> swap set-delegate ] keep
+    [ set-no-entity-thing ] keep ;
+
+M: no-entity error.
+    dup xml-error.
+    "Entity does not exist: &" write no-entity-thing write ";" print ;
+
+TUPLE: xml-string-error string ;
+C: xml-string-error ( -- xml-string-error )
+    [ set-xml-string-error-string ] keep
+    [ <xml-error> swap set-delegate ] keep ;
+
+M: xml-string-error error.
+    dup xml-error.
+    xml-string-error-string print ;
+
+!   -- Parsing strings
+
+: expect ( ch -- )
+    char 2dup = [ 2drop ] [
+        >r ch>string r> ch>string <expected> throw
+    ] if incr-spot ;
+
+: expect-string ( string -- )
+    >r spot get r> t over [ char incr-spot = and ] each [ 2drop ] [
+        swap spot get code get subseq <expected> throw
+    ] if ;
+
+: entities
+    H{
+        [[ "lt" CHAR: < ]]
+        [[ "gt" CHAR: > ]]
+        [[ "amp" CHAR: & ]]
+        [[ "apos" CHAR: ' ]]
+        [[ "quot" CHAR: " ]]
+    } ;
+
+: parse-entity ( -- ch )
+    incr-spot [ CHAR: ; = ] take-until incr-spot
+    dup first CHAR: # = [
+        1 swap tail "x" ?head 16 10 ? base>
+    ] [
+        dup entities hash [ nip ] [ <no-entity> throw ] if*
+    ] if ;
+
+: (parse-text) ( vector -- vector )
+    [ CHAR: & = ] take-until over push
+    char CHAR: & = [
+        parse-entity ch>string over push (parse-text)
+    ] when ;
+
+: parse-text ( string -- string )
+    [
+        code set 0 spot set
+        100 <vector> (parse-text) concat
+    ] with-scope ;
+
+: get-text ( -- string )
+    [ CHAR: < = ] take-until parse-text ;
+
+!   -- Parsing tags
+
+: name-start-char? ( ch -- ? )
+    dup ":_" member? swap {
+        [[ CHAR: A CHAR: Z ]] [[ CHAR: a CHAR: z ]] [[ HEX: C0 HEX: D6 ]]
+        [[ HEX: D8 HEX: F6 ]] [[ HEX: F8 HEX: 2FF ]] [[ HEX: 370 HEX: 37D ]]
+        [[ HEX: 37F HEX: 1FFF ]] [[ HEX: 200C HEX: 200D ]] [[ HEX: 2070 HEX: 218F ]]
+        [[ HEX: 2C00 HEX: 2FEF ]] [[ HEX: 3001 HEX: D7FF ]] [[ HEX: F900 HEX: FDCF ]]
+        [[ HEX: FDF0 HEX: FFFD ]] [[ HEX: 10000 HEX: EFFFF ]]
+    } in-range-seq? or ;
+
+: name-char? ( ch -- ? )
+    dup name-start-char? over "-." member? or over HEX: B7 = or swap
+    { [[ CHAR: 0 CHAR: 9 ]] [[ HEX: 300 HEX: 36F ]] [[ HEX: 203F HEX: 2040 ]] }
+    in-range-seq? or ;
+
+: parse-name ( -- name )
+    char dup name-start-char? [
+        incr-spot ch>string [ name-char? not ] take-until append
+    ] [
+        "Malformed name" <xml-string-error> throw
+    ] if ;
+
+: parse-quot ( ch -- str )
+    incr-spot [ dupd = ] take-until parse-text nip incr-spot ;
+
+: parse-prop-value ( -- str )
+    char dup "'\"" member? [
+        parse-quot
+    ] [
+        "Attribute lacks quote" <xml-string-error> throw
+    ] if ;
+
+: parse-prop ( -- [[ name value ]] )
+    parse-name pass-blank CHAR: = expect pass-blank
+    parse-prop-value cons pass-blank ;
+
+TUPLE: opener name props ;
+TUPLE: closer name ;
+TUPLE: contained name props ;
+TUPLE: comment text ;
+
+: start-tag ( -- string ? )
+    #! Outputs the name and whether this is a closing tag
+    char CHAR: / = dup [ incr-spot ] when
+    parse-name swap ;
+
+: (middle-tag) ( list -- list )
+    pass-blank char name-char? [ parse-prop swons (middle-tag) ] when ;
+
+: middle-tag ( -- hash )
+    f (middle-tag) alist>hash ;
+
+: end-tag ( string hash -- tag )
+    pass-blank char CHAR: / = [
+        <contained> incr-spot
+    ] [
+        <opener>
+    ] if ;
+
+: skip-comment ( -- comment )
+    "--" expect-string "--" take-until-string <comment> CHAR: > expect ;
+
+: cdata ( -- string )
+    "[CDATA[" expect-string "]]>" take-until-string ;
+
+: cdata/comment ( -- object )
+    incr-spot char CHAR: - = [ skip-comment ] [ cdata ] if ;
+
+: make-tag ( -- tag/f )
+    CHAR: < expect
+    char CHAR: ! = [
+        cdata/comment
+    ] [
+        start-tag [
+            <closer>
+        ] [
+            middle-tag end-tag
+        ] if pass-blank CHAR: > expect
+    ] if ;
+
+!   -- Overall
+
+: get-version ( -- )
+    "<?" string-matches? [
+        "<?xml" expect-string
+        pass-blank middle-tag "?>" expect-string
+        "version" swap hash [ version set ] when*
+    ] when ;
+
+: dip-ns ( quot -- )
+    n> slip >n ; inline
+
+: (xml-each) ( quot -- )
+    get-text swap [ dip-ns ] keep
+    more? [
+        make-tag [ swap [ dip-ns ] keep ] when* (xml-each)
+    ] [ drop ] if ; inline
+
+: xml-each ( string quot -- | quot: node -- )
+    #! Quotation is called with each node: an opener, closer, contained,
+    #! comment, or string
+    #! Somewhat like SAX but vastly simplified.
+    [
+        swap code set
+        [ spot line column ] [ 0 swap set ] each
+        "1.0" version set
+        get-version (xml-each)
+    ] with-scope ; inline
+
+! * Data tree
+
+TUPLE: tag name props children ;
+
+SYMBOL: xml-stack
+
+TUPLE: mismatched open close ;
+M: mismatched error.
+    "Mismatched tags" print
+    "Opening tag: <" write dup mismatched-open write ">" print
+    "Closing tag: </" write mismatched-close write ">" print ;
+
+TUPLE: unclosed tags ;
+C: unclosed ( -- unclosed )
+    1 xml-stack get tail-slice [ car opener-name ] map
+    swap [ set-unclosed-tags  ] keep ;
+M: unclosed error.
+    "Unclosed tags" print
+    "Tags: " print
+    unclosed-tags [ "  <" write write ">" print ] each ;
+
+: seq-last ( seq -- last )
+    [ length 1 - ] keep nth ;
+
+: push-datum ( object -- )
+    xml-stack get seq-last cdr push ;
+
+GENERIC: process ( object -- )
+
+M: string process push-datum ;
+M: comment process push-datum ;
+
+M: contained process
+    [ contained-name ] keep contained-props 0 <vector> <tag> push-datum ;
+
+M: opener process
+    V{ } clone cons
+    xml-stack get push ;
+
+M: closer process
+    closer-name xml-stack get pop uncons
+    >r [ 
+        opener-name [
+           2dup = [ 2drop ] [ swap <mismatched> throw ] if
+       ] keep
+    ] keep opener-props r> <tag> push-datum ;
+
+: initialize-xml-stack ( -- )
+    f V{ } clone cons unit >vector xml-stack set ;
+
+: xml ( string -- vector )
+    #! Produces a tree of XML nodes
+    [
+       initialize-xml-stack
+        [ process ] xml-each
+        xml-stack get
+        dup length 1 = [ <unclosed> throw ] unless
+        first cdr second
+    ] with-scope ;
+
+! * Printer
+
+: print-props ( hash -- )
+    [
+        " " % unswons % "=\"" % % "\"" %
+    ] hash-each ;
+
+GENERIC: (xml>string) ( object -- )
+
+: reverse-entities ! not as many as entities needed for printing
+    H{
+        [[ CHAR: & "amp" ]]
+        [[ CHAR: < "lt" ]]
+        [[ CHAR: " "quot" ]]
+    } ;
+
+M: string (xml>string)
+    [
+        dup reverse-entities hash [
+            CHAR: & , % CHAR: ; ,
+        ] [
+            ,
+        ] ?if
+    ] each ;
+
+: print-open/close ( tag -- )
+    CHAR: > ,
+    dup tag-children [ (xml>string) ] each
+    "</" %
+    tag-name %
+    CHAR: > , ;
+
+M: tag (xml>string)
+    CHAR: < ,
+    dup tag-name %
+    dup tag-props print-props
+    dup tag-children [ "" = not ] subset empty? [
+        drop "/>" %
+    ] [
+        print-open/close
+    ] if ;
+
+M: comment (xml>string)
+    "<!--" %
+    comment-text %
+    "-->" % ;
+
+: xml>string ( xml -- string )
+    [ (xml>string) ] "" make ;
+
+: xml-reprint ( string -- string )
+    xml xml>string ;
+
+! * Easy XML generation for more literal things
+! should this be rewritten?
+
+: text ( string -- )
+    chars>entities push-datum ;
+
+: tag ( string attr-quot contents-quot -- )
+    >r swap >r make-hash r> swap r> 
+    -rot dupd <opener> process
+    slip
+    <closer> process ; inline
+
+: comment ( string -- )
+    <comment> push-datum ;
+
+: make-xml ( quot -- vector )
+    #! Produces a tree of XML from a quotation to generate it
+    [
+        initialize-xml-stack
+        call
+        xml-stack get
+        first cdr second
+    ] with-scope ; inline
+
+! * System for words specialized on tag names
+
+: PROCESS:
+    CREATE
+    dup H{ } clone "xtable" set-word-prop
+    dup literalize [
+        "xtable" word-prop
+        >r dup tag-name r> hash call
+    ] cons define-compound ; parsing
+
+: TAG:
+    scan scan-word [
+        swap "xtable" word-prop
+        rot "/" split [ >r 2dup r> swap set-hash ] each 2drop
+    ] f ; parsing
diff --git a/contrib/xml.factor b/contrib/xml.factor
deleted file mode 100644 (file)
index 20c5751..0000000
+++ /dev/null
@@ -1,419 +0,0 @@
-USING: kernel math infix parser namespaces sequences strings prettyprint
-    errors lists hashtables vectors html io generic words ;
-IN: xml
-
-! * Simple SAX-ish parser
-
-!   -- Basic utility words
-
-SYMBOL: code #! Source code
-SYMBOL: spot #! Current index of string
-SYMBOL: version
-SYMBOL: line
-SYMBOL: column
-
-: set-code ( string -- ) ! for debugging
-    code set [ spot line column ] [ 0 swap set ] each ;
-
-: more? ( -- ? )
-    #! Return t if spot is not at the end of code
-    code get length spot get = not ;
-
-: char ( -- char/f )
-    more? [ spot get code get nth ] [ f ] if ;
-
-: incr-spot ( -- )
-    #! Increment spot.
-    spot [ 1 + ] change
-    char "\n\r" member? [
-        0 column set
-        line
-    ] [
-        column
-    ] if [ 1 + ] change ;
-
-: skip-until ( quot -- | quot: char -- ? )
-    more? [
-        char swap [ call ] keep swap [ drop ] [
-             incr-spot skip-until
-        ] if
-    ] [ drop ] if ; inline
-
-: take-until ( quot -- string | quot: char -- ? )
-    #! Take the substring of a string starting at spot
-    #! from code until the quotation given is true and
-    #! advance spot to after the substring.
-    spot get >r skip-until r>
-    spot get code get subseq ; inline
-
-: pass-blank ( -- )
-    #! Advance code past any whitespace, including newlines
-    [ blank? not ] skip-until ;
-
-: string-matches? ( string -- ? )
-    spot get dup pick length + code get subseq = ;
-
-DEFER: <xml-string-error>
-: (take-until-string) ( string -- n )
-    more? [
-        dup string-matches? [
-            drop spot get
-        ] [
-            incr-spot (take-until-string)
-        ] if
-    ] [ "Missing closing token" <xml-string-error> throw ] if ;
-
-: take-until-string ( string -- string )
-    [ >r spot get r> (take-until-string) code get subseq ] keep
-    length spot [ + ] change ;
-
-: in-range-seq? ( number { [[ min max ]] ... } -- ? )
-    [ uncons between? not ] all-with? not ;
-
-!   -- Error reporting
-
-TUPLE: xml-error line column ;
-C: xml-error ( -- xml-error )
-    [ line get swap set-xml-error-line ] keep
-    [ column get swap set-xml-error-column ] keep ;
-
-: xml-error. ( xml-error -- )
-    "XML error" print
-    "Line: " write dup xml-error-line .
-    "Column: " write xml-error-column . ;
-
-TUPLE: expected should-be was ;
-C: expected ( should-be was -- error )
-    [ <xml-error> swap set-delegate ] keep
-    [ set-expected-was ] keep
-    [ set-expected-should-be ] keep ;
-
-M: expected error.
-    dup xml-error.
-    "Token expected: " write dup expected-should-be print
-    "Token present: " write expected-was print ;
-
-TUPLE: no-entity thing ;
-C: no-entity ( string -- entitiy )
-    [ <xml-error> swap set-delegate ] keep
-    [ set-no-entity-thing ] keep ;
-
-M: no-entity error.
-    dup xml-error.
-    "Entity does not exist: &" write no-entity-thing write ";" print ;
-
-TUPLE: xml-string-error string ;
-C: xml-string-error ( -- xml-string-error )
-    [ set-xml-string-error-string ] keep
-    [ <xml-error> swap set-delegate ] keep ;
-
-M: xml-string-error error.
-    dup xml-error.
-    xml-string-error-string print ;
-
-!   -- Parsing strings
-
-: expect ( ch -- )
-    char 2dup = [ 2drop ] [
-        >r ch>string r> ch>string <expected> throw
-    ] if incr-spot ;
-
-: expect-string ( string -- )
-    >r spot get r> t over [ char incr-spot = and ] each [ 2drop ] [
-        swap spot get code get subseq <expected> throw
-    ] if ;
-
-: entities
-    H{
-        [[ "lt" CHAR: < ]]
-        [[ "gt" CHAR: > ]]
-        [[ "amp" CHAR: & ]]
-        [[ "apos" CHAR: ' ]]
-        [[ "quot" CHAR: " ]]
-    } ;
-
-: parse-entity ( -- ch )
-    incr-spot [ CHAR: ; = ] take-until incr-spot
-    dup first CHAR: # = [
-        1 swap tail "x" ?head 16 10 ? base>
-    ] [
-        dup entities hash [ nip ] [ <no-entity> throw ] if*
-    ] if ;
-
-: (parse-text) ( vector -- vector )
-    [ CHAR: & = ] take-until over push
-    char CHAR: & = [
-        parse-entity ch>string over push (parse-text)
-    ] when ;
-
-: parse-text ( string -- string )
-    [
-        code set 0 spot set
-        100 <vector> (parse-text) concat
-    ] with-scope ;
-
-: get-text ( -- string )
-    [ CHAR: < = ] take-until parse-text ;
-
-!   -- Parsing tags
-
-: name-start-char? ( ch -- ? )
-    dup ":_" member? swap {
-        [[ CHAR: A CHAR: Z ]] [[ CHAR: a CHAR: z ]] [[ HEX: C0 HEX: D6 ]]
-        [[ HEX: D8 HEX: F6 ]] [[ HEX: F8 HEX: 2FF ]] [[ HEX: 370 HEX: 37D ]]
-        [[ HEX: 37F HEX: 1FFF ]] [[ HEX: 200C HEX: 200D ]] [[ HEX: 2070 HEX: 218F ]]
-        [[ HEX: 2C00 HEX: 2FEF ]] [[ HEX: 3001 HEX: D7FF ]] [[ HEX: F900 HEX: FDCF ]]
-        [[ HEX: FDF0 HEX: FFFD ]] [[ HEX: 10000 HEX: EFFFF ]]
-    } in-range-seq? or ;
-
-: name-char? ( ch -- ? )
-    dup name-start-char? over "-." member? or over HEX: B7 = or swap
-    { [[ CHAR: 0 CHAR: 9 ]] [[ HEX: 300 HEX: 36F ]] [[ HEX: 203F HEX: 2040 ]] }
-    in-range-seq? or ;
-
-: parse-name ( -- name )
-    char dup name-start-char? [
-        incr-spot ch>string [ name-char? not ] take-until append
-    ] [
-        "Malformed name" <xml-string-error> throw
-    ] if ;
-
-: parse-quot ( ch -- str )
-    incr-spot [ dupd = ] take-until parse-text nip incr-spot ;
-
-: parse-prop-value ( -- str )
-    char dup "'\"" member? [
-        parse-quot
-    ] [
-        "Attribute lacks quote" <xml-string-error> throw
-    ] if ;
-
-: parse-prop ( -- [[ name value ]] )
-    parse-name pass-blank CHAR: = expect pass-blank
-    parse-prop-value cons pass-blank ;
-
-TUPLE: opener name props ;
-TUPLE: closer name ;
-TUPLE: contained name props ;
-TUPLE: comment text ;
-
-: start-tag ( -- string ? )
-    #! Outputs the name and whether this is a closing tag
-    char CHAR: / = dup [ incr-spot ] when
-    parse-name swap ;
-
-: (middle-tag) ( list -- list )
-    pass-blank char name-char? [ parse-prop swons (middle-tag) ] when ;
-
-: middle-tag ( -- hash )
-    f (middle-tag) alist>hash ;
-
-: end-tag ( string hash -- tag )
-    pass-blank char CHAR: / = [
-        <contained> incr-spot
-    ] [
-        <opener>
-    ] if ;
-
-: skip-comment ( -- comment )
-    "--" expect-string "--" take-until-string <comment> CHAR: > expect ;
-
-: cdata ( -- string )
-    "[CDATA[" expect-string "]]>" take-until-string ;
-
-: cdata/comment ( -- object )
-    incr-spot char CHAR: - = [ skip-comment ] [ cdata ] if ;
-
-: make-tag ( -- tag/f )
-    CHAR: < expect
-    char CHAR: ! = [
-        cdata/comment
-    ] [
-        start-tag [
-            <closer>
-        ] [
-            middle-tag end-tag
-        ] if pass-blank CHAR: > expect
-    ] if ;
-
-!   -- Overall
-
-: get-version ( -- )
-    "<?" string-matches? [
-        "<?xml" expect-string
-        pass-blank middle-tag "?>" expect-string
-        "version" swap hash [ version set ] when*
-    ] when ;
-
-: dip-ns ( quot -- )
-    n> slip >n ; inline
-
-: (xml-each) ( quot -- )
-    get-text swap [ dip-ns ] keep
-    more? [
-        make-tag [ swap [ dip-ns ] keep ] when* (xml-each)
-    ] [ drop ] if ; inline
-
-: xml-each ( string quot -- | quot: node -- )
-    #! Quotation is called with each node: an opener, closer, contained,
-    #! comment, or string
-    #! Somewhat like SAX but vastly simplified.
-    [
-        swap code set
-        [ spot line column ] [ 0 swap set ] each
-        "1.0" version set
-        get-version (xml-each)
-    ] with-scope ; inline
-
-! * Data tree
-
-TUPLE: tag name props children ;
-
-SYMBOL: xml-stack
-
-TUPLE: mismatched open close ;
-M: mismatched error.
-    "Mismatched tags" print
-    "Opening tag: <" write dup mismatched-open write ">" print
-    "Closing tag: </" write mismatched-close write ">" print ;
-
-TUPLE: unclosed tags ;
-C: unclosed ( -- unclosed )
-    1 xml-stack get tail-slice [ car opener-name ] map
-    swap [ set-unclosed-tags  ] keep ;
-M: unclosed error.
-    "Unclosed tags" print
-    "Tags: " print
-    unclosed-tags [ "  <" write write ">" print ] each ;
-
-: seq-last ( seq -- last )
-    [ length 1 - ] keep nth ;
-
-: push-datum ( object -- )
-    xml-stack get seq-last cdr push ;
-
-GENERIC: process ( object -- )
-
-M: string process push-datum ;
-M: comment process push-datum ;
-
-M: contained process
-    [ contained-name ] keep contained-props 0 <vector> <tag> push-datum ;
-
-M: opener process
-    V{ } clone cons
-    xml-stack get push ;
-
-M: closer process
-    closer-name xml-stack get pop uncons
-    >r [ 
-        opener-name [
-           2dup = [ 2drop ] [ swap <mismatched> throw ] if
-       ] keep
-    ] keep opener-props r> <tag> push-datum ;
-
-: initialize-xml-stack ( -- )
-    f V{ } clone cons unit >vector xml-stack set ;
-
-: xml ( string -- vector )
-    #! Produces a tree of XML nodes
-    [
-       initialize-xml-stack
-        [ process ] xml-each
-        xml-stack get
-        dup length 1 = [ <unclosed> throw ] unless
-        first cdr second
-    ] with-scope ;
-
-! * Printer
-
-: print-props ( hash -- )
-    [
-        " " % unswons % "=\"" % % "\"" %
-    ] hash-each ;
-
-GENERIC: (xml>string) ( object -- )
-
-: reverse-entities ! not as many as entities needed for printing
-    H{
-        [[ CHAR: & "amp" ]]
-        [[ CHAR: < "lt" ]]
-        [[ CHAR: " "quot" ]]
-    } ;
-
-M: string (xml>string)
-    [
-        dup reverse-entities hash [
-            CHAR: & , % CHAR: ; ,
-        ] [
-            ,
-        ] ?if
-    ] each ;
-
-: print-open/close ( tag -- )
-    CHAR: > ,
-    dup tag-children [ (xml>string) ] each
-    "</" %
-    tag-name %
-    CHAR: > , ;
-
-M: tag (xml>string)
-    CHAR: < ,
-    dup tag-name %
-    dup tag-props print-props
-    dup tag-children [ "" = not ] subset empty? [
-        drop "/>" %
-    ] [
-        print-open/close
-    ] if ;
-
-M: comment (xml>string)
-    "<!--" %
-    comment-text %
-    "-->" % ;
-
-: xml>string ( xml -- string )
-    [ (xml>string) ] "" make ;
-
-: xml-reprint ( string -- string )
-    xml xml>string ;
-
-! * Easy XML generation for more literal things
-! should this be rewritten?
-
-: text ( string -- )
-    chars>entities push-datum ;
-
-: tag ( string attr-quot contents-quot -- )
-    >r swap >r make-hash r> swap r> 
-    -rot dupd <opener> process
-    slip
-    <closer> process ; inline
-
-: comment ( string -- )
-    <comment> push-datum ;
-
-: make-xml ( quot -- vector )
-    #! Produces a tree of XML from a quotation to generate it
-    [
-        initialize-xml-stack
-        call
-        xml-stack get
-        first cdr second
-    ] with-scope ; inline
-
-! * System for words specialized on tag names
-
-: PROCESS:
-    CREATE
-    dup H{ } clone "xtable" set-word-prop
-    dup literalize [
-        "xtable" word-prop
-        >r dup tag-name r> hash call
-    ] cons define-compound ; parsing
-
-: TAG:
-    scan scan-word [
-        swap "xtable" word-prop
-        rot "/" split [ >r 2dup r> swap set-hash ] each 2drop
-    ] f ; parsing