! Copyright (C) 2005, 2009 Daniel Ehrenberg ! See http://factorcode.org/license.txt for BSD license. USING: kernel sequences sequences.private assocs arrays delegate.protocols delegate vectors accessors multiline macros words quotations combinators slots fry strings ; IN: xml.data TUPLE: interpolated var ; C: interpolated UNION: nullable-string string POSTPONE: f ; TUPLE: name { space nullable-string } { main string } { url nullable-string } ; C: name : ?= ( object/f object/f -- ? ) 2dup and [ = ] [ 2drop t ] if ; : names-match? ( name1 name2 -- ? ) [ [ space>> ] bi@ ?= ] [ [ url>> ] bi@ ?= ] [ [ main>> ] bi@ ?= ] 2tri and and ; : ( string -- name ) "" swap f ; : ( string -- name ) f swap f ; : assure-name ( string/name -- name ) dup name? [ ] unless ; TUPLE: attrs { alist sequence } ; C: attrs : attr@ ( key alist -- index {key,value} ) [ assure-name ] dip alist>> [ first names-match? ] with find ; M: attrs at* attr@ nip [ second t ] [ f f ] if* ; M: attrs set-at 2dup attr@ nip [ 2nip set-second ] [ [ assure-name swap 2array ] dip [ alist>> ?push ] keep (>>alist) ] if* ; M: attrs assoc-size alist>> length ; M: attrs new-assoc drop V{ } new-sequence ; M: attrs >alist alist>> ; : >attrs ( assoc -- attrs ) dup [ V{ } assoc-clone-like [ [ assure-name ] dip ] assoc-map ] when ; M: attrs assoc-like drop dup attrs? [ >attrs ] unless ; M: attrs clear-assoc f >>alist drop ; M: attrs delete-at [ nip ] [ attr@ drop ] 2bi [ swap alist>> delete-nth ] [ drop ] if* ; M: attrs clone alist>> clone ; INSTANCE: attrs assoc TUPLE: opener { name name } { attrs attrs } ; C: opener TUPLE: closer { name name } ; C: closer TUPLE: contained { name name } { attrs attrs } ; C: contained TUPLE: comment { text string } ; C: comment TUPLE: directive ; TUPLE: element-decl < directive { name string } { content-spec string } ; C: element-decl TUPLE: attlist-decl < directive { name string } { att-defs string } ; C: attlist-decl UNION: boolean t POSTPONE: f ; TUPLE: entity-decl < directive { name string } { def string } { pe? boolean } ; C: entity-decl TUPLE: system-id { system-literal string } ; C: system-id TUPLE: public-id { pubid-literal string } { system-literal string } ; C: public-id UNION: id system-id public-id POSTPONE: f ; TUPLE: dtd { directives sequence } { entities assoc } { parameter-entities assoc } ; C: dtd UNION: dtd/f dtd POSTPONE: f ; TUPLE: doctype-decl < directive { name string } { external-id id } { internal-subset dtd/f } ; C: doctype-decl TUPLE: notation-decl < directive { name string } { id string } ; C: notation-decl TUPLE: instruction { text string } ; C: instruction TUPLE: prolog { version string } { encoding string } { standalone boolean } ; C: prolog TUPLE: tag { name name } { attrs attrs } { children sequence } ; : ( name attrs children -- tag ) [ assure-name ] [ T{ attrs } assoc-like ] [ ] tri* tag boa ; ! For convenience, tags follow the assoc protocol too (for attrs) CONSULT: assoc-protocol tag attrs>> ; INSTANCE: tag assoc ! They also follow the sequence protocol (for children) CONSULT: sequence-protocol tag children>> ; INSTANCE: tag sequence CONSULT: name tag name>> ; M: tag like over tag? [ drop ] [ [ name>> ] keep attrs>> rot dup [ V{ } like ] when ] if ; MACRO: clone-slots ( class -- tuple ) [ "slots" word-prop [ name>> reader-word '[ _ execute clone ] ] map '[ _ cleave ] ] [ '[ _ boa ] ] bi compose ; M: tag clone tag clone-slots ; TUPLE: xml { prolog prolog } { before sequence } { body tag } { after sequence } ; C: xml CONSULT: sequence-protocol xml body>> ; INSTANCE: xml sequence CONSULT: assoc-protocol xml body>> ; INSTANCE: xml assoc CONSULT: tag xml body>> ; CONSULT: name xml body>> ; xml ( xml tag -- newxml ) [ [ prolog>> ] [ before>> ] [ after>> ] tri ] dip swap ; : seq>xml ( xml seq -- newxml ) over body>> like tag>xml ; PRIVATE> M: xml clone xml clone-slots ; M: xml like swap dup xml? [ nip ] [ dup tag? [ tag>xml ] [ seq>xml ] if ] if ; ! tag with children=f is contained : ( name attrs -- tag ) f ; PREDICATE: contained-tag < tag children>> not ; PREDICATE: open-tag < tag children>> ; UNION: xml-data tag comment string directive instruction ; TUPLE: unescaped string ; C: unescaped