module DTD where
import XML
import qualified AssocList as FM
type GI = Name
type DCN = Name
data CE a =
Prim a
| Rep (CE a)
| Opt (CE a)
| Plus (CE a)
| Seq [(CE a)]
| Or [(CE a)]
| And [(CE a)]
deriving Eq
data PrimitiveToken =
PCDATA
| ELEMENT GI
deriving Eq
type ModelGroup = CE PrimitiveToken
data CONTYPE =
DC_EMPTY
| DC_ANY
| DC_MODELGRP ModelGroup
deriving Show
data ELEMTYPE = ELEMTYPE {
gi :: GI,
contype :: CONTYPE,
omissibility:: (Bool,Bool),
inclusions :: [GI],
exclusions :: [GI] } deriving Show
data ATT_TYPE =
ATcdata
| ATentity
| ATentities
| ATid
| ATidref
| ATidrefs
| ATnmtoken
| ATnmtokens
| ATnotation [DCN]
| ATenumerated [Name]
deriving Show
data ATT_DV =
ADVfixed String
| ADVrequired
| ADVimplied
| ADVdefault String
| ADVcurrent
| ADVconref
deriving Show
data ATTDEF = ATTDEF {
att_name :: Name,
att_type :: ATT_TYPE,
att_dv :: ATT_DV } deriving Show
type ATTSPEC = (Name,String)
type ExternalID = (Maybe PUBID, Maybe SYSID)
type PUBID = String
type SYSID = String
data ENTTYPE =
ETtext
| ETcdata
| ETsdata
| ETndata
| ETsubdoc
| ETpi
data EntityText =
EN_INTERNAL String
| EN_EXTERNAL ExternalID
deriving Show
data Entity = Entity {
ename :: Name,
etype :: ENTTYPE,
etext :: EntityText,
edcn :: Maybe DCN,
eatts :: [ATTSPEC]
}
type EntityMap = FM.FM Name EntityText
predefinedEntities :: EntityMap
predefinedEntities = foldr (uncurry FM.insert) FM.empty predefinedGEs
where
(==>) = \a b -> (a,EN_INTERNAL b)
predefinedGEs = [
"lt" ==> "<",
"amp" ==> "&",
"gt" ==> ">",
"apos" ==> "'",
"quot" ==> "\"" ]
expandInternalEntity :: EntityMap -> Name -> Maybe String
expandInternalEntity entities name =
case FM.lookupM entities name of
Just (EN_INTERNAL text) -> Just text
_ -> Nothing
data DTD = DTD {
elements :: FM.FM Name ELEMTYPE,
attlists :: FM.FM Name [ATTDEF],
genents :: FM.FM Name EntityText,
parments :: FM.FM Name EntityText,
notations:: [DCN],
dtdname :: Name
} deriving Show
emptyDTD :: DTD
emptyDTD = DTD {
elements = FM.empty,
attlists = FM.empty,
genents = predefinedEntities,
parments = FM.empty,
dtdname = "",
notations= []
}
declareParameterEntity,declareGeneralEntity :: Name -> EntityText -> DTD -> DTD
declareParameterEntity name entityText dtd =
dtd { parments = FM.insertWith keepOld name entityText (parments dtd) }
where keepOld old _new = old
declareGeneralEntity name entityText dtd =
dtd { genents = FM.insertWith keepOld name entityText (genents dtd) }
where keepOld old _new = old
declareElements :: [GI] -> (Bool,Bool) -> CONTYPE -> ([GI],[GI]) -> DTD -> DTD
declareElements elementNames omissibility contentDefinition (incl,excl) dtd =
dtd { elements = foldl mkElement (elements dtd) elementNames }
where mkElement fm gi = FM.insert gi el fm where
el = ELEMTYPE {
gi = gi,
contype = contentDefinition,
omissibility = omissibility,
inclusions = incl,
exclusions = excl
}
declareAttlist :: [GI] -> [ATTDEF] -> DTD -> DTD
declareAttlist elementNames attdefs dtd =
dtd { attlists = foldl addAttdefs (attlists dtd) elementNames }
where addAttdefs fm gi = FM.insert gi attdefs fm
declareNotation :: DCN -> ExternalID -> DTD -> DTD
declareNotation dcn _unused dtd =
dtd { notations = dcn : notations dtd }
instance Show PrimitiveToken where
showsPrec _ PCDATA = showString "#PCDATA"
showsPrec _ (ELEMENT gi) = showString gi
instance (Show prim) => Show (CE prim) where
showsPrec _ mg = pp mg where
pp (Prim p) = shows p
pp (Rep x) = shows x . showString "*"
pp (Opt x) = shows x . showString "?"
pp (Plus x) = shows x . showString "+"
pp (Seq x) = showgroup ", " x
pp (Or x) = showgroup " | " x
pp (And x) = showgroup " & " x
showgroup delim l = showString "(" . showl l . showString ")" where
showl [x] = shows x
showl (x:xs) = shows x . showString delim . showl xs
showl [] = showString "-- ERROR: empty model group! --"