renaming: contain? -> any?, deep-contains? -> deep-any?, pad-left -> pad-head, pad...
[factor/jcg.git] / basis / xml / xml.factor
blob5ca486a57fc2220e6743ab29ee6ca3eb0c199af7
1 ! Copyright (C) 2005, 2009 Daniel Ehrenberg
2 ! See http://factorcode.org/license.txt for BSD license.
3 USING: accessors arrays io io.encodings.binary io.files
4 io.streams.string kernel namespaces sequences strings io.encodings.utf8
5 xml.data xml.errors xml.elements ascii xml.entities
6 xml.writer xml.state xml.autoencoding assocs xml.tokenize
7 combinators.short-circuit xml.name ;
8 IN: xml
10 <PRIVATE
12 : add-child ( object -- )
13     xml-stack get peek second push ;
15 : push-xml ( object -- )
16     V{ } clone 2array xml-stack get push ;
18 : pop-xml ( -- object )
19     xml-stack get pop ;
21 GENERIC: process ( object -- )
23 M: object process add-child ;
25 M: prolog process
26     xml-stack get
27     { V{ { f V{ "" } } } V{ { f V{ } } } } member?
28     [ bad-prolog ] unless drop ;
30 : before-main? ( -- ? )
31     xml-stack get {
32         [ length 1 = ]
33         [ first second [ tag? ] any? not ]
34     } 1&& ;
36 M: directive process
37     before-main? [ misplaced-directive ] unless add-child ;
39 M: contained process
40     [ name>> ] [ attrs>> ] bi
41     <contained-tag> add-child ;
43 M: opener process push-xml ;
45 : check-closer ( name opener -- name opener )
46     dup [ unopened ] unless
47     2dup name>> =
48     [ name>> swap mismatched ] unless ;
50 M: closer process
51     name>> pop-xml first2
52     [ check-closer attrs>> ] dip
53     <tag> add-child ;
55 : init-xml-stack ( -- )
56     V{ } clone xml-stack set
57     f push-xml ;
59 : default-prolog ( -- prolog )
60     "1.0" "UTF-8" f <prolog> ;
62 : init-xml ( -- )
63     init-ns-stack
64     extra-entities [ H{ } assoc-like ] change ;
66 : assert-blanks ( seq pre? -- )
67     swap [ string? ] filter
68     [
69         dup [ blank? ] all?
70         [ drop ] [ swap pre/post-content ] if
71     ] each drop ;
73 : no-pre/post ( pre post -- pre post/* )
74     ! this does *not* affect the contents of the stack
75     [ dup t assert-blanks ] [ dup f assert-blanks ] bi* ;
77 : no-post-tags ( post -- post/* )
78     ! this does *not* affect the contents of the stack
79     dup [ tag? ] any? [ multitags ] when ; 
81 : assure-tags ( seq -- seq )
82     ! this does *not* affect the contents of the stack
83     [ notags ] unless* ;
85 : get-prolog ( seq -- prolog )
86     first dup prolog? [ drop default-prolog ] unless ;
88 : make-xml-doc ( seq -- xml-doc )
89     [ get-prolog ] keep
90     dup [ tag? ] find
91     [ assure-tags cut rest no-pre/post no-post-tags ] dip
92     swap <xml> ;
94 ! * Views of XML
96 SYMBOL: text-now?
98 PRIVATE>
100 TUPLE: pull-xml scope ;
101 : <pull-xml> ( -- pull-xml )
102     [
103         input-stream [ ] change ! bring var in this scope
104         init-xml text-now? on
105     ] H{ } make-assoc
106     pull-xml boa ;
107 ! pull-xml needs to call start-document somewhere
109 : pull-event ( pull -- xml-event/f )
110     scope>> [
111         text-now? get [ parse-text f ] [
112             get-char [ make-tag t ] [ f f ] if
113         ] if text-now? set
114     ] bind ;
116 <PRIVATE
118 : done? ( -- ? )
119     xml-stack get length 1 = ;
121 : (pull-elem) ( pull -- xml-elem/f )
122     dup pull-event dup closer? done? and [ nip ] [
123         process done?
124         [ drop xml-stack get first second ]
125         [ (pull-elem) ] if
126     ] if ;
128 PRIVATE>
130 : pull-elem ( pull -- xml-elem/f )
131     [ init-xml-stack (pull-elem) ] with-scope ;
133 <PRIVATE
135 : call-under ( quot object -- quot )
136     swap dup slip ; inline
138 : xml-loop ( quot: ( xml-elem -- ) -- )
139     parse-text call-under
140     get-char [ make-tag call-under xml-loop ]
141     [ drop ] if ; inline recursive
143 : read-seq ( stream quot n -- seq )
144     rot [
145         depth set
146         init-xml init-xml-stack
147         call
148         [ process ] xml-loop
149         done? [ unclosed ] unless
150         xml-stack get first second
151     ] with-state ; inline
153 PRIVATE>
155 : each-element ( stream quot: ( xml-elem -- ) -- )
156     swap [
157         init-xml
158         start-document [ call-under ] when*
159         xml-loop
160     ] with-state ; inline
162 : read-xml ( stream -- xml )
163     [ start-document [ process ] when* ]
164     0 read-seq make-xml-doc ;
166 : read-xml-chunk ( stream -- seq )
167     [ check ] 1 read-seq <xml-chunk> ;
169 : string>xml ( string -- xml )
170     <string-reader> [ check ] 0 read-seq make-xml-doc ;
172 : string>xml-chunk ( string -- xml )
173     <string-reader> read-xml-chunk ;
175 : file>xml ( filename -- xml )
176     binary <file-reader> read-xml ;
178 : read-dtd ( stream -- dtd )
179     [
180         H{ } clone extra-entities set
181         take-internal-subset
182     ] with-state ;
184 : file>dtd ( filename -- dtd )
185     utf8 <file-reader> read-dtd ;
187 : string>dtd ( string -- dtd )
188     <string-reader> read-dtd ;