wraxml-0.5: src/Text/XML/WraXML/String.hs
module Text.XML.WraXML.String where
import qualified Text.XML.Basic.Character as XmlChar
import Text.XML.WraXML.Utility (compose)
import qualified Data.String.Unicode as Unicode
import qualified Data.Char as Char
import Data.Tuple.HT (mapFst)
import qualified Numeric
import qualified Control.Monad.Exception.Synchronous as Exc
import Control.Monad.Trans.State (State, evalState)
import Control.Applicative (Applicative, liftA)
type T = [Atom]
type EmbeddedExceptions = [Exc.Exceptional String Char]
type Atom = XmlChar.T
-- | should be an abstract type
type Encoding = String
-- | should be [Word8]
type Encoded = String
{- |
Literal translation from pure strings.
This can only work, if the string does not contain special characters.
-}
fromString :: String -> T
fromString = map XmlChar.fromUnicode
diffFromString :: String -> T -> T
diffFromString =
flip (foldr (\c -> (XmlChar.fromUnicode c :)))
{- |
default routine
-}
fromUnicodeString :: String -> T
fromUnicodeString = map XmlChar.asciiFromUnicode
toUnicodeStringOrFormat :: T -> String
toUnicodeStringOrFormat =
flip compose "" .
map XmlChar.toUnicodeOrFormat
toUnicodeStringEmbedMessage :: T -> String
toUnicodeStringEmbedMessage =
flip compose "" .
map
(Exc.switch (\err ->
showString "(decoding error: " . showString err . showString ")")
(:)) .
toUnicodeStringEmbedException
{- |
Errors in on resolution of references yield undefined elements.
-}
toUnicodeString :: T -> String
toUnicodeString =
map (Exc.resolve error) . toUnicodeStringEmbedException
toUnicodeStringEmbedException :: T -> EmbeddedExceptions
toUnicodeStringEmbedException =
map XmlChar.toUnicode
{-# DEPRECATED utf8ToUnicodeString, isoLatin1ToUnicodeString, replaceUTF8ByUnicode, uStringWithErrorsMergePlainChars "XmlChar.Unicode constructors must contain unicode characters and not encoded ones. Decode characters before parsing!" #-}
{- |
Interpret the XML string as mixture of ISO-Latin-1 characters and XML entities
and convert that to a Unicode string.
-}
isoLatin1ToUnicodeString :: T -> String
isoLatin1ToUnicodeString = toUnicodeString
{- |
Interpret the XML string as mixture of UTF-8 characters and XML entities
and convert that to a Unicode string.
-}
utf8ToUnicodeString :: T -> String
utf8ToUnicodeString = toUnicodeString . replaceUTF8ByUnicode
readHex :: (Eq a, Num a) => String -> a
readHex str =
case Numeric.readHex str of
[(n,"")] -> n
_ -> error "readHex: no parse"
{- |
Caution: There is a memory leak for the case that entity references are huge.
-}
parse :: String -> T
parse ('&':'#':'x':xs) =
parseAux Char.isHexDigit (XmlChar.fromCharRef . readHex) "&#x" xs
parse ('&':'#':xs) =
parseAux Char.isDigit (XmlChar.fromCharRef . read) "&#" xs
parse ('&':xs) =
parseAux Char.isAlphaNum XmlChar.fromEntityRef "&" xs
parse (x:xs) = XmlChar.fromUnicode x : parse xs
parse [] = []
-- use unfoldr?
parseAux ::
(Char -> Bool) ->
(String -> XmlChar.T) ->
String ->
String ->
T
parseAux check ref prefix xs =
let (name,rest0) = span check xs
in case rest0 of
';':rest1 -> ref name : parse rest1
_ -> map XmlChar.fromUnicode (prefix++name) ++ parse rest0
reduceRefs :: T -> T
reduceRefs = map XmlChar.reduceRef
{- |
Consider the XmlString as a mixture of XML entities and UTF-8 characters.
Replace UTF-8 characters by Unicode representations.
-}
replaceUTF8ByUnicode :: T -> T
replaceUTF8ByUnicode =
mapUnicodeRuns (fst . Unicode.utf8ToUnicode)
mapUnicodeRuns :: (String -> String) -> T -> T
mapUnicodeRuns f =
flip compose [] .
XmlChar.switchUnicodeRuns
-- (\s -> fromString (f s) ++)
(diffFromString . f)
((:) . XmlChar.fromCharRef)
((:) . XmlChar.fromEntityRef)
uStringWithErrorsMergePlainChars ::
EmbeddedExceptions -> [Exc.Exceptional String String]
uStringWithErrorsMergePlainChars =
foldr (\x ys ->
case x of
Exc.Exception err -> Exc.Exception err : ys
Exc.Success c ->
uncurry (:) $
mapFst Exc.Success $
mapFst (c:) $
case ys of
Exc.Success cs : ys0 -> (cs, ys0)
_ -> ([], ys))
[]
evalDecodeAdaptive ::
State (Encoded -> String) a -> a
evalDecodeAdaptive =
flip evalState id
liftFromUnicode :: (String -> String) -> (T -> T)
liftFromUnicode f =
fromUnicodeString . f . toUnicodeString
liftFromUnicodeA :: Applicative m => (String -> m String) -> (T -> m T)
liftFromUnicodeA f =
liftA fromUnicodeString . f . toUnicodeString