module Text.XML.Expat.Annotated (
Node(..),
Attributes,
UNode,
UAttributes,
LNode,
ULNode,
textContent,
isElement,
isNamed,
isText,
getName,
getAttributes,
getAttribute,
getChildren,
modifyName,
modifyAttributes,
setAttribute,
deleteAttribute,
alterAttribute,
modifyChildren,
mapAllTags,
unannotate,
modifyAnnotation,
mapAnnotation,
QName(..),
QNode,
QAttributes,
QLNode,
toQualified,
fromQualified,
NName (..),
NNode,
NAttributes,
NLNode,
mkNName,
mkAnNName,
toNamespaced,
fromNamespaced,
xmlnsUri,
xmlns,
Tree.ParserOptions(..),
Tree.defaultParserOptions,
Encoding(..),
parse,
parse',
XMLParseError(..),
XMLParseLocation(..),
parseThrowing,
XMLParseException(..),
SAXEvent(..),
saxToTree,
GenericXMLString(..),
eAttrs,
parseSAX,
parseSAXThrowing,
parseSAXLocations,
parseSAXLocationsThrowing,
parseTree,
parseTree',
parseTreeThrowing
) where
import Control.Arrow
import Text.XML.Expat.Tree ( Attributes, UAttributes )
import qualified Text.XML.Expat.Tree as Tree
import Text.XML.Expat.SAX ( Encoding(..)
, GenericXMLString(..)
, ParserOptions(..)
, SAXEvent(..)
, XMLParseError(..)
, XMLParseException(..)
, XMLParseLocation(..)
, parseSAX
, parseSAXThrowing
, parseSAXLocations
, parseSAXLocationsThrowing )
import qualified Text.XML.Expat.SAX as SAX
import Text.XML.Expat.Qualified hiding (QNode, QNodes)
import Text.XML.Expat.Namespaced hiding (NNode, NNodes)
import Text.XML.Expat.NodeClass
import Control.Monad (mplus)
import Control.Parallel.Strategies
import qualified Data.ByteString as B
import qualified Data.ByteString.Lazy as L
import Data.Monoid
data Node a tag text =
Element {
eName :: !tag,
eAttributes :: ![(tag,text)],
eChildren :: [Node a tag text],
eAnn :: a
} |
Text !text
deriving (Eq, Show)
eAttrs :: Node a tag text -> [(tag, text)]
eAttrs = eAttributes
instance (NFData tag, NFData text, NFData a) => NFData (Node a tag text) where
rnf (Element nam att chi ann) = rnf (nam, att, chi, ann)
rnf (Text txt) = rnf txt
instance NodeClass (Node a) where
textContent (Element _ _ children _) = mconcat $ map textContent children
textContent (Text txt) = txt
isElement (Element _ _ _ _) = True
isElement _ = False
isText (Text _) = True
isText _ = False
isNamed _ (Text _) = False
isNamed nm (Element nm' _ _ _) = nm == nm'
getName (Text _) = gxFromString ""
getName (Element name _ _ _) = name
getAttributes (Text _) = []
getAttributes (Element _ attrs _ _) = attrs
getChildren (Text _) = []
getChildren (Element _ _ ch _) = ch
modifyName _ node@(Text _) = node
modifyName f (Element n a c ann) = Element (f n) a c ann
modifyAttributes _ node@(Text _) = node
modifyAttributes f (Element n a c ann) = Element n (f a) c ann
modifyChildren _ node@(Text _) = node
modifyChildren f (Element n a c ann) = Element n a (f c) ann
mapAllTags _ (Text t) = Text t
mapAllTags f (Element n a c ann) = Element (f n) (map (first f) a) (map (mapAllTags f) c) ann
mapElement _ (Text t) = Text t
mapElement f (Element n a c ann) =
let (n', a', c') = f (n, a, c)
in Element n' a' c' ann
unannotate :: Node a tag text -> Tree.Node tag text
unannotate (Element na at ch _) = (Tree.Element na at (map unannotate ch))
unannotate (Text t) = Tree.Text t
type UNode a text = Node a text text
type LNode tag text = Node XMLParseLocation tag text
type ULNode text = LNode text text
type QNode a text = Node a (QName text) text
type QLNode text = LNode (QName text) text
type NNode text a = Node a (NName text) text
type NLNode text = LNode (NName text) text
modifyAnnotation :: (a -> a) -> Node a tag text -> Node a tag text
f `modifyAnnotation` Element na at ch an = Element na at ch (f an)
_ `modifyAnnotation` Text t = Text t
mapAnnotation :: (a -> b) -> Node a tag text -> Node b tag text
f `mapAnnotation` Element na at ch an = Element na at (map (f `mapAnnotation`) ch) (f an)
_ `mapAnnotation` Text t = Text t
saxToTree :: GenericXMLString tag =>
[(SAXEvent tag text, a)]
-> (Node a tag text, Maybe XMLParseError)
saxToTree events =
let (nodes, mError, _) = ptl events
in (safeHead nodes, mError)
where
safeHead (a:_) = a
safeHead [] = Element (gxFromString "") [] [] (error "saxToTree null annotation")
ptl ((StartElement name attrs, ann):rema) =
let (children, err1, rema') = ptl rema
elt = Element name attrs children ann
(out, err2, rema'') = ptl rema'
in (elt:out, err1 `mplus` err2, rema'')
ptl ((EndElement _, _):rema) = ([], Nothing, rema)
ptl ((CharacterData txt, _):rema) =
let (out, err, rema') = ptl rema
in (Text txt:out, err, rema')
ptl ((FailDocument err, _):_) = ([], Just err, [])
ptl [] = ([], Nothing, [])
parse :: (GenericXMLString tag, GenericXMLString text) =>
ParserOptions tag text
-> L.ByteString
-> (LNode tag text, Maybe XMLParseError)
parse opts bs = saxToTree $ SAX.parseLocations opts bs
parseTree :: (GenericXMLString tag, GenericXMLString text) =>
Maybe Encoding
-> L.ByteString
-> (LNode tag text, Maybe XMLParseError)
parseTree mEnc = parse (ParserOptions mEnc Nothing)
parseThrowing :: (GenericXMLString tag, GenericXMLString text) =>
ParserOptions tag text
-> L.ByteString
-> LNode tag text
parseThrowing opts bs = fst $ saxToTree $ SAX.parseLocationsThrowing opts bs
parseTreeThrowing :: (GenericXMLString tag, GenericXMLString text) =>
Maybe Encoding
-> L.ByteString
-> LNode tag text
parseTreeThrowing mEnc = parseThrowing (ParserOptions mEnc Nothing)
parse' :: (GenericXMLString tag, GenericXMLString text) =>
ParserOptions tag text
-> B.ByteString
-> Either XMLParseError (LNode tag text)
parse' opts bs = case parse opts (L.fromChunks [bs]) of
(_, Just err) -> Left err
(root, Nothing) -> Right root
parseTree' :: (GenericXMLString tag, GenericXMLString text) =>
Maybe Encoding
-> B.ByteString
-> Either XMLParseError (LNode tag text)
parseTree' mEnc = parse' (ParserOptions mEnc Nothing)