diff --git a/hquery.cabal b/hquery.cabal
--- a/hquery.cabal
+++ b/hquery.cabal
@@ -1,5 +1,5 @@
 name:                hquery
-version:             0.1.0.2
+version:             0.1.0.3
 synopsis:            A query language for transforming HTML5
 license:             MIT
 license-file:        LICENSE
@@ -20,7 +20,7 @@
   location:          git://github.com/tych0/hquery.git
 
 library
-  build-depends: base ==4.*, parsec >= 3.1, xmlhtml >= 0.2,
+  build-depends: base ==4.*, parsec >= 3.1, xmlhtml >= 0.2.1,
                  text >= 0.11, containers
 
   hs-source-dirs: src
diff --git a/src/Text/Hquery.hs b/src/Text/Hquery.hs
--- a/src/Text/Hquery.hs
+++ b/src/Text/Hquery.hs
@@ -68,7 +68,7 @@
 import Text.Hquery.Internal.Transform
 
 parseSel :: String ->
-            (Maybe AttrSel -> Cursor -> Cursor) ->
+            (Maybe AttrSel -> Cursor -> Maybe Cursor) ->
             [Node] ->
             [Node]
 parseSel sel builder = case parse commandParser "" sel of
@@ -91,10 +91,10 @@
   hq sel target = parseSel sel nodeXform
     where
       nodeXform attr c = case (attr, current c) of
-        (Just CData, e @ Element {}) -> setNode (e { elementChildren = [TextNode (T.pack target)] }) c
+        (Just CData, e @ Element {}) -> Just $ setNode (e { elementChildren = [TextNode (T.pack target)] }) c
         -- the non-Element case isn't relevant here, since we can't match non-Elements
-        (Just s, _) -> buildAttrMod s (T.pack target) c
-        (Nothing, _) -> (setNode (TextNode (T.pack target))) c
+        (Just s, _) -> Just $ buildAttrMod s (T.pack target) c
+        (Nothing, _) -> Just $ (setNode (TextNode (T.pack target))) c
 
 instance MakeTransformer [String] where
   hq sel xs = hq sel $ map (TextNode . T.pack) xs
@@ -106,8 +106,8 @@
   hq sel (Group ns) = parseSel sel groupXform
     where
       groupXform attr c = case (attr, current c) of
-        (Just CData, e @ Element {}) -> setNode (e { elementChildren = ns }) c
-        (Just _, _) -> c -- TODO: error handling?
+        (Just CData, e @ Element {}) -> Just $ setNode (e { elementChildren = ns }) c
+        (Just _, _) -> Just c -- TODO: error handling?
         (Nothing, _) -> replaceCurrent ns c
 
 instance MakeTransformer ([Node] -> [Node]) where
@@ -124,9 +124,9 @@
   hq sel ns = parseSel sel buildNodesXform
     where
       buildNodesXform (Just CData) = replicateNode
-      buildNodesXform (Just _) = id -- TODO: error handling? can't insert nodes in an attr
-      buildNodesXform Nothing = replaceCurrent(ns)
-      replicateNode :: Cursor -> Cursor
+      buildNodesXform (Just _) = Just -- TODO: error handling? can't insert nodes in an attr
+      buildNodesXform Nothing = replaceCurrent ns
+      replicateNode :: Cursor -> Maybe Cursor
       replicateNode c = let n = (current c) in
         case n of
           e @ Element {} ->
@@ -134,7 +134,7 @@
             in replaceCurrent replicated c
           _ -> raise "bug: shouldn't be replicating on a non-Element node"
 
-replaceCurrent :: [Node] -> Cursor -> Cursor
+replaceCurrent :: [Node] -> Cursor -> Maybe Cursor
 replaceCurrent ns c = fromMaybe dflt $ do
   p <- parent c
   case current p of
@@ -142,14 +142,11 @@
       ix <- elemIndex curN kids
       let next = setNode (pn { elementChildren = concatMap replaceN kids }) p
       let childIdx = (ix - 1 + (length ns))
-      -- FIXME: xmlhtml <= 0.2.0.3 crashes on negative indicies
-      return $ fromMaybe next $ if childIdx < 0 then Nothing else getChild childIdx next
+      return $ Just $ fromMaybe next $ getChild childIdx next
     _ -> raise "should be no non-Element parents!"
   where
     curN = current c
     replaceN n2 = if n2 == curN then ns else [n2]
-    -- FIXME: replacing a root node with no elements generates a bogus comment
-    empty = fromNode (Comment "FIXME: hquery: replaced root with empty node")
-    dflt = fromMaybe empty $ do
+    dflt = do
       newCur <- (fromNodes ns)
       return (fromMaybe newCur $ findRight isLast newCur)
diff --git a/src/Text/Hquery/Internal/Transform.hs b/src/Text/Hquery/Internal/Transform.hs
--- a/src/Text/Hquery/Internal/Transform.hs
+++ b/src/Text/Hquery/Internal/Transform.hs
@@ -8,8 +8,6 @@
 import Text.XmlHtml
 import Text.XmlHtml.Cursor
 
-import Control.Monad
-
 import Text.Hquery.Internal.Error
 import Text.Hquery.Internal.Selector
 
@@ -43,18 +41,23 @@
   modifyNode f cur
 buildAttrMod CData _ _ = (raise "shouldn't be attr-modding a CData")
 
-transform :: CssSel -> (Cursor -> Cursor) -> [Node] -> [Node]
-transform sel f roots =
-  fromMaybe [] $ liftM (\c -> topNodes (transformR c)) (fromNodes roots)
+transform :: CssSel -> (Cursor -> Maybe Cursor) -> [Node] -> [Node]
+transform sel f roots = fromMaybe [] $ do
+  cur <- fromNodes roots
+  transformed <- transformR cur
+  return $ topNodes transformed
   where
-    transformR cur = do
+    transformR cur =
       let result = process cur
-      maybe result transformR (nextDF result)
+      in maybe result transformR $ do
+         r <- result
+         next <- nextDF r
+         return next
     process cur = do
       let node = current cur
       let matchAttr attr pred_ = case getAttribute attr node of
                                    Just value | pred_ value -> f cur
-                                   _ -> cur
+                                   _ -> Just cur
       case sel of
         Id name -> matchAttr "id" ((==) name)
         Name name -> matchAttr "name" ((==) name)
@@ -63,5 +66,5 @@
         Elem name ->
           case tagName node of
             Just id_ | id_ == name -> f cur
-            _ -> cur
+            _ -> Just cur
         Star -> f cur
