module Text.XML.HXT.Arrow.XmlState.URIHandling
where
import Control.Arrow
import Control.Arrow.ArrowList
import Control.Arrow.ArrowIf
import Control.Arrow.ArrowIO
import Control.Monad ( mzero
, mplus )
import Text.XML.HXT.Arrow.XmlArrow
import Text.XML.HXT.Arrow.XmlState.TypeDefs
import Text.XML.HXT.Arrow.XmlState.TraceHandling
import Data.Maybe
import Network.URI ( URI
, escapeURIChar
, isUnescapedInURI
, nonStrictRelativeTo
, parseURIReference
, uriAuthority
, uriFragment
, uriPath
, uriPort
, uriQuery
, uriRegName
, uriScheme
, uriUserInfo
)
import System.Directory ( getCurrentDirectory )
setBaseURI :: IOStateArrow s String String
setBaseURI = setSysVar theBaseURI
>>>
traceValue 2 (("setBaseURI: new base URI is " ++) . show)
getBaseURI :: IOStateArrow s b String
getBaseURI = getSysVar theBaseURI
>>>
( ( getDefaultBaseURI
>>>
setBaseURI
>>>
getBaseURI
)
`when`
isA null
)
changeBaseURI :: IOStateArrow s String String
changeBaseURI = mkAbsURI >>> setBaseURI
setDefaultBaseURI :: String -> IOStateArrow s b String
setDefaultBaseURI base = ( if null base
then arrIO getDir
else constA base
)
>>>
setSysVar theDefaultBaseURI
>>>
traceValue 2 (("setDefaultBaseURI: new default base URI is " ++) . show)
where
getDir _ = do
cwd <- getCurrentDirectory
return ("file://" ++ normalize cwd ++ "/")
normalize wd'@(d : ':' : _)
| d `elem` ['A'..'Z']
||
d `elem` ['a'..'z']
= '/' : concatMap win32ToUriChar wd'
normalize wd' = concatMap escapeNonUriChar wd'
win32ToUriChar '\\' = "/"
win32ToUriChar c = escapeNonUriChar c
escapeNonUriChar c = escapeURIChar isUnescapedInURI c
getDefaultBaseURI :: IOStateArrow s b String
getDefaultBaseURI = getSysVar theDefaultBaseURI
>>>
( ( setDefaultBaseURI ""
>>>
getDefaultBaseURI
)
`when` isA null
)
runInLocalURIContext :: IOStateArrow s b c -> IOStateArrow s b c
runInLocalURIContext f = localSysVar theBaseURI f
parseURIReference' :: String -> Maybe URI
parseURIReference' uri
= parseURIReference uri
`mplus`
( if unesc
then parseURIReference uri'
else mzero
)
where
unesc = not . all isUnescapedInURI $ uri
escape '\\' = "/"
escape c = escapeURIChar isUnescapedInURI c
uri' = concatMap escape uri
expandURIString :: String -> String -> Maybe String
expandURIString uri base
= do
base' <- parseURIReference' base
uri' <- parseURIReference' uri
let abs' = nonStrictRelativeTo uri' base'
return $ show abs'
expandURI :: ArrowXml a => a (String, String) String
expandURI
= arrL (maybeToList . uncurry expandURIString)
mkAbsURI :: IOStateArrow s String String
mkAbsURI
= ( this &&& getBaseURI ) >>> expandURI
getSchemeFromURI :: ArrowList a => a String String
getSchemeFromURI = getPartFromURI scheme
where
scheme = init . uriScheme
getRegNameFromURI :: ArrowList a => a String String
getRegNameFromURI = getPartFromURI host
where
host = maybe "" uriRegName . uriAuthority
getPortFromURI :: ArrowList a => a String String
getPortFromURI = getPartFromURI port
where
port = dropWhile (==':') . maybe "" uriPort . uriAuthority
getUserInfoFromURI :: ArrowList a => a String String
getUserInfoFromURI = getPartFromURI ui
where
ui = reverse . dropWhile (=='@') . reverse . maybe "" uriUserInfo . uriAuthority
getPathFromURI :: ArrowList a => a String String
getPathFromURI = getPartFromURI uriPath
getQueryFromURI :: ArrowList a => a String String
getQueryFromURI = getPartFromURI uriQuery
getFragmentFromURI :: ArrowList a => a String String
getFragmentFromURI = getPartFromURI uriFragment
getPartFromURI :: ArrowList a => (URI -> String) -> a String String
getPartFromURI sel
= arrL (maybeToList . getPart)
where
getPart s = do
uri <- parseURIReference' s
return (sel uri)