import Text.XML.HXT.Core (
ArrowXml,
IOStateArrow,
+ SysConfigList,
XmlTree,
(>>>),
(/>),
is_type1,
pickle_message,
teams_are_normal )
-import Xml ( DtdName(..), parse_opts )
+import Xml ( DtdName(..), parse_opts, parse_opts_novalidate )
-- | This is where most of the work happens. This function is called
results <- parse_and_import `catch` exception_handler
case results of
[] -> do
- -- One of the arrows returned "nothing."
- report_error $ "Unable to determine DTD for file " ++ path ++ "."
- return False
+ -- One of the arrows returned "nothing." Now that we're
+ -- validating against the DTDs, this will almost always be
+ -- caused by a document whose DTD is not present (i.e. is
+ -- unsupported). So we return "success" to allow the XML file to
+ -- be deleted.
+ report_error $ "No DTD for file " ++ path ++ "."
+ return True
(ImportFailed errmsg:_) -> do
report_error $ errmsg ++ " (" ++ path ++ ")"
return False
-- we couldn't parse the DTD.
return [ImportFailed errdesc]
- -- | An arrow that reads a document into an 'XmlTree'.
- readA :: IOStateArrow s a XmlTree
- readA = readDocument parse_opts path
+ -- | An arrow that reads a document into an 'XmlTree'. We take a
+ -- SysConfigList so our caller can decide whether or not to
+ -- e.g. validate the document against its DTD.
+ readA :: SysConfigList -> IOStateArrow s a XmlTree
+ readA scl = readDocument scl path
-- | An arrow which parses the doctype "SYSTEM" of an 'XmlTree'.
-- We use these to determine the parser to use.
-- The result of runX has type IO [IO ImportResult]. We thus use
-- bind (>>=) and sequence to combine all of the IOs into one
-- big one outside of the list.
+ --
+ -- Before we actually run the import, we check it against a list
+ -- of problem DTDs. These can produce weird errors, and we have
+ -- checks for them. But with DTD validation enabled, we can't
+ -- even look inside the document to see what's wrong -- parsing
+ -- will fail! So for those special document types, we proceed
+ -- using 'parse_opts_novalidate' instead of the default
+ -- 'parse_opts'.
+ --
parse_and_import :: IO [ImportResult]
- parse_and_import =
- runX (readA >>> (dtdnameA &&& returnA) >>> (arr import_with_dtd))
- >>=
- sequence
+ parse_and_import = do
+ -- Get the DTD name without validating against it.
+ ((DtdName dtd) : _) <- runX $ (readA parse_opts_novalidate) >>> dtdnameA
+
+ let problem_dtds = [ News.dtd, Weather.dtd ]
+ let opts = if dtd `elem` problem_dtds
+ then parse_opts_novalidate
+ else parse_opts
+
+ runX ((readA opts) >>> (dtdnameA &&& returnA) >>> (arr import_with_dtd))
+ >>= sequence
-- | Takes a ('DtdName', 'XmlTree') pair and uses the 'DtdName'
-- to determine which function to call on the 'XmlTree'.
| otherwise = do
let infomsg =
"Unrecognized DTD in " ++ path ++ ": " ++ dtd ++ "."
+ -- This should be an impossible case while DTD
+ -- validation is enabled. If we can parse the file at
+ -- all, then we have a DTD for it sitting around. And we
+ -- only have DTDs for supported types.
return $ ImportUnsupported infomsg