git.iko.soy/typeable/pandoc
on master help sign in
Added code for xml library (Text.XML.Light) to source tree,

since there is currently no debian package. Removed dependency on xml library. Added license to debian/copyright. git-svn-id: https://pandoc.googlecode.com/svn/trunk@1351 788f1e2b-df1e-0410-8736-df70ead52e1b

commit0c6dd105b73e95d61d3a3d3213d8f80f3d8a22d4 authorfiddlosopher <fiddlosopher@788f1e2b-df1e-0410-8736-df70ead52e1b> dateFri 1 Aug 2008, 00:45 (18 years ago) parent8440385
8 files changed+1116−4
Text/XML/Light.hs+96 Text/XML/Light/Cursor.hs+327 Text/XML/Light/Input.hs+307 Text/XML/Light/Output.hs+150 Text/XML/Light/Proc.hs+103 Text/XML/Light/Types.hs+91 debian/copyright+33 pandoc.cabal+9−4
Text/XML/Light.hsnew file+96
@@ -0,0 +1,96 @@
1+{-# LANGUAGE FlexibleInstances #-}
2+--------------------------------------------------------------------
3+-- |
4+-- Module : Text.XML.Light
5+-- Copyright : (c) Galois, Inc. 2007
6+-- License : BSD3
7+--
8+-- Maintainer: Iavor S. Diatchki <diatchki@galois.com>
9+-- Stability : provisional
10+-- Portability: portability
11+--
12+-- A lightweight XML parsing, filtering and generating library.
13+--
14+-- This module reexports functions from:
15+--
16+-- * "Text.XML.Light.Types"
17+--
18+-- * "Text.XML.Light.Proc"
19+--
20+-- * "Text.XML.Light.Input"
21+--
22+-- * "Text.XML.Light.Output"
23+--
24+
25+module Text.XML.Light (
26+
27+ module Text.XML.Light,
28+ module Text.XML.Light.Types,
29+ module Text.XML.Light.Proc,
30+ module Text.XML.Light.Input,
31+ module Text.XML.Light.Output
32+
33+ ) where
34+
35+import Text.XML.Light.Types
36+import Text.XML.Light.Proc
37+import Text.XML.Light.Input
38+import Text.XML.Light.Output
39+
40+-- | Add an attribute to an element.
41+add_attr :: Attr -> Element -> Element
42+add_attr a e = add_attrs [a] e
43+
44+-- | Add some attributes to an element.
45+add_attrs :: [Attr] -> Element -> Element
46+add_attrs as e = e { elAttribs = as ++ elAttribs e }
47+
48+-- | Create an unqualified name.
49+unqual :: String -> QName
50+unqual x = blank_name { qName = x }
51+
52+-- | A smart element constructor which uses the type of its argument
53+-- to determine what sort of element to make.
54+class Node t where
55+ node :: QName -> t -> Element
56+
57+instance Node ([Attr],[Content]) where
58+ node n (attrs,cont) = blank_element { elName = n
59+ , elAttribs = attrs
60+ , elContent = cont
61+ }
62+
63+instance Node [Attr] where node n as = node n (as,[]::[Content])
64+instance Node Attr where node n a = node n [a]
65+instance Node () where node n () = node n ([]::[Attr])
66+
67+instance Node [Content] where node n cs = node n ([]::[Attr],cs)
68+instance Node Content where node n c = node n [c]
69+instance Node ([Attr],Content) where node n (as,c) = node n (as,[c])
70+instance Node (Attr,Content) where node n (a,c) = node n ([a],[c])
71+
72+instance Node ([Attr],[Element]) where
73+ node n (as,cs) = node n (as,map Elem cs)
74+
75+instance Node ([Attr],Element) where node n (as,c) = node n (as,[c])
76+instance Node (Attr,Element) where node n (a,c) = node n ([a],c)
77+instance Node ([Element]) where node n es = node n ([]::[Attr],es)
78+instance Node (Element) where node n e = node n [e]
79+
80+instance Node ([Attr],[CData]) where
81+ node n (as,cs) = node n (as,map Text cs)
82+
83+instance Node ([Attr],CData) where node n (as,c) = node n (as,[c])
84+instance Node (Attr,CData) where node n (a,c) = node n ([a],c)
85+instance Node [CData] where node n es = node n ([]::[Attr],es)
86+instance Node CData where node n e = node n [e]
87+
88+instance Node ([Attr],String) where
89+ node n (as,t) = node n (as,blank_cdata { cdData = t })
90+
91+instance Node (Attr,String) where node n (a,t) = node n ([a],t)
92+instance Node [Char] where node n t = node n ([]::[Attr],t)
93+
94+-- | Create node with unqualified name
95+unode :: Node t => String -> t -> Element
96+unode = node . unqual
Text/XML/Light/Cursor.hsnew file+327
@@ -0,0 +1,327 @@
1+--------------------------------------------------------------------
2+-- |
3+-- Module : Text.XML.Light.Cursor
4+-- Copyright : (c) Galois, Inc. 2008
5+-- License : BSD3
6+--
7+-- Maintainer: Iavor S. Diatchki <diatchki@galois.com>
8+-- Stability : provisional
9+-- Portability:
10+--
11+-- XML cursors for working XML content withing the context of
12+-- an XML document. This implemntation is based on the general
13+-- tree zipper written by Krasimir Angelov and Iavor S. Diatchki.
14+--
15+
16+module Text.XML.Light.Cursor
17+ ( Tag(..), getTag, setTag, fromTag
18+ , Cursor(..), Path
19+
20+ -- * Conversions
21+ , fromContent
22+ , fromElement
23+ , fromForest
24+ , toForest
25+ , toTree
26+
27+ -- * Moving around
28+ , parent
29+ , root
30+ , getChild
31+ , firstChild
32+ , lastChild
33+ , left
34+ , right
35+
36+ -- ** Searching
37+ , findChild
38+ , findLeft
39+ , findRight
40+
41+ -- * Node classification
42+ , isRoot
43+ , isFirst
44+ , isLast
45+ , isLeaf
46+ , isChild
47+ , hasChildren
48+ , getNodeIndex
49+
50+ -- * Updates
51+ , setContent
52+ , modifyContent
53+ , modifyContentM
54+
55+ -- ** Inserting content
56+ , insertLeft
57+ , insertRight
58+ , insertGoLeft
59+ , insertGoRight
60+
61+ -- ** Removing content
62+ , removeLeft
63+ , removeRight
64+ , removeGoLeft
65+ , removeGoRight
66+ , removeGoUp
67+
68+ ) where
69+
70+import Text.XML.Light.Types
71+import Data.Maybe(isNothing)
72+
73+data Tag = Tag { tagName :: QName
74+ , tagAttribs :: [Attr]
75+ , tagLine :: Maybe Line
76+ } deriving (Show)
77+
78+getTag :: Element -> Tag
79+getTag e = Tag { tagName = elName e
80+ , tagAttribs = elAttribs e
81+ , tagLine = elLine e
82+ }
83+
84+setTag :: Tag -> Element -> Element
85+setTag t e = fromTag t (elContent e)
86+
87+fromTag :: Tag -> [Content] -> Element
88+fromTag t cs = Element { elName = tagName t
89+ , elAttribs = tagAttribs t
90+ , elLine = tagLine t
91+ , elContent = cs
92+ }
93+
94+type Path = [([Content],Tag,[Content])]
95+
96+-- | The position of a piece of content in an XML document.
97+data Cursor = Cur
98+ { current :: Content -- ^ The currently selected content.
99+ , lefts :: [Content] -- ^ Siblings on the left, closest first.
100+ , rights :: [Content] -- ^ Siblings on the right, closest first.
101+ , parents :: Path -- ^ The contexts of the parent elements of this location.
102+ } deriving (Show)
103+
104+-- Moving around ---------------------------------------------------------------
105+
106+-- | The parent of the given location.
107+parent :: Cursor -> Maybe Cursor
108+parent loc =
109+ case parents loc of
110+ (pls,v,prs) : ps -> Just
111+ Cur { current = Elem
112+ (fromTag v
113+ (combChildren (lefts loc) (current loc) (rights loc)))
114+ , lefts = pls, rights = prs, parents = ps
115+ }
116+ [] -> Nothing
117+
118+
119+-- | The top-most parent of the given location.
120+root :: Cursor -> Cursor
121+root loc = maybe loc root (parent loc)
122+
123+-- | The left sibling of the given location.
124+left :: Cursor -> Maybe Cursor
125+left loc =
126+ case lefts loc of
127+ t : ts -> Just loc { current = t, lefts = ts
128+ , rights = current loc : rights loc }
129+ [] -> Nothing
130+
131+-- | The right sibling of the given location.
132+right :: Cursor -> Maybe Cursor
133+right loc =
134+ case rights loc of
135+ t : ts -> Just loc { current = t, lefts = current loc : lefts loc
136+ , rights = ts }
137+ [] -> Nothing
138+
139+-- | The first child of the given location.
140+firstChild :: Cursor -> Maybe Cursor
141+firstChild loc =
142+ do (t : ts, ps) <- downParents loc
143+ return Cur { current = t, lefts = [], rights = ts , parents = ps }
144+
145+-- | The last child of the given location.
146+lastChild :: Cursor -> Maybe Cursor
147+lastChild loc =
148+ do (ts, ps) <- downParents loc
149+ case reverse ts of
150+ l : ls -> return Cur { current = l, lefts = ls, rights = []
151+ , parents = ps }
152+ [] -> Nothing
153+
154+-- | Find the next left sibling that satisfies a predicate.
155+findLeft :: (Cursor -> Bool) -> Cursor -> Maybe Cursor
156+findLeft p loc = do loc1 <- left loc
157+ if p loc1 then return loc1 else findLeft p loc1
158+
159+-- | Find the next right sibling that satisfies a predicate.
160+findRight :: (Cursor -> Bool) -> Cursor -> Maybe Cursor
161+findRight p loc = do loc1 <- right loc
162+ if p loc1 then return loc1 else findRight p loc1
163+
164+-- | The first child that satisfies a predicate.
165+findChild :: (Cursor -> Bool) -> Cursor -> Maybe Cursor
166+findChild p loc =
167+ do loc1 <- firstChild loc
168+ if p loc1 then return loc1 else findRight p loc1
169+
170+-- | The child with the given index (starting from 0).
171+getChild :: Int -> Cursor -> Maybe Cursor
172+getChild n loc =
173+ do (ts,ps) <- downParents loc
174+ (ls,t,rs) <- splitChildren ts n
175+ return Cur { current = t, lefts = ls, rights = rs, parents = ps }
176+
177+
178+-- | private: computes the parent for "down" operations.
179+downParents :: Cursor -> Maybe ([Content], Path)
180+downParents loc =
181+ case current loc of
182+ Elem e -> Just ( elContent e
183+ , (lefts loc, getTag e, rights loc) : parents loc
184+ )
185+ _ -> Nothing
186+
187+-- Conversions -----------------------------------------------------------------
188+
189+-- | A cursor for the guven content.
190+fromContent :: Content -> Cursor
191+fromContent t = Cur { current = t, lefts = [], rights = [], parents = [] }
192+
193+-- | A cursor for the guven element.
194+fromElement :: Element -> Cursor
195+fromElement e = fromContent (Elem e)
196+
197+-- | The location of the first tree in a forest.
198+fromForest :: [Content] -> Maybe Cursor
199+fromForest (t:ts) = Just Cur { current = t, lefts = [], rights = ts
200+ , parents = [] }
201+fromForest [] = Nothing
202+
203+-- | Computes the tree containing this location.
204+toTree :: Cursor -> Content
205+toTree loc = current (root loc)
206+
207+-- | Computes the forest containing this location.
208+toForest :: Cursor -> [Content]
209+toForest loc = let r = root loc in combChildren (lefts r) (current r) (rights r)
210+
211+
212+-- Queries ---------------------------------------------------------------------
213+
214+-- | Are we at the top of the document?
215+isRoot :: Cursor -> Bool
216+isRoot loc = null (parents loc)
217+
218+-- | Are we at the left end of the the document?
219+isFirst :: Cursor -> Bool
220+isFirst loc = null (lefts loc)
221+
222+-- | Are we at the right end of the document?
223+isLast :: Cursor -> Bool
224+isLast loc = null (rights loc)
225+
226+-- | Are we at the bottom of the document?
227+isLeaf :: Cursor -> Bool
228+isLeaf loc = isNothing (downParents loc)
229+
230+-- | Do we have a parent?
231+isChild :: Cursor -> Bool
232+isChild loc = not (isRoot loc)
233+
234+-- | Get the node index inside the sequence of children
235+getNodeIndex :: Cursor -> Int
236+getNodeIndex loc = length (lefts loc)
237+
238+-- | Do we have children?
239+hasChildren :: Cursor -> Bool
240+hasChildren loc = not (isLeaf loc)
241+
242+
243+
244+-- Updates ---------------------------------------------------------------------
245+
246+-- | Change the current content.
247+setContent :: Content -> Cursor -> Cursor
248+setContent t loc = loc { current = t }
249+
250+-- | Modify the current content.
251+modifyContent :: (Content -> Content) -> Cursor -> Cursor
252+modifyContent f loc = setContent (f (current loc)) loc
253+
254+-- | Modify the current content, allowing for an effect.
255+modifyContentM :: Monad m => (Content -> m Content) -> Cursor -> m Cursor
256+modifyContentM f loc = do x <- f (current loc)
257+ return (setContent x loc)
258+
259+-- | Insert content to the left of the current position.
260+insertLeft :: Content -> Cursor -> Cursor
261+insertLeft t loc = loc { lefts = t : lefts loc }
262+
263+-- | Insert content to the right of the current position.
264+insertRight :: Content -> Cursor -> Cursor
265+insertRight t loc = loc { rights = t : rights loc }
266+
267+-- | Remove the conent on the left of the current position, if any.
268+removeLeft :: Cursor -> Maybe (Content,Cursor)
269+removeLeft loc = case lefts loc of
270+ l : ls -> return (l,loc { lefts = ls })
271+ [] -> Nothing
272+
273+-- | Remove the conent on the right of the current position, if any.
274+removeRight :: Cursor -> Maybe (Content,Cursor)
275+removeRight loc = case rights loc of
276+ l : ls -> return (l,loc { rights = ls })
277+ [] -> Nothing
278+
279+
280+-- | Insert content to the left of the current position.
281+-- The new content becomes the current position.
282+insertGoLeft :: Content -> Cursor -> Cursor
283+insertGoLeft t loc = loc { current = t, rights = current loc : rights loc }
284+
285+-- | Insert content to the right of the current position.
286+-- The new content becomes the current position.
287+insertGoRight :: Content -> Cursor -> Cursor
288+insertGoRight t loc = loc { current = t, lefts = current loc : lefts loc }
289+
290+-- | Remove the current element.
291+-- The new position is the one on the left.
292+removeGoLeft :: Cursor -> Maybe Cursor
293+removeGoLeft loc = case lefts loc of
294+ l : ls -> Just loc { current = l, lefts = ls }
295+ [] -> Nothing
296+
297+-- | Remove the current element.
298+-- The new position is the one on the right.
299+removeGoRight :: Cursor -> Maybe Cursor
300+removeGoRight loc = case rights loc of
301+ l : ls -> Just loc { current = l, rights = ls }
302+ [] -> Nothing
303+
304+-- | Remove the current element.
305+-- The new position is the parent of the old position.
306+removeGoUp :: Cursor -> Maybe Cursor
307+removeGoUp loc =
308+ case parents loc of
309+ (pls,v,prs) : ps -> Just
310+ Cur { current = Elem (fromTag v (reverse (lefts loc) ++ rights loc))
311+ , lefts = pls, rights = prs, parents = ps
312+ }
313+ [] -> Nothing
314+
315+
316+-- | private: Gets the given element of a list.
317+-- Also returns the preceeding elements (reversed) and the folloing elements.
318+splitChildren :: [a] -> Int -> Maybe ([a],a,[a])
319+splitChildren _ n | n < 0 = Nothing
320+splitChildren cs pos = loop [] cs pos
321+ where loop acc (x:xs) 0 = Just (acc,x,xs)
322+ loop acc (x:xs) n = loop (x:acc) xs $! n-1
323+ loop _ _ _ = Nothing
324+
325+-- | private: combChildren ls x ys = reverse ls ++ [x] ++ ys
326+combChildren :: [a] -> a -> [a] -> [a]
327+combChildren ls t rs = foldl (flip (:)) (t:rs) ls
Text/XML/Light/Input.hsnew file+307
@@ -0,0 +1,307 @@
1+--------------------------------------------------------------------
2+-- |
3+-- Module : Text.XML.Light.Input
4+-- Copyright : (c) Galois, Inc. 2007
5+-- License : BSD3
6+--
7+-- Maintainer: Iavor S. Diatchki <diatchki@galois.com>
8+-- Stability : provisional
9+-- Portability: portable
10+--
11+-- Lightweight XML parsing
12+--
13+
14+module Text.XML.Light.Input (parseXML,parseXMLDoc) where
15+
16+import Text.XML.Light.Types
17+import Text.XML.Light.Proc
18+import Text.XML.Light.Output(tagEnd)
19+
20+import Data.Char(isSpace)
21+import Data.List(isPrefixOf)
22+import Numeric(readHex)
23+
24+-- | parseXMLDoc, parse a XMLl document to maybe an element
25+parseXMLDoc :: String -> Maybe Element
26+parseXMLDoc xs = strip (parseXML xs)
27+ where strip cs = case onlyElems cs of
28+ e : es
29+ | "?xml" `isPrefixOf` qName (elName e)
30+ -> strip (map Elem es)
31+ | otherwise -> Just e
32+ _ -> Nothing
33+
34+-- | parseXML to a list of content chunks
35+parseXML :: String -> [Content]
36+parseXML xs = parse $ tokens $ preprocess xs
37+
38+------------------------------------------------------------------------
39+
40+parse :: [Token] -> [Content]
41+parse [] = []
42+parse ts = let (es,_,ts1) = nodes ([],Nothing) [] ts
43+ in es ++ parse ts1
44+
45+-- Information about namespaces.
46+-- The first component is a map that associates prefixes to URIs,
47+-- the second is the URI for the default namespace, if one was provided.
48+type NSInfo = ([(String,String)],Maybe String)
49+
50+nodes :: NSInfo -> [QName] -> [Token] -> ([Content], [QName], [Token])
51+
52+nodes ns ps (TokCRef ref : ts) =
53+ let (es,qs,ts1) = nodes ns ps ts
54+ in (CRef ref : es, qs, ts1)
55+
56+nodes ns ps (TokText txt : ts) =
57+ let (es,qs,ts1) = nodes ns ps ts
58+ (more,es1) = case es of
59+ Text cd : es1'
60+ | cdVerbatim cd == cdVerbatim txt -> (cdData cd,es1')
61+ _ -> ([],es)
62+
63+ in (Text txt { cdData = cdData txt ++ more } : es1, qs, ts1)
64+
65+nodes cur_info ps (TokStart p t as empty : ts) = (node : siblings, open, toks)
66+ where
67+ new_name = annotName new_info t
68+ new_info = foldr addNS cur_info as
69+ node = Elem Element { elLine = Just p
70+ , elName = new_name
71+ , elAttribs = map (annotAttr new_info) as
72+ , elContent = children
73+ }
74+
75+ (children,(siblings,open,toks))
76+ | empty = ([], nodes cur_info ps ts)
77+ | otherwise = let (es1,qs1,ts1) = nodes new_info (new_name:ps) ts
78+ in (es1,
79+ case qs1 of
80+ [] -> nodes cur_info ps ts1
81+ _ : qs3 -> ([],qs3,ts1))
82+
83+nodes ns ps (TokEnd p t : ts) = let t1 = annotName ns t
84+ in case break (t1 ==) ps of
85+ (as,_:_) -> ([],as,ts)
86+ -- Unknown closing tag. Insert as text.
87+ (_,[]) ->
88+ let (es,qs,ts1) = nodes ns ps ts
89+ in (Text CData {
90+ cdLine = Just p,
91+ cdVerbatim = CDataText,
92+ cdData = tagEnd t ""
93+ } : es,qs, ts1)
94+
95+nodes _ ps [] = ([],ps,[])
96+
97+
98+annotName :: NSInfo -> QName -> QName
99+annotName (namespaces,def_ns) n =
100+ n { qURI = maybe def_ns (`lookup` namespaces) (qPrefix n) }
101+
102+annotAttr :: NSInfo -> Attr -> Attr
103+annotAttr ns a@(Attr { attrKey = k}) =
104+ case (qPrefix k, qName k) of
105+ (Nothing,"xmlns") -> a
106+ _ -> a { attrKey = annotName ns k }
107+
108+addNS :: Attr -> NSInfo -> NSInfo
109+addNS (Attr { attrKey = key, attrVal = val }) (ns,def) =
110+ case (qPrefix key, qName key) of
111+ (Nothing,"xmlns") -> (ns, if null val then Nothing else Just val)
112+ (Just "xmlns", k) -> ((k, val) : ns, def)
113+ _ -> (ns,def)
114+
115+
116+-- Lexer -----------------------------------------------------------------------
117+
118+type LChar = (Line,Char)
119+type LString = [LChar]
120+data Token = TokStart Line QName [Attr] Bool -- is empty?
121+ | TokEnd Line QName
122+ | TokCRef String
123+ | TokText CData
124+ deriving Show
125+
126+tokens :: String -> [Token]
127+tokens = tokens' . linenumber 1
128+
129+tokens' :: LString -> [Token]
130+tokens' ((_,'<') : c@(_,'!') : cs) = special c cs
131+
132+tokens' ((_,'<') : cs) = tag (dropSpace cs) -- we are being nice here
133+tokens' [] = []
134+tokens' cs@((l,_):_) = let (as,bs) = breakn ('<' ==) cs
135+ in map cvt (decode_text as) ++ tokens' bs
136+
137+ -- XXX: Note, some of the lines might be a bit inacuarate
138+ where cvt (TxtBit x) = TokText CData { cdLine = Just l
139+ , cdVerbatim = CDataText
140+ , cdData = x
141+ }
142+ cvt (CRefBit x) = case cref_to_char x of
143+ Just c -> TokText CData { cdLine = Just l
144+ , cdVerbatim = CDataText
145+ , cdData = [c]
146+ }
147+ Nothing -> TokCRef x
148+
149+
150+special :: LChar -> LString -> [Token]
151+special _ ((_,'-') : (_,'-') : cs) = skip cs
152+ where skip ((_,'-') : (_,'-') : (_,'>') : ds) = tokens' ds
153+ skip (_ : ds) = skip ds
154+ skip [] = [] -- unterminated comment
155+
156+special c ((_,'[') : (_,'C') : (_,'D') : (_,'A') : (_,'T') : (_,'A') : (_,'[')
157+ : cs) =
158+ let (xs,ts) = cdata cs
159+ in TokText CData { cdLine = Just (fst c), cdVerbatim = CDataVerbatim, cdData = xs }
160+ : tokens' ts
161+ where cdata ((_,']') : (_,']') : (_,'>') : ds) = ([],ds)
162+ cdata ((_,d) : ds) = let (xs,ys) = cdata ds in (d:xs,ys)
163+ cdata [] = ([],[])
164+
165+special c cs =
166+ let (xs,ts) = munch "" 0 cs
167+ in TokText CData { cdLine = Just (fst c), cdVerbatim = CDataRaw, cdData = '<':'!':(reverse xs) } : tokens' ts
168+ where munch acc nesting ((_,'>') : ds)
169+ | nesting == (0::Int) = ('>':acc,ds)
170+ | otherwise = munch ('>':acc) (nesting-1) ds
171+ munch acc nesting ((_,'<') : ds)
172+ = munch ('<':acc) (nesting+1) ds
173+ munch acc n ((_,x) : ds) = munch (x:acc) n ds
174+ munch acc _ [] = (acc,[]) -- unterminated DTD markup
175+
176+--special c cs = tag (c : cs) -- invalid specials are processed as tags
177+
178+
179+qualName :: LString -> (QName,LString)
180+qualName xs = let (as,bs) = breakn endName xs
181+ (q,n) = case break (':'==) as of
182+ (q1,_:n1) -> (Just q1, n1)
183+ _ -> (Nothing, as)
184+ in (QName { qURI = Nothing, qPrefix = q, qName = n }, bs)
185+ where endName x = isSpace x || x == '=' || x == '>' || x == '/'
186+
187+
188+
189+
190+
191+tag :: LString -> [Token]
192+tag ((p,'/') : cs) = let (n,ds) = qualName (dropSpace cs)
193+ in TokEnd p n : case ds of
194+ (_,'>') : es -> tokens' es
195+ -- tag was not properly closed...
196+ _ -> tokens' ds
197+tag [] = []
198+tag cs = let (n,ds) = qualName cs
199+ (as,b,ts) = attribs (dropSpace ds)
200+ in TokStart (fst (head cs)) n as b : ts
201+
202+attribs :: LString -> ([Attr], Bool, [Token])
203+attribs cs = case cs of
204+ (_,'>') : ds -> ([], False, tokens' ds)
205+
206+ (_,'/') : ds -> ([], True, case ds of
207+ (_,'>') : es -> tokens' es
208+ -- insert missing > ...
209+ _ -> tokens' ds)
210+
211+ (_,'?') : (_,'>') : ds -> ([], True, tokens' ds)
212+
213+ -- doc ended within a tag..
214+ [] -> ([],False,[])
215+
216+ _ -> let (a,cs1) = attrib cs
217+ (as,b,ts) = attribs cs1
218+ in (a:as,b,ts)
219+
220+attrib :: LString -> (Attr,LString)
221+attrib cs = let (ks,cs1) = qualName cs
222+ (vs,cs2) = attr_val (dropSpace cs1)
223+ in ((Attr ks (decode_attr vs)),dropSpace cs2)
224+
225+attr_val :: LString -> (String,LString)
226+attr_val ((_,'=') : cs) = string (dropSpace cs)
227+attr_val cs = ("",cs)
228+
229+
230+dropSpace :: LString -> LString
231+dropSpace = dropWhile (isSpace . snd)
232+
233+-- | Match the value for an attribute. For malformed XML we do
234+-- our best to guess the programmer's intention.
235+string :: LString -> (String,LString)
236+string ((_,'"') : cs) = break' ('"' ==) cs
237+
238+-- Allow attributes to be enclosed between ' '.
239+string ((_,'\'') : cs) = break' ('\'' ==) cs
240+
241+-- Allow attributes that are not enclosed by anything.
242+string cs = breakn eos cs
243+ where eos x = isSpace x || x == '>' || x == '/'
244+
245+
246+break' :: (a -> Bool) -> [(b,a)] -> ([a],[(b,a)])
247+break' p xs = let (as,bs) = breakn p xs
248+ in (as, case bs of
249+ [] -> []
250+ _ : cs -> cs)
251+
252+breakn :: (a -> Bool) -> [(b,a)] -> ([a],[(b,a)])
253+breakn p l = (map snd as,bs) where (as,bs) = break (p . snd) l
254+
255+
256+
257+decode_attr :: String -> String
258+decode_attr cs = concatMap cvt (decode_text cs)
259+ where cvt (TxtBit x) = x
260+ cvt (CRefBit x) = case cref_to_char x of
261+ Just c -> [c]
262+ Nothing -> '&' : x ++ ";"
263+
264+data Txt = TxtBit String | CRefBit String deriving Show
265+
266+decode_text :: [Char] -> [Txt]
267+decode_text xs@('&' : cs) = case break (';' ==) cs of
268+ (as,_:bs) -> CRefBit as : decode_text bs
269+ _ -> [TxtBit xs]
270+decode_text [] = []
271+decode_text cs = let (as,bs) = break ('&' ==) cs
272+ in TxtBit as : decode_text bs
273+
274+cref_to_char :: [Char] -> Maybe Char
275+cref_to_char cs = case cs of
276+ '#' : ds -> num_esc ds
277+ "lt" -> Just '<'
278+ "gt" -> Just '>'
279+ "amp" -> Just '&'
280+ "apos" -> Just '\''
281+ "quot" -> Just '"'
282+ _ -> Nothing
283+
284+num_esc :: String -> Maybe Char
285+num_esc cs = case cs of
286+ 'x' : ds -> check (readHex ds)
287+ _ -> check (reads cs)
288+
289+ where check [(n,"")] = cvt_char n
290+ check _ = Nothing
291+
292+cvt_char :: Int -> Maybe Char
293+cvt_char x
294+ | fromEnum (minBound :: Char) <= x && x <= fromEnum (maxBound::Char)
295+ = Just (toEnum x)
296+ | otherwise = Nothing
297+
298+preprocess :: String -> String
299+preprocess ('\r' : '\n' : cs) = '\n' : preprocess cs
300+preprocess ('\r' : cs) = '\n' : preprocess cs
301+preprocess (c : cs) = c : preprocess cs
302+preprocess [] = []
303+
304+linenumber :: Line -> String -> LString
305+linenumber _ [] = []
306+linenumber n ('\n':s) = n' `seq` ((n,'\n'):linenumber n' s) where n' = n + 1
307+linenumber n (c:s) = (n,c) : linenumber n s
Text/XML/Light/Output.hsnew file+150
@@ -0,0 +1,150 @@
1+--------------------------------------------------------------------
2+-- |
3+-- Module : Text.XML.Light.Output
4+-- Copyright : (c) Galois, Inc. 2007
5+-- License : BSD3
6+--
7+-- Maintainer: Iavor S. Diatchki <diatchki@galois.com>
8+-- Stability : provisional
9+-- Portability:
10+--
11+-- Output handling for the lightweight XML lib.
12+--
13+
14+module Text.XML.Light.Output
15+ ( showTopElement, showContent, showElement, showCData, showQName, showAttr
16+ , ppTopElement, ppContent, ppElement
17+ , tagEnd, xml_header
18+ ) where
19+
20+import Text.XML.Light.Types
21+import Data.Char
22+import Data.List ( isPrefixOf )
23+
24+-- | The XML 1.0 header
25+xml_header :: String
26+xml_header = "<?xml version='1.0' ?>"
27+
28+-- | Pretty printing renders XML documents faithfully,
29+-- with the exception that whitespace may be added\/removed
30+-- in non-verbatim character data.
31+ppTopElement :: Element -> String
32+ppTopElement e = unlines [xml_header,ppElement e]
33+
34+-- | Pretty printing elements
35+ppElement :: Element -> String
36+ppElement e = ppElementS "" e ""
37+
38+-- | Pretty printing content
39+ppContent :: Content -> String
40+ppContent x = ppContentS "" x ""
41+
42+-- | Pretty printing content using ShowS
43+ppContentS :: String -> Content -> ShowS
44+ppContentS i x xs = case x of
45+ Elem e -> ppElementS i e xs
46+ Text c -> ppCData i c xs
47+ CRef r -> showCRefS r xs
48+
49+ppElementS :: String -> Element -> ShowS
50+ppElementS i e xs = i ++ (tagStart (elName e) (elAttribs e) $
51+ case elContent e of
52+ []
53+ | not ("?xml" `isPrefixOf` (qName $ elName e)) -> " />" ++ xs
54+ | otherwise -> " ?>" ++ xs
55+ [Text t] -> ">" ++ ppCData "" t (tagEnd (elName e) xs)
56+ cs -> ">\n" ++ foldr ppSub (i ++ tagEnd (elName e) xs) cs
57+ where ppSub e1 = ppContentS (" " ++ i) e1 . showChar '\n'
58+ )
59+
60+ppCData :: String -> CData -> ShowS
61+ppCData i c xs = i ++ if (cdVerbatim c /= CDataText )
62+ then showCDataS c xs
63+ else foldr cons xs (showCData c)
64+
65+ where cons :: Char -> String -> String
66+ cons '\n' ys = "\n" ++ i ++ ys
67+ cons y ys = y : ys
68+
69+
70+
71+--------------------------------------------------------------------------------
72+-- | Adds the <?xml?> header.
73+showTopElement :: Element -> String
74+showTopElement c = xml_header ++ showElement c
75+
76+showContent :: Content -> String
77+showContent c = showContentS c ""
78+
79+showElement :: Element -> String
80+showElement c = showElementS c ""
81+
82+showCData :: CData -> String
83+showCData c = showCDataS c ""
84+
85+-- Note: crefs should not contain '&', ';', etc.
86+showCRefS :: String -> ShowS
87+showCRefS r xs = '&' : r ++ ';' : xs
88+
89+-- | Good for transmition (no extra white space etc.) but less readable.
90+showContentS :: Content -> ShowS
91+showContentS (Elem e) = showElementS e
92+showContentS (Text cs) = showCDataS cs
93+showContentS (CRef cs) = showCRefS cs
94+
95+-- | Good for transmition (no extra white space etc.) but less readable.
96+showElementS :: Element -> ShowS
97+showElementS e xs =
98+ tagStart (elName e) (elAttribs e)
99+ $ case elContent e of
100+ [] -> " />" ++ xs
101+ ch -> '>' : foldr showContentS (tagEnd (elName e) xs) ch
102+
103+-- | Convert a text element to characters.
104+showCDataS :: CData -> ShowS
105+showCDataS cd =
106+ case cdVerbatim cd of
107+ CDataText -> escStr (cdData cd)
108+ CDataVerbatim -> showString "<![CDATA[" . escCData (cdData cd) . showString "]]>"
109+ CDataRaw -> \ xs -> cdData cd ++ xs
110+
111+--------------------------------------------------------------------------------
112+escCData :: String -> ShowS
113+escCData (']' : ']' : '>' : cs) = showString "]]]]><![CDATA[>" . escCData cs
114+escCData (c : cs) = showChar c . escCData cs
115+escCData [] = id
116+
117+escChar :: Char -> ShowS
118+escChar c = case c of
119+ '<' -> showString "&lt;"
120+ '>' -> showString "&gt;"
121+ '&' -> showString "&amp;"
122+ '"' -> showString "&quot;"
123+ '\'' -> showString "&apos;"
124+ -- XXX: Is this really wortherd?
125+ -- We could deal with these issues when we convert characters to bytes.
126+ _ | (oc <= 0x7f && isPrint c) || c == '\n' || c == '\r' -> showChar c
127+ | otherwise -> showString "&#" . shows oc . showChar ';'
128+ where oc = ord c
129+
130+escStr :: String -> ShowS
131+escStr cs rs = foldr escChar rs cs
132+
133+tagEnd :: QName -> ShowS
134+tagEnd qn rs = '<':'/':showQName qn ++ '>':rs
135+
136+tagStart :: QName -> [Attr] -> ShowS
137+tagStart qn as rs = '<':showQName qn ++ as_str ++ rs
138+ where as_str = if null as then "" else ' ' : unwords (map showAttr as)
139+
140+showAttr :: Attr -> String
141+showAttr (Attr qn v) = showQName qn ++ '=' : '"' : escStr v "\""
142+
143+showQName :: QName -> String
144+showQName q = pre ++ qName q
145+ where pre = case qPrefix q of
146+ Nothing -> ""
147+ Just p -> p ++ ":"
148+
149+
150+
Text/XML/Light/Proc.hsnew file+103
@@ -0,0 +1,103 @@
1+--------------------------------------------------------------------
2+-- |
3+-- Module : Text.XML.Light.Proc
4+-- Copyright : (c) Galois, Inc. 2007
5+-- License : BSD3
6+--
7+-- Maintainer: Iavor S. Diatchki <diatchki@galois.com>
8+-- Stability : provisional
9+-- Portability:
10+--
11+--------------------------------------------------------------------
12+
13+
14+module Text.XML.Light.Proc where
15+
16+import Text.XML.Light.Types
17+
18+import Data.Maybe(listToMaybe)
19+import Data.List(find)
20+
21+-- | Get the text value of an XML element. This function
22+-- ignores non-text elements, and concatenates all text elements.
23+strContent :: Element -> String
24+strContent e = concatMap cdData $ onlyText $ elContent e
25+
26+-- | Select only the elements from a list of XML content.
27+onlyElems :: [Content] -> [Element]
28+onlyElems xs = [ x | Elem x <- xs ]
29+
30+-- | Select only the elements from a parent.
31+elChildren :: Element -> [Element]
32+elChildren e = [ x | Elem x <- elContent e ]
33+
34+-- | Select only the text from a list of XML content.
35+onlyText :: [Content] -> [CData]
36+onlyText xs = [ x | Text x <- xs ]
37+
38+-- | Find all immediate children with the given name.
39+findChildren :: QName -> Element -> [Element]
40+findChildren q e = filterChildren ((q ==) . elName) e
41+
42+-- | Filter all immediate children wrt a given predicate.
43+filterChildren :: (Element -> Bool) -> Element -> [Element]
44+filterChildren p e = filter p (onlyElems (elContent e))
45+
46+
47+-- | Filter all immediate children wrt a given predicate over their names.
48+filterChildrenName :: (QName -> Bool) -> Element -> [Element]
49+filterChildrenName p e = filter (p.elName) (onlyElems (elContent e))
50+
51+
52+-- | Find an immediate child with the given name.
53+findChild :: QName -> Element -> Maybe Element
54+findChild q e = listToMaybe (findChildren q e)
55+
56+-- | Find an immediate child with the given name.
57+filterChild :: (Element -> Bool) -> Element -> Maybe Element
58+filterChild p e = listToMaybe (filterChildren p e)
59+
60+-- | Find an immediate child with name matching a predicate.
61+filterChildName :: (QName -> Bool) -> Element -> Maybe Element
62+filterChildName p e = listToMaybe (filterChildrenName p e)
63+
64+-- | Find the left-most occurrence of an element matching given name.
65+findElement :: QName -> Element -> Maybe Element
66+findElement q e = listToMaybe (findElements q e)
67+
68+-- | Filter the left-most occurrence of an element wrt. given predicate.
69+filterElement :: (Element -> Bool) -> Element -> Maybe Element
70+filterElement p e = listToMaybe (filterElements p e)
71+
72+-- | Filter the left-most occurrence of an element wrt. given predicate.
73+filterElementName :: (QName -> Bool) -> Element -> Maybe Element
74+filterElementName p e = listToMaybe (filterElementsName p e)
75+
76+-- | Find all non-nested occurances of an element.
77+-- (i.e., once we have found an element, we do not search
78+-- for more occurances among the element's children).
79+findElements :: QName -> Element -> [Element]
80+findElements qn e = filterElementsName (qn==) e
81+
82+-- | Find all non-nested occurrences of an element wrt. given predicate.
83+-- (i.e., once we have found an element, we do not search
84+-- for more occurances among the element's children).
85+filterElements :: (Element -> Bool) -> Element -> [Element]
86+filterElements p e
87+ | p e = [e]
88+ | otherwise = concatMap (filterElements p) $ onlyElems $ elContent e
89+
90+-- | Find all non-nested occurences of an element wrt a predicate over element names.
91+-- (i.e., once we have found an element, we do not search
92+-- for more occurances among the element's children).
93+filterElementsName :: (QName -> Bool) -> Element -> [Element]
94+filterElementsName p e = filterElements (p.elName) e
95+
96+-- | Lookup the value of an attribute.
97+findAttr :: QName -> Element -> Maybe String
98+findAttr x e = attrVal `fmap` find ((x ==) . attrKey) (elAttribs e)
99+
100+-- | Lookup attribute name from list.
101+lookupAttr :: QName -> [Attr] -> Maybe String
102+lookupAttr x as = attrVal `fmap` find ((x ==) . attrKey) as
103+
Text/XML/Light/Types.hsnew file+91
@@ -0,0 +1,91 @@
1+--------------------------------------------------------------------
2+-- |
3+-- Module : Text.XML.Light.Types
4+-- Copyright : (c) Galois, Inc. 2007
5+-- License : BSD3
6+--
7+-- Maintainer: Iavor S. Diatchki <diatchki@galois.com>
8+-- Stability : provisional
9+-- Portability:
10+--
11+-- Basic XML types.
12+--
13+
14+module Text.XML.Light.Types where
15+
16+-- | A line is an Integer
17+type Line = Integer
18+
19+-- | XML content
20+data Content = Elem Element
21+ | Text CData
22+ | CRef String
23+ deriving Show
24+
25+-- | XML elements
26+data Element = Element {
27+ elName :: QName,
28+ elAttribs :: [Attr],
29+ elContent :: [Content],
30+ elLine :: Maybe Line
31+ } deriving Show
32+
33+-- | XML attributes
34+data Attr = Attr {
35+ attrKey :: QName,
36+ attrVal :: String
37+ } deriving (Eq,Ord,Show)
38+
39+-- | XML CData
40+data CData = CData {
41+ cdVerbatim :: CDataKind,
42+ cdData :: String,
43+ cdLine :: Maybe Line
44+ } deriving Show
45+
46+data CDataKind
47+ = CDataText -- ^ Ordinary character data; pretty printer escapes &, < etc.
48+ | CDataVerbatim -- ^ Unescaped character data; pretty printer embeds it in <![CDATA[..
49+ | CDataRaw -- ^ As-is character data; pretty printer passes it along without any escaping or CDATA wrap-up.
50+ deriving ( Eq, Show )
51+
52+-- | XML qualified names
53+data QName = QName {
54+ qName :: String,
55+ qURI :: Maybe String,
56+ qPrefix :: Maybe String
57+ } deriving Show
58+
59+
60+instance Eq QName where
61+ q1 == q2 = compare q1 q2 == EQ
62+
63+instance Ord QName where
64+ compare q1 q2 =
65+ case compare (qName q1) (qName q2) of
66+ EQ -> case (qURI q1, qURI q2) of
67+ (Nothing,Nothing) -> compare (qPrefix q1) (qPrefix q2)
68+ (u1,u2) -> compare u1 u2
69+ x -> x
70+
71+
72+-- blank elements --------------------------------------------------------------
73+
74+-- | Blank names
75+blank_name :: QName
76+blank_name = QName { qName = "", qURI = Nothing, qPrefix = Nothing }
77+
78+-- | Blank cdata
79+blank_cdata :: CData
80+blank_cdata = CData { cdVerbatim = CDataText, cdData = "", cdLine = Nothing }
81+
82+-- | Blank elements
83+blank_element :: Element
84+blank_element = Element
85+ { elName = blank_name
86+ , elAttribs = []
87+ , elContent = []
88+ , elLine = Nothing
89+ }
90+
91+
debian/copyright+33
@@ -50,3 +50,36 @@ by Eric A. Meyer
5050<http://meyerweb.com/eric/tools/s5
5151
5252Released under an explicit Public Domain License
53+
54+----------------------------------------------------------------------
55+Text/XML/Light/*
56+(c) 2007 Galois Inc.
57+
58+All rights reserved.
59+
60+Redistribution and use in source and binary forms, with or without
61+modification, are permitted provided that the following conditions
62+are met:
63+
64+1. Redistributions of source code must retain the above copyright
65+notice, this list of conditions and the following disclaimer.
66+
67+2. Redistributions in binary form must reproduce the above copyright
68+notice, this list of conditions and the following disclaimer in the
69+documentation and/or other materials provided with the distribution.
70+
71+3. Neither the name of the author nor the names of his contributors
72+may be used to endorse or promote products derived from this software
73+without specific prior written permission.
74+
75+THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND ANY EXPRESS
76+OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
77+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
78+DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR
79+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
80+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
81+OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
82+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
83+STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
84+ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
85+POSSIBILITY OF SUCH DAMAGE.
pandoc.cabal+9−4
@@ -79,8 +79,7 @@ Library
7979 if flag(highlighting)
8080 Build-depends: highlighting-kate
8181 cpp-options: -DHIGHLIGHTING
82− Build-Depends: parsec < 3, xhtml, mtl, network, filepath, process, directory, xml,
83− utf8-string
82+ Build-Depends: parsec < 3, xhtml, mtl, network, filepath, process, directory, utf8-string
8483 Hs-Source-Dirs: .
8584 Exposed-Modules: Text.Pandoc,
8685 Text.Pandoc.Blocks,
@@ -108,10 +107,16 @@ Library
108107 Text.Pandoc.Writers.MediaWiki,
109108 Text.Pandoc.Writers.RTF,
110109 Text.Pandoc.Writers.S5
111− Other-Modules: Text.Pandoc.XML
110+ Other-Modules: Text.Pandoc.XML,
111+ Text.XML.Light,
112+ Text.XML.Light.Types,
113+ Text.XML.Light.Output,
114+ Text.XML.Light.Input,
115+ Text.XML.Light.Cursor
112116 Ghc-Options: -O2 -Wall -threaded
113117 Ghc-Prof-Options: -auto-all
114− Extensions: CPP
118+ Extensions: CPP, FlexibleInstances
119+ -- FlexibleInstances needed for Text.XML.Light
115120
116121 if flag(library)
117122 Buildable: True