@@ -1,11 +1,11 @@
1−{-# LANGUAGE RecordWildCards #-}
1+{-# LANGUAGE RecordWildCards, BangPatterns #-}
3-- | A module for fast first-approximation parsing of XML.
3-- | A module for fast first-approximation parsing of XML.
4-- Note that entities, e.g. @&@, are not expanded.
4-- Note that entities, e.g. @&@, are not expanded.
5module Text.XML.Hexml(
5module Text.XML.Hexml(
6 Node, Attribute(..),
6 Node, Attribute(..),
7 parse, render,
7 parse, render,
8− name, inner, outer,
8+ location, name, inner, outer,
9 attributes, children, contents,
9 attributes, children, contents,
10 attributeBy, childrenBy
10 attributeBy, childrenBy
@@ -179,3 +179,17 @@ attributeBy (Node src doc n) str = unsafePerformIO $ withForeignPtr doc $ \d ->
179 BS.unsafeUseAsCStringLen str $ \(bs, len) -> do
179 BS.unsafeUseAsCStringLen str $ \(bs, len) -> do
180 r <- node_attributeBy d n bs $ fromIntegral len
180 r <- node_attributeBy d n bs $ fromIntegral len
181 return $ if r == nullPtr then Nothing else Just $ attrPeek src doc r
181 return $ if r == nullPtr then Nothing else Just $ attrPeek src doc r
183+-- | Find the starting location of a node, the '<' character.
184+-- The first character will be reported as @(line 1,column 1)@, because thats
185+-- how error messages typically do it.
186+location :: Node -> (Int, Int)
187+location n@(Node src _ _) = BS.foldl' f (pair 1 1) $ BS.take (fromIntegral i) src
191+ i = strStart $ nodeStr 2 n
193+ | c == '\n' = pair (line+1) 1
194+ | c == '\t' = pair line (col+8)
195+ | otherwise = pair line (col+1)