diff --git a/LICENCE b/LICENCE
new file mode 100644
--- /dev/null
+++ b/LICENCE
@@ -0,0 +1,30 @@
+Copyright (c) 2019 Tony Morris
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above
+      copyright notice, this list of conditions and the following
+      disclaimer in the documentation and/or other materials provided
+      with the distribution.
+
+    * Neither the name of Tony Morris nor the names of other
+      contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,2 @@
+import Distribution.Simple
+main = defaultMain
diff --git a/changelog.md b/changelog.md
new file mode 100644
--- /dev/null
+++ b/changelog.md
@@ -0,0 +1,4 @@
+0.1.0.0
+
+* The initial version of tagsoup-navigate.
+
diff --git a/src/Text/HTML/TagSoup/Navigate.hs b/src/Text/HTML/TagSoup/Navigate.hs
new file mode 100644
--- /dev/null
+++ b/src/Text/HTML/TagSoup/Navigate.hs
@@ -0,0 +1,7 @@
+{-# OPTIONS_GHC -Wall #-}
+
+module Text.HTML.TagSoup.Navigate(module N) where
+
+import Text.HTML.TagSoup.Navigate.Parse as N
+import Text.HTML.TagSoup.Navigate.Render as N
+import Text.HTML.TagSoup.Navigate.Types as N
diff --git a/src/Text/HTML/TagSoup/Navigate/Parse.hs b/src/Text/HTML/TagSoup/Navigate/Parse.hs
new file mode 100644
--- /dev/null
+++ b/src/Text/HTML/TagSoup/Navigate/Parse.hs
@@ -0,0 +1,10 @@
+{-# OPTIONS_GHC -Wall #-}
+
+{-# LANGUAGE NoImplicitPrelude #-}
+
+module Text.HTML.TagSoup.Navigate.Parse(
+  module P
+) where
+
+import Text.HTML.TagSoup.Navigate.Parse.Parse as P
+import Text.HTML.TagSoup.Navigate.Parse.ParseOptions as P
diff --git a/src/Text/HTML/TagSoup/Navigate/Parse/Parse.hs b/src/Text/HTML/TagSoup/Navigate/Parse/Parse.hs
new file mode 100644
--- /dev/null
+++ b/src/Text/HTML/TagSoup/Navigate/Parse/Parse.hs
@@ -0,0 +1,103 @@
+{-# OPTIONS_GHC -Wall #-}
+{-# LANGUAGE NoImplicitPrelude #-}
+
+module Text.HTML.TagSoup.Navigate.Parse.Parse(
+  parseTags
+, parseTagsOptions
+, parseOptions'
+, parseOptionsFast'
+, parseOptionsEntities
+, parseTree
+, parseTreePos
+, parseTreePosState
+, parseTreeOptions
+, fromParseTree
+) where
+
+import Control.Category((.))
+import Control.Lens(( # ), (^.))
+import Data.Functor(fmap)
+import Data.Maybe(Maybe(Nothing, Just))
+import Text.HTML.TagSoup.Navigate.Parse.ParseOptions(ParseOptions, tagsoupParseOptions)
+import Text.HTML.TagSoup.Navigate.Types.Tag(Tag, tagsoupTag)
+import Text.HTML.TagSoup.Navigate.Types.TagTree(TagTree, tagsoupTagTree)
+import Text.HTML.TagSoup.Navigate.Types.TagTreePos(TagTreePos(TagTreePos), fromTagTree)
+import Text.HTML.TagSoup.Navigate.Types.TagTreePosState
+import qualified Text.HTML.TagSoup as TagSoup(parseTags, parseTagsOptions, parseOptions, parseOptionsFast, parseOptionsEntities)
+import qualified Text.HTML.TagSoup.Tree as TagSoup(parseTree, parseTreeOptions)
+import Text.StringLike(StringLike)
+
+parseTags ::
+  StringLike str =>
+  str
+  -> [Tag str]
+parseTags =
+  fmap (tagsoupTag #) . TagSoup.parseTags
+
+parseTagsOptions ::
+  StringLike str =>
+  ParseOptions str
+  -> str
+  -> [Tag str]
+parseTagsOptions o =
+  fmap (tagsoupTag #) . TagSoup.parseTagsOptions (o ^. tagsoupParseOptions)
+
+parseOptions' ::
+  StringLike str =>
+  ParseOptions str
+parseOptions' = 
+  tagsoupParseOptions # TagSoup.parseOptions
+
+parseOptionsFast' ::
+  StringLike str =>
+  ParseOptions str
+parseOptionsFast' = 
+  tagsoupParseOptions # TagSoup.parseOptionsFast
+
+parseOptionsEntities ::
+  StringLike str =>
+  (str -> Maybe str)
+  -> ParseOptions str
+parseOptionsEntities f = 
+  tagsoupParseOptions # TagSoup.parseOptionsEntities f
+
+parseTree ::
+  StringLike str =>
+  str
+  -> [TagTree str]
+parseTree =
+  fmap (tagsoupTagTree #) . TagSoup.parseTree
+
+parseTreePos ::
+  StringLike str =>
+  str
+  -> Maybe (TagTreePos str)
+parseTreePos s =
+  case parseTree s of
+    [] ->
+      Nothing
+    h:t ->
+      Just (TagTreePos h [] t [])
+
+parseTreePosState ::
+  StringLike str =>
+  str
+  -> TagTreePosState str ()
+parseTreePosState =
+  putTagTreePosState . parseTreePos
+
+parseTreeOptions ::
+  StringLike str =>
+  ParseOptions str
+  -> str
+  -> [TagTree str] 
+parseTreeOptions o =
+  fmap (tagsoupTagTree #) . TagSoup.parseTreeOptions (o ^. tagsoupParseOptions)
+
+fromParseTree ::
+  StringLike str =>
+  str
+  -> [TagTreePos str]
+fromParseTree =
+  fmap fromTagTree . parseTree
+  
diff --git a/src/Text/HTML/TagSoup/Navigate/Parse/ParseOptions.hs b/src/Text/HTML/TagSoup/Navigate/Parse/ParseOptions.hs
new file mode 100644
--- /dev/null
+++ b/src/Text/HTML/TagSoup/Navigate/Parse/ParseOptions.hs
@@ -0,0 +1,120 @@
+{-# OPTIONS_GHC -Wall #-}
+
+{-# LANGUAGE NoImplicitPrelude #-}
+{-# LANGUAGE MultiParamTypeClasses #-}
+{-# LANGUAGE FunctionalDependencies #-}
+{-# LANGUAGE FlexibleInstances #-}
+
+module Text.HTML.TagSoup.Navigate.Parse.ParseOptions(
+  ParseOptions(..)
+, HasParseOptions(..)
+, AsParseOptions(..)
+, tagsoupParseOptions
+, boolParseOptions
+, xmapParseOptions
+) where
+
+import Control.Lens(Lens', Prism', Iso, Traversal', ( # ), from, iso, (^.))
+import Text.StringLike(StringLike)
+import qualified Text.HTML.TagSoup as TagSoup(ParseOptions(ParseOptions), parseOptionsFast)
+import Text.HTML.TagSoup.Navigate.Types.Tag(Tag, tagsoupTag)
+import Data.Bool(Bool, (&&))
+import Control.Category((.), id)
+import Data.Functor(Functor(fmap), (<$>))
+import Control.Applicative((<*>), pure)
+import Data.Semigroup(Semigroup((<>)))
+import Data.Monoid(Monoid(mappend, mempty))
+
+data ParseOptions str =
+  ParseOptions
+    Bool
+    Bool
+    ((str, Bool) -> [Tag str])
+    ((str, Bool) -> (str, [Tag str]))
+    Bool
+
+class HasParseOptions s str | s -> str where
+  parseOptions ::
+    Lens' s (ParseOptions str)
+  optTagPosition ::
+    Lens' s Bool
+  optTagPosition =
+    parseOptions . optTagPosition
+  optTagWarning ::
+    Lens' s Bool
+  optTagWarning =
+    parseOptions . optTagWarning
+  optEntityDate ::
+    Lens' s ((str, Bool) -> [Tag str])
+  optEntityDate =
+    parseOptions . optEntityDate
+  optEntityAttrib ::
+    Lens' s ((str, Bool) -> (str, [Tag str]))
+  optEntityAttrib =
+    parseOptions . optEntityAttrib
+  optTagTextMerge ::
+    Lens' s Bool
+  optTagTextMerge =
+    parseOptions . optTagTextMerge
+
+instance HasParseOptions (ParseOptions str) str where
+  parseOptions =
+    id
+  optTagPosition f (ParseOptions p w ed ea tm) =
+    fmap (\p' -> ParseOptions p' w ed ea tm) (f p)
+  optTagWarning f (ParseOptions p w ed ea tm) =
+    fmap (\w' -> ParseOptions p w' ed ea tm) (f w)
+  optEntityDate f (ParseOptions p w ed ea tm) =
+    fmap (\ed' -> ParseOptions p w ed' ea tm) (f ed)
+  optEntityAttrib f (ParseOptions p w ed ea tm) =
+    fmap (\ea' -> ParseOptions p w ed ea' tm) (f ea)
+  optTagTextMerge f (ParseOptions p w ed ea tm) =
+    fmap (\tm' -> ParseOptions p w ed ea tm') (f tm)
+
+class AsParseOptions s str | s -> str where
+  _ParseOptions ::
+    Prism' s (ParseOptions str)
+
+instance AsParseOptions (ParseOptions str) str where
+  _ParseOptions =
+    id
+
+instance Semigroup str => Semigroup (ParseOptions str) where
+  ParseOptions p1 w1 ed1 ea1 tm1 <> ParseOptions p2 w2 ed2 ea2 tm2 =
+    ParseOptions (p1 && p2) (w1 && w2) (\z -> ed1 z <> ed2 z) (\z -> ea1 z <> ea2 z) (tm1 && tm2)
+
+instance (Monoid str, StringLike str) => Monoid (ParseOptions str) where
+  mempty =
+    tagsoupParseOptions # TagSoup.parseOptionsFast
+  ParseOptions p1 w1 ed1 ea1 tm1 `mappend` ParseOptions p2 w2 ed2 ea2 tm2 =
+    ParseOptions (p1 && p2) (w1 && w2) (\z -> ed1 z `mappend` ed2 z) (\z -> ea1 z `mappend` ea2 z) (tm1 && tm2)
+
+instance HasParseOptions (TagSoup.ParseOptions str) str where
+  parseOptions =
+    from tagsoupParseOptions . parseOptions
+
+instance AsParseOptions (TagSoup.ParseOptions str) str where
+  _ParseOptions =
+    from tagsoupParseOptions . _ParseOptions
+
+tagsoupParseOptions ::
+  Iso (ParseOptions str) (ParseOptions str') (TagSoup.ParseOptions str) (TagSoup.ParseOptions str')
+tagsoupParseOptions =
+  iso
+    (\(ParseOptions p w ed ea tm) ->
+      TagSoup.ParseOptions p w (fmap (^. tagsoupTag) . ed) (fmap (fmap (^. tagsoupTag)) . ea) tm)
+    (\(TagSoup.ParseOptions p w ed ea tm) ->
+      ParseOptions p w (fmap (tagsoupTag #) . ed) (fmap (fmap (tagsoupTag #)) . ea) tm)
+
+boolParseOptions ::
+  Traversal' (ParseOptions str) Bool
+boolParseOptions f (ParseOptions p w ed ea tm) =
+  ParseOptions <$> f p <*> f w <*> pure ed <*> pure ea <*> f tm
+
+xmapParseOptions ::
+  (str -> str')
+  -> (str' -> str)
+  -> ParseOptions str
+  -> ParseOptions str'
+xmapParseOptions f g (ParseOptions p w ed ea tm) =
+  ParseOptions p w (\(s, b) -> fmap (fmap f) (ed (g s, b))) (\(s, b) -> let (s', t) = (ea (g s, b)) in (f s', fmap (fmap f) t)) tm
diff --git a/src/Text/HTML/TagSoup/Navigate/Render.hs b/src/Text/HTML/TagSoup/Navigate/Render.hs
new file mode 100644
--- /dev/null
+++ b/src/Text/HTML/TagSoup/Navigate/Render.hs
@@ -0,0 +1,10 @@
+{-# OPTIONS_GHC -Wall #-}
+
+{-# LANGUAGE NoImplicitPrelude #-}
+
+module Text.HTML.TagSoup.Navigate.Render(
+  module R
+) where
+
+import Text.HTML.TagSoup.Navigate.Render.Render as R
+import Text.HTML.TagSoup.Navigate.Render.RenderOptions as R
diff --git a/src/Text/HTML/TagSoup/Navigate/Render/Render.hs b/src/Text/HTML/TagSoup/Navigate/Render/Render.hs
new file mode 100644
--- /dev/null
+++ b/src/Text/HTML/TagSoup/Navigate/Render/Render.hs
@@ -0,0 +1,56 @@
+{-# OPTIONS_GHC -Wall #-}
+{-# LANGUAGE NoImplicitPrelude #-}
+
+module Text.HTML.TagSoup.Navigate.Render.Render(
+  renderTags
+, renderTagsOptions
+, renderOptions'
+, renderTree
+, renderTreeOptions
+) where
+
+import Control.Category((.))
+import Control.Lens(( # ), (^.))
+import Data.Functor(fmap)
+import Text.HTML.TagSoup.Navigate.Render.RenderOptions(RenderOptions, tagsoupRenderOptions)
+import Text.HTML.TagSoup.Navigate.Types.Tag(Tag, tagsoupTag)
+import Text.HTML.TagSoup.Navigate.Types.TagTree(TagTree, tagsoupTagTree)
+import qualified Text.HTML.TagSoup as TagSoup(renderTags, renderTagsOptions, renderOptions)
+import qualified Text.HTML.TagSoup.Tree as TagSoup(renderTree, renderTreeOptions)
+import Text.StringLike(StringLike)
+
+renderTags ::
+  StringLike str =>
+  [Tag str]
+  -> str
+renderTags =
+  TagSoup.renderTags . fmap (^. tagsoupTag)
+
+renderTagsOptions ::
+  StringLike str =>
+  RenderOptions str
+  -> [Tag str]
+  -> str 
+renderTagsOptions o =
+  TagSoup.renderTagsOptions (o ^. tagsoupRenderOptions) . fmap (^. tagsoupTag)
+
+renderOptions' ::
+  StringLike str =>
+  RenderOptions str 
+renderOptions' =
+  tagsoupRenderOptions # TagSoup.renderOptions
+
+renderTree ::
+  StringLike str =>
+  [TagTree str]
+  -> str
+renderTree =
+  TagSoup.renderTree . fmap (^. tagsoupTagTree)
+
+renderTreeOptions ::
+  StringLike str =>
+  RenderOptions str
+  -> [TagTree str]
+  -> str
+renderTreeOptions o =
+  TagSoup.renderTreeOptions (o ^. tagsoupRenderOptions) . fmap (^. tagsoupTagTree)
diff --git a/src/Text/HTML/TagSoup/Navigate/Render/RenderOptions.hs b/src/Text/HTML/TagSoup/Navigate/Render/RenderOptions.hs
new file mode 100644
--- /dev/null
+++ b/src/Text/HTML/TagSoup/Navigate/Render/RenderOptions.hs
@@ -0,0 +1,104 @@
+{-# OPTIONS_GHC -Wall #-}
+{-# LANGUAGE NoImplicitPrelude #-}
+{-# LANGUAGE MultiParamTypeClasses #-}
+{-# LANGUAGE FunctionalDependencies #-}
+{-# LANGUAGE FlexibleInstances #-}
+
+module Text.HTML.TagSoup.Navigate.Render.RenderOptions(
+  RenderOptions(..)
+, HasRenderOptions(..)
+, AsRenderOptions(..)
+, tagsoupRenderOptions
+, boolRenderOptions
+, xmapRenderOptions
+) where
+
+import Text.StringLike(StringLike)
+import Control.Lens(Lens', Prism', Iso, Traversal', ( # ), from, iso)
+import Data.Bool(Bool, (&&))
+import Control.Category((.), id)
+import Data.Functor(fmap, (<$>))
+import Control.Applicative((<*>))
+import Data.Semigroup(Semigroup((<>)))
+import Data.Monoid(Monoid(mappend, mempty))
+import qualified Text.HTML.TagSoup as TagSoup(RenderOptions(RenderOptions), renderOptions)
+
+data RenderOptions str =
+  RenderOptions
+    (str -> str)
+    (str -> Bool)
+    (str -> Bool)
+
+class HasRenderOptions s str | s -> str where
+  renderOptions ::
+    Lens' s (RenderOptions str)
+  optEscape ::
+    Lens' s (str -> str)
+  optEscape =
+    renderOptions . optEscape
+  optMinimize ::
+    Lens' s (str -> Bool)
+  optMinimize =
+    renderOptions . optMinimize
+  optRawTag ::
+    Lens' s (str -> Bool)
+  optRawTag =
+    renderOptions . optRawTag
+
+instance HasRenderOptions (RenderOptions str) str where
+  renderOptions =
+    id
+  optEscape f (RenderOptions e m r) =
+    fmap (\e' -> RenderOptions e' m r) (f e)
+  optMinimize f (RenderOptions e m r) =
+    fmap (\m' -> RenderOptions e m' r) (f m)
+  optRawTag f (RenderOptions e m r) =
+    fmap (\r' -> RenderOptions e m r') (f r)
+
+class AsRenderOptions s str | s -> str where
+  _RenderOptions ::
+    Prism' s (RenderOptions str)
+
+instance AsRenderOptions (RenderOptions str) str where
+  _RenderOptions =
+    id
+
+instance Semigroup (RenderOptions str) where
+  RenderOptions e1 m1 r1 <> RenderOptions e2 m2 r2 =
+    RenderOptions (e1 . e2) (\s -> m1 s && m2 s) (\s -> r1 s && r2 s)
+
+instance StringLike str => Monoid (RenderOptions str) where
+  mempty =
+    tagsoupRenderOptions # TagSoup.renderOptions
+  mappend =
+    (<>)
+
+instance HasRenderOptions (TagSoup.RenderOptions str) str where
+  renderOptions =
+    from tagsoupRenderOptions . renderOptions
+
+instance AsRenderOptions (TagSoup.RenderOptions str) str where
+  _RenderOptions =
+    from tagsoupRenderOptions . _RenderOptions
+
+tagsoupRenderOptions ::
+  Iso (RenderOptions str) (RenderOptions str') (TagSoup.RenderOptions str) (TagSoup.RenderOptions str')
+tagsoupRenderOptions =
+  iso
+    (\(RenderOptions e m r) ->
+      TagSoup.RenderOptions e m r)
+    (\(TagSoup.RenderOptions e m r) ->
+      RenderOptions e m r)
+
+boolRenderOptions ::
+  Traversal' (RenderOptions str) (str -> Bool)
+boolRenderOptions f (RenderOptions e m r) =
+  RenderOptions e <$> f m <*> f r
+
+xmapRenderOptions ::
+  (str -> str')
+  -> (str' -> str)
+  -> RenderOptions str
+  -> RenderOptions str'
+xmapRenderOptions f g (RenderOptions e m r) =
+  RenderOptions (f . e . g) (m . g) (r . g)
diff --git a/src/Text/HTML/TagSoup/Navigate/Types.hs b/src/Text/HTML/TagSoup/Navigate/Types.hs
new file mode 100644
--- /dev/null
+++ b/src/Text/HTML/TagSoup/Navigate/Types.hs
@@ -0,0 +1,14 @@
+{-# OPTIONS_GHC -Wall #-}
+
+{-# LANGUAGE NoImplicitPrelude #-}
+
+module Text.HTML.TagSoup.Navigate.Types(
+  module T
+) where
+
+import Text.HTML.TagSoup.Navigate.Types.Attribute as T
+import Text.HTML.TagSoup.Navigate.Types.Tag as T
+import Text.HTML.TagSoup.Navigate.Types.TagTree as T
+import Text.HTML.TagSoup.Navigate.Types.TagTreePos as T
+import Text.HTML.TagSoup.Navigate.Types.TagTreePosParent as T
+import Text.HTML.TagSoup.Navigate.Types.TagTreePosState as T
diff --git a/src/Text/HTML/TagSoup/Navigate/Types/Attribute.hs b/src/Text/HTML/TagSoup/Navigate/Types/Attribute.hs
new file mode 100644
--- /dev/null
+++ b/src/Text/HTML/TagSoup/Navigate/Types/Attribute.hs
@@ -0,0 +1,175 @@
+{-# OPTIONS_GHC -Wall #-}
+{-# LANGUAGE NoImplicitPrelude #-}
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE TypeFamilies #-}
+{-# LANGUAGE FunctionalDependencies #-}
+
+module Text.HTML.TagSoup.Navigate.Types.Attribute(
+  Attribute(..)
+, AsAttribute(..)
+, HasAttribute(..)
+, Row
+, Column
+, bothAttributes
+, tagsoupAttribute
+) where
+
+import Control.Applicative(Applicative((<*>), pure), liftA2)
+import Control.Category((.), id)
+import Control.Lens(Each(each), Reversing(reversing), Rewrapped, Wrapped(Unwrapped), _Wrapped', _Wrapped, Field1(_1), Field2(_2), Prism', Lens', Traversal, Iso, iso)
+import Control.Monad(Monad((>>=), return))
+import Control.Monad.Zip(MonadZip(mzipWith))
+import Data.Bool((&&))
+import Data.Eq(Eq)
+import Data.Foldable(Foldable(foldMap))
+import Data.Functor(Functor(fmap), (<$>))
+import Data.Functor.Apply(Apply((<.>)))
+import Data.Functor.Bind(Bind((>>-)))
+import Data.Functor.Classes(Eq1(liftEq), Ord1(liftCompare), Show1(liftShowsPrec), showsBinaryWith)
+import Data.Monoid(Monoid(mappend, mempty))
+import Data.Ord(Ord)
+import Data.Semigroup.Foldable(Foldable1(foldMap1))
+import Data.Semigroup.Traversable(Traversable1(traverse1))
+import Data.Semigroup(Semigroup((<>)))
+import Data.Traversable(Traversable(traverse))
+import Prelude(Show)
+import Text.HTML.TagSoup(Row, Column)
+import qualified Text.HTML.TagSoup as TagSoup(Attribute)
+
+data Attribute str =
+  Attribute
+    str
+    str
+  deriving (Eq, Ord, Show)
+
+instance Functor Attribute where
+  fmap f (Attribute s1 s2) =
+    Attribute (f s1) (f s2)
+
+instance Apply Attribute where
+  Attribute s1 s2 <.> Attribute s3 s4 =
+    Attribute (s1 s3) (s2 s4)
+  
+instance Applicative Attribute where
+  pure s =
+    Attribute s s
+  (<*>) =
+    (<.>)
+
+instance Bind Attribute where
+  Attribute a b >>- f =
+    let Attribute a' _ = f a
+        Attribute _ b' = f b
+    in  Attribute a' b'
+
+instance Monad Attribute where
+  return =
+    pure
+  (>>=) =
+    (>>-)
+
+instance Foldable Attribute where
+  foldMap f (Attribute s1 s2) = 
+    f s1 `mappend` f s2
+
+instance Foldable1 Attribute where
+  foldMap1 f (Attribute a b) =
+    f a <> f b
+
+instance Traversable Attribute where
+  traverse f (Attribute s1 s2) =
+    Attribute <$> f s1 <*> f s2
+
+instance Traversable1 Attribute where
+  traverse1 f (Attribute s1 s2) =
+    Attribute <$> f s1 <.> f s2
+
+instance MonadZip Attribute where
+  mzipWith =
+    liftA2
+
+instance Semigroup str => Semigroup (Attribute str) where
+  Attribute s1 s2 <> Attribute s3 s4 =
+    Attribute (s1 <> s3) (s2 <> s4)
+
+instance Monoid str => Monoid (Attribute str) where
+  Attribute s1 s2 `mappend` Attribute s3 s4 =
+    Attribute (s1 `mappend` s3) (s2 `mappend` s4)
+  mempty =
+    Attribute mempty mempty
+
+instance Each (Attribute str) (Attribute str) str str where
+  each f (Attribute s1 s2) =
+    Attribute <$> f s1 <*> f s2
+
+instance Reversing (Attribute str) where
+  reversing (Attribute s1 s2) =
+    Attribute s2 s1
+
+instance Attribute s ~ str =>
+  Rewrapped (Attribute x) str
+
+instance Wrapped (Attribute str) where
+  type Unwrapped (Attribute str) =
+    (str, str)
+  _Wrapped' =
+    iso
+      (\(Attribute s1 s2) -> (s1, s2))
+      (\(s1, s2) -> Attribute s1 s2)
+
+instance Eq1 Attribute where
+  liftEq f (Attribute s1 s2) (Attribute s3 s4) =
+    f s1 s3 && f s2 s4
+
+instance Ord1 Attribute where
+  liftCompare f (Attribute s1 s2) (Attribute s3 s4) =
+    f s1 s3 `mappend` f s2 s4
+
+instance Show1 Attribute where
+  liftShowsPrec f _ k (Attribute s1 s2) =
+    showsBinaryWith f f "Attribute" k s1 s2
+
+instance Field1 (Attribute str) (Attribute str) str str where
+  _1 =
+    attributeName
+
+instance Field2 (Attribute str) (Attribute str) str str where
+  _2 =
+    attributeValue
+
+class AsAttribute s str | s -> str where
+  _Attribute ::
+    Prism' s (Attribute str)
+
+instance AsAttribute (Attribute str) str where
+  _Attribute = id
+
+class HasAttribute s str | s -> str where
+  attribute ::
+    Lens' s (Attribute str)
+  attributeName ::
+    Lens' s str
+  attributeName =
+    attribute . attributeName
+  attributeValue ::
+    Lens' s str
+  attributeValue =
+    attribute . attributeValue
+
+instance HasAttribute (Attribute str) str where
+  attribute =
+    id
+  attributeName f (Attribute s1 s2) =
+    fmap (\s1' -> Attribute s1' s2) (f s1)
+  attributeValue f (Attribute s1 s2) =
+    fmap (\s2' -> Attribute s1 s2') (f s2)
+
+bothAttributes ::
+  Traversal (Attribute str) (Attribute str') str str'
+bothAttributes f (Attribute s1 s2) =
+  Attribute <$> f s1 <*> f s2
+
+tagsoupAttribute ::
+  Iso (Attribute str) (Attribute str') (TagSoup.Attribute str) (TagSoup.Attribute str')
+tagsoupAttribute =
+  _Wrapped
diff --git a/src/Text/HTML/TagSoup/Navigate/Types/Tag.hs b/src/Text/HTML/TagSoup/Navigate/Types/Tag.hs
new file mode 100644
--- /dev/null
+++ b/src/Text/HTML/TagSoup/Navigate/Types/Tag.hs
@@ -0,0 +1,213 @@
+{-# OPTIONS_GHC -Wall #-}
+{-# LANGUAGE NoImplicitPrelude #-}
+{-# LANGUAGE TemplateHaskell #-}
+{-# LANGUAGE MultiParamTypeClasses #-}
+{-# LANGUAGE FunctionalDependencies #-}
+{-# LANGUAGE FlexibleInstances #-}
+
+module Text.HTML.TagSoup.Navigate.Types.Tag(
+  Tag(..)
+, HasTag(..)
+, AsTag(..)
+, tagOpen
+, tagAttributes
+, tagAttributeNames
+, tagAttributeValues
+, tagRows
+, tagColumns
+, tagsoupTag
+) where
+
+import Control.Applicative((<*>), pure)
+import Control.Category(id, (.))
+import Control.Lens(Lens', Prism', Traversal', Each(each), Iso, iso, _1, _2, (^.), ( # ))
+import Data.Eq(Eq)
+import Data.Eq.Deriving(deriveEq1)
+import Data.Ord(Ord)
+import Data.Ord.Deriving(deriveOrd1)
+import Data.Foldable(Foldable(foldMap))
+import Data.Functor(Functor(fmap), (<$>))
+import Data.Monoid(mappend, mempty)
+import Data.Traversable(Traversable(traverse))
+import Prelude(Show)
+import Text.HTML.TagSoup.Navigate.Types.Attribute(Attribute, Row, Column, attributeName, attributeValue, tagsoupAttribute)
+import qualified Text.HTML.TagSoup as TagSoup(Tag(TagOpen, TagClose, TagText, TagComment, TagWarning, TagPosition))
+import Text.Show.Deriving(deriveShow1)
+
+data Tag str
+  = TagOpen str [Attribute str]
+  | TagClose str
+  | TagText str
+  | TagComment str
+  | TagWarning str
+  | TagPosition Row Column
+  deriving (Eq, Ord, Show)
+
+instance Functor Tag where
+  fmap f (TagOpen s as) =
+    TagOpen (f s) (fmap (fmap f) as)
+  fmap f (TagClose s) =
+    TagClose (f s)
+  fmap f (TagText s) =
+    TagText (f s)
+  fmap f (TagComment s) =
+    TagComment (f s)
+  fmap f (TagWarning s) =
+    TagWarning (f s)
+  fmap _ (TagPosition r c) =
+    TagPosition r c
+
+instance Foldable Tag where
+  foldMap f (TagOpen s as) =
+    f s `mappend` foldMap (foldMap f) as
+  foldMap f (TagClose s) =
+    f s
+  foldMap f (TagText s) =
+    f s
+  foldMap f (TagComment s) =
+    f s
+  foldMap f (TagWarning s) =
+    f s
+  foldMap _ (TagPosition _ _) =
+    mempty
+
+instance Traversable Tag where
+  traverse f (TagOpen s as) =
+    TagOpen <$> f s <*> traverse (traverse f) as
+  traverse f (TagClose s) =
+    TagClose <$> f s
+  traverse f (TagText s) =
+    TagText <$> f s
+  traverse f (TagComment s) =
+    TagComment <$> f s
+  traverse f (TagWarning s) =
+    TagWarning <$> f s
+  traverse _ (TagPosition r c) =
+    pure (TagPosition r c)
+
+deriveEq1 ''Tag
+deriveOrd1 ''Tag
+deriveShow1 ''Tag
+
+instance Each (Tag str) (Tag str') str str' where
+  each f (TagOpen a as) =
+    TagOpen <$> f a <*> traverse (traverse f) as
+  each f (TagClose s) =
+    TagClose <$> f s
+  each f (TagText s) =
+    TagClose <$> f s
+  each f (TagComment s) =
+    TagClose <$> f s
+  each f (TagWarning s) =
+    TagClose <$> f s
+  each _ (TagPosition r c) =
+    pure (TagPosition r c)
+
+class HasTag a str | a -> str where
+  tag ::
+    Lens' a (Tag str)
+
+instance HasTag (Tag str) str where
+  tag =
+    id
+
+class AsTag a str | a -> str where
+  _Tag ::
+    Prism' a (Tag str)
+  _TagOpen ::
+    Prism' a (str, [Attribute str])
+  _TagOpen =
+    _Tag . _TagOpen
+  _TagClose ::
+    Prism' a str
+  _TagClose =
+    _Tag . _TagClose
+  _TagText ::
+    Prism' a str
+  _TagText =
+    _Tag . _TagText
+  _TagComment ::
+    Prism' a str
+  _TagComment =
+    _Tag . _TagComment
+  _TagWarning ::
+    Prism' a str
+  _TagWarning =
+    _Tag . _TagWarning
+  _TagPosition ::
+    Prism' a (Row, Column)
+  _TagPosition =
+    _Tag . _TagPosition
+
+instance AsTag (Tag str) str where
+  _Tag =
+    id
+
+tagOpen ::
+  AsTag a str =>
+  Traversal' a str
+tagOpen =
+  _TagOpen . _1
+
+tagAttributes ::
+  AsTag a str =>
+  Traversal' a (Attribute str)
+tagAttributes =
+  _TagOpen . _2 . traverse
+
+tagAttributeNames ::
+  AsTag a str =>
+  Traversal' a str
+tagAttributeNames =
+  tagAttributes . attributeName
+
+tagAttributeValues ::
+  AsTag a str =>
+  Traversal' a str
+tagAttributeValues =
+  tagAttributes . attributeValue
+
+tagRows ::
+  AsTag a str =>
+  Traversal' a Row
+tagRows =
+  _TagPosition . _1
+  
+tagColumns ::
+  AsTag a str =>
+  Traversal' a Column
+tagColumns =
+  _TagPosition . _2
+
+tagsoupTag ::
+  Iso (Tag str) (Tag str') (TagSoup.Tag str) (TagSoup.Tag str')
+tagsoupTag =
+  iso
+    (\t ->
+      case t of
+        TagOpen s as ->
+          TagSoup.TagOpen s (fmap (^. tagsoupAttribute) as)
+        TagClose s ->
+          TagSoup.TagClose s
+        TagText s ->
+          TagSoup.TagText s
+        TagComment s ->
+          TagSoup.TagComment s
+        TagWarning s ->
+          TagSoup.TagWarning s
+        TagPosition r c ->
+          TagSoup.TagPosition r c)
+    (\t ->
+      case t of
+        TagSoup.TagOpen s as ->
+          TagOpen s (fmap (tagsoupAttribute #) as)
+        TagSoup.TagClose s ->
+          TagClose s
+        TagSoup.TagText s ->
+          TagText s
+        TagSoup.TagComment s ->
+          TagComment s
+        TagSoup.TagWarning s ->
+          TagWarning s
+        TagSoup.TagPosition r c ->
+          TagPosition r c)
diff --git a/src/Text/HTML/TagSoup/Navigate/Types/TagTree.hs b/src/Text/HTML/TagSoup/Navigate/Types/TagTree.hs
new file mode 100644
--- /dev/null
+++ b/src/Text/HTML/TagSoup/Navigate/Types/TagTree.hs
@@ -0,0 +1,180 @@
+{-# OPTIONS_GHC -Wall #-}
+{-# LANGUAGE NoImplicitPrelude #-}
+{-# LANGUAGE TemplateHaskell #-}
+{-# LANGUAGE MultiParamTypeClasses #-}
+{-# LANGUAGE FunctionalDependencies #-}
+{-# LANGUAGE FlexibleInstances #-}
+
+module Text.HTML.TagSoup.Navigate.Types.TagTree(
+  TagTree(..)
+, HasTagTree(..)
+, AsTagTree(..)
+, tagsoupTagTree
+, tagTreeBranchNames
+, tagTreeChildren
+, tagTreeAttributes
+, tagTreeAttributeNames
+, tagTreeAttributeValues
+, tagTree'
+, flattenTree
+) where
+
+import Control.Applicative((<*>))
+import Control.Category((.), id)
+import Control.Lens(Plated(plate), Each(each), Lens', Prism', Iso, Traversal', prism', iso, (^.), ( # ), _1, _2, _3)
+import Data.Eq(Eq)
+import Data.Eq.Deriving(deriveEq1)
+import Data.Foldable(Foldable(foldMap))
+import Data.Functor(Functor(fmap), (<$>))
+import Data.Ord(Ord)
+import Data.Ord.Deriving(deriveOrd1)
+import Data.Maybe(Maybe(Just, Nothing))
+import Data.Monoid(mappend)
+import Data.Traversable(Traversable(traverse))
+import Prelude(Show)
+import Text.HTML.TagSoup.Navigate.Types.Attribute(Attribute, tagsoupAttribute, attributeName, attributeValue)
+import Text.HTML.TagSoup.Navigate.Types.Tag(Tag, AsTag(_Tag), tagsoupTag)
+import qualified Text.HTML.TagSoup.Tree as TagSoup(TagTree(TagBranch, TagLeaf), tagTree, flattenTree)
+import Text.Show.Deriving(deriveShow1)
+
+data TagTree str =
+  TagBranch
+    str
+    [Attribute str]
+    [TagTree str]
+  | TagLeaf (Tag str)
+  deriving (Eq, Ord, Show)
+
+instance Functor TagTree where
+  fmap f (TagBranch s as ts) =
+    TagBranch (f s) (fmap (fmap f) as) (fmap (fmap f) ts)
+  fmap f (TagLeaf t) =
+    TagLeaf (fmap f t)
+
+instance Foldable TagTree where
+  foldMap f (TagBranch s as ts) =
+    f s `mappend` foldMap (foldMap f) as `mappend` foldMap (foldMap f) ts
+  foldMap f (TagLeaf t) =
+    foldMap f t
+
+instance Traversable TagTree where
+  traverse f (TagBranch s as ts) =
+    TagBranch <$> f s <*> traverse (traverse f) as <*> traverse (traverse f) ts
+  traverse f (TagLeaf t) =
+    TagLeaf <$> traverse f t
+
+instance Plated (TagTree str) where
+  plate =
+    tagTreeChildren
+
+instance Each (TagTree str) (TagTree str') str str' where
+  each =
+    traverse
+
+class HasTagTree a str | a -> str where
+  tagTree ::
+    Lens' a (TagTree str)
+
+instance HasTagTree (TagTree str) str where
+  tagTree =
+    id
+
+class AsTagTree a str | a -> str where
+  _TagTree ::
+    Prism' a (TagTree str)
+  _TagBranch ::
+    Prism' a (str, [Attribute str], [TagTree str])
+  _TagBranch =
+    _TagTree . _TagBranch
+  _TagLeaf ::
+    Prism' a (Tag str)
+  _TagLeaf =
+    _TagTree . _TagLeaf
+
+instance AsTagTree (TagTree str) str where
+  _TagTree =
+    id
+  _TagBranch =
+    prism'
+      (\(s, as, t) -> TagBranch s as t)
+      (\tr ->  case tr of
+                TagBranch s as t ->
+                  Just (s, as, t)
+                TagLeaf _ ->
+                  Nothing)
+  _TagLeaf =
+    prism'
+      TagLeaf
+      (\tr ->  case tr of
+                TagBranch _ _ _ ->
+                  Nothing
+                TagLeaf x ->
+                  Just x)
+
+instance AsTag (TagTree str) str where
+  _Tag =
+    _TagLeaf . _Tag
+
+tagsoupTagTree ::
+  Iso (TagTree str) (TagTree str') (TagSoup.TagTree str) (TagSoup.TagTree str')
+tagsoupTagTree =
+  iso
+    (\tr ->
+      case tr of
+        TagBranch s as t ->
+          TagSoup.TagBranch s (fmap (^. tagsoupAttribute) as) (fmap (^. tagsoupTagTree) t)
+        TagLeaf x ->
+          TagSoup.TagLeaf (x ^. tagsoupTag))
+    (\tr ->
+      case tr of
+        TagSoup.TagBranch s as t ->
+          TagBranch s (fmap (tagsoupAttribute #) as) (fmap (tagsoupTagTree #) t)
+        TagSoup.TagLeaf x ->
+          TagLeaf (tagsoupTag # x))
+
+tagTreeBranchNames ::
+  AsTagTree a str =>
+  Traversal' a str
+tagTreeBranchNames =
+  _TagBranch . _1
+
+tagTreeAttributes ::
+  AsTagTree a str =>
+  Traversal' a (Attribute str)
+tagTreeAttributes =
+  _TagBranch . _2 . traverse
+
+tagTreeChildren ::
+  AsTagTree a str =>
+  Traversal' a (TagTree str)
+tagTreeChildren =
+  _TagBranch . _3 . traverse
+
+tagTreeAttributeNames ::
+  AsTagTree a str =>
+  Traversal' a str
+tagTreeAttributeNames =
+  tagTreeAttributes . attributeName
+
+tagTreeAttributeValues ::
+  AsTagTree a str =>
+  Traversal' a str
+tagTreeAttributeValues =
+  tagTreeAttributes . attributeValue
+
+deriveEq1 ''TagTree
+deriveOrd1 ''TagTree
+deriveShow1 ''TagTree
+
+tagTree' ::
+  Eq str =>
+  [Tag str]
+  -> [TagTree str] 
+tagTree' =
+  fmap (tagsoupTagTree #) . TagSoup.tagTree . fmap (^. tagsoupTag)
+
+flattenTree ::
+  [TagTree str]
+  -> [Tag str]
+flattenTree =
+  fmap (tagsoupTag #) . TagSoup.flattenTree . fmap (^. tagsoupTagTree)
diff --git a/src/Text/HTML/TagSoup/Navigate/Types/TagTreePos.hs b/src/Text/HTML/TagSoup/Navigate/Types/TagTreePos.hs
new file mode 100644
--- /dev/null
+++ b/src/Text/HTML/TagSoup/Navigate/Types/TagTreePos.hs
@@ -0,0 +1,137 @@
+{-# OPTIONS_GHC -Wall #-}
+{-# LANGUAGE NoImplicitPrelude #-}
+{-# LANGUAGE TemplateHaskell #-}
+{-# LANGUAGE MultiParamTypeClasses #-}
+{-# LANGUAGE FunctionalDependencies #-}
+{-# LANGUAGE FlexibleInstances #-}
+
+module Text.HTML.TagSoup.Navigate.Types.TagTreePos(
+  TagTreePos(..)
+, HasTagTreePos(..)
+, AsTagTreePos(..)
+, tagsoupTagTreePos
+, fromTagTree
+, toTagTree
+) where
+
+import Control.Applicative((<*>))
+import Control.Category((.), id)
+import Control.Lens(Each(each), Lens', Prism', Iso, iso, view, from)
+import Data.Eq(Eq)
+import Data.Eq.Deriving(deriveEq1)
+import Data.Foldable(Foldable(foldMap))
+import Data.Functor(Functor(fmap), (<$>))
+import Data.Ord(Ord)
+import Data.Ord.Deriving(deriveOrd1)
+import Data.Monoid(mappend)
+import Data.Traversable(Traversable(traverse))
+import Prelude(Show)
+import Text.HTML.TagSoup.Navigate.Types.Attribute(tagsoupAttribute)
+import Text.HTML.TagSoup.Navigate.Types.TagTree(TagTree, tagsoupTagTree)
+import Text.HTML.TagSoup.Navigate.Types.TagTreePosParent(TagTreePosParent(TagTreePosParent))
+import qualified Text.HTML.TagSoup.Tree.Zipper as TagSoup(TagTreePos(TagTreePos), fromTagTree, root)
+import Text.Show.Deriving(deriveShow1)
+
+data TagTreePos str =
+  TagTreePos
+    (TagTree str)
+    [TagTree str]
+    [TagTree str]
+    [TagTreePosParent str]
+  deriving (Eq, Ord, Show)
+
+instance Functor TagTreePos where
+  fmap f (TagTreePos c b a p) =
+    TagTreePos (fmap f c) (fmap (fmap f) b) (fmap (fmap f) a) (fmap (fmap f) p)
+
+instance Foldable TagTreePos where
+  foldMap f (TagTreePos c b a p) =
+    foldMap f c `mappend` foldMap (foldMap f) b `mappend` foldMap (foldMap f) a `mappend` foldMap (foldMap f) p
+
+instance Traversable TagTreePos where
+  traverse f (TagTreePos c b a p) =
+    TagTreePos <$> traverse f c <*> traverse (traverse f) b <*> traverse (traverse f) a <*> traverse (traverse f) p
+
+instance Each (TagTreePos str) (TagTreePos str') str str' where
+  each =
+    traverse
+
+class HasTagTreePos a str | a -> str where
+  tagTreePos ::
+    Lens' a (TagTreePos str)
+  tagTreePosContent ::
+    Lens' a (TagTree str)
+  tagTreePosContent =
+    tagTreePos . tagTreePosContent
+  tagTreePosBefore ::
+    Lens' a [TagTree str]
+  tagTreePosBefore =
+    tagTreePos . tagTreePosBefore
+  tagTreePosAfter ::
+    Lens' a [TagTree str]
+  tagTreePosAfter =
+    tagTreePos . tagTreePosAfter
+  tagTreePosParents ::
+    Lens' a [TagTreePosParent str]
+  tagTreePosParents =
+    tagTreePos . tagTreePosParents
+
+instance HasTagTreePos (TagTreePos str) str where
+  tagTreePos =
+    id
+  tagTreePosContent f (TagTreePos c b a p) =
+    fmap (\c' -> TagTreePos c' b a p) (f c)
+  tagTreePosBefore f (TagTreePos c b a p) =
+    fmap (\b' -> TagTreePos c b' a p) (f b)
+  tagTreePosAfter f (TagTreePos c b a p) =
+    fmap (\a' -> TagTreePos c b a' p) (f a)
+  tagTreePosParents f (TagTreePos c b a p) =
+    fmap (\p' -> TagTreePos c b a p') (f p)
+
+class AsTagTreePos a str | a -> str where
+  _TagTreePos ::
+    Prism' a (TagTreePos str)
+
+instance AsTagTreePos (TagTreePos str) str where
+  _TagTreePos =
+    id
+
+deriveEq1 ''TagTreePos
+deriveOrd1 ''TagTreePos
+deriveShow1 ''TagTreePos
+
+tagsoupTagTreePos ::
+  Iso (TagTreePos str) (TagTreePos str') (TagSoup.TagTreePos str) (TagSoup.TagTreePos str')
+tagsoupTagTreePos =
+  iso
+    (\(TagTreePos c b a p) ->
+      TagSoup.TagTreePos
+        (view tagsoupTagTree c)
+        (fmap (view tagsoupTagTree) b)
+        (fmap (view tagsoupTagTree) a)
+        (fmap (\(TagTreePosParent l' x' a' r') -> (fmap (view tagsoupTagTree) l', x', fmap (view tagsoupAttribute) a', fmap (view tagsoupTagTree) r')) p)
+    )
+    (\(TagSoup.TagTreePos c b a p) ->
+      let tagsoupTagTree' = 
+            from tagsoupTagTree
+          tagsoupAttribute' =
+            from tagsoupAttribute
+      in  TagTreePos
+            (view tagsoupTagTree' c)
+            (fmap (view tagsoupTagTree') b)
+            (fmap (view tagsoupTagTree') a)
+            (fmap (\(l', x', a', r') -> TagTreePosParent (fmap (view tagsoupTagTree') l') x' (fmap (view tagsoupAttribute') a') (fmap (view tagsoupTagTree') r')) p)
+    )
+
+fromTagTree ::
+  TagTree str
+  -> TagTreePos str
+fromTagTree =
+  view (from tagsoupTagTreePos) . TagSoup.fromTagTree . view tagsoupTagTree
+
+toTagTree ::
+  TagTreePos str
+  -> TagTree str
+toTagTree t =
+  let TagSoup.TagTreePos x _ _ _ = TagSoup.root (view tagsoupTagTreePos t)
+  in  view (from tagsoupTagTree) x
diff --git a/src/Text/HTML/TagSoup/Navigate/Types/TagTreePosParent.hs b/src/Text/HTML/TagSoup/Navigate/Types/TagTreePosParent.hs
new file mode 100644
--- /dev/null
+++ b/src/Text/HTML/TagSoup/Navigate/Types/TagTreePosParent.hs
@@ -0,0 +1,96 @@
+{-# OPTIONS_GHC -Wall #-}
+{-# LANGUAGE NoImplicitPrelude #-}
+{-# LANGUAGE TemplateHaskell #-}
+{-# LANGUAGE MultiParamTypeClasses #-}
+{-# LANGUAGE FunctionalDependencies #-}
+{-# LANGUAGE FlexibleInstances #-}
+
+module Text.HTML.TagSoup.Navigate.Types.TagTreePosParent(
+  TagTreePosParent(..)
+, HasTagTreePosParent(..)
+, AsTagTreePosParent(..)
+) where
+
+import Control.Applicative((<*>))
+import Control.Category((.), id)
+import Control.Lens(Each(each), Lens', Prism')
+import Data.Eq(Eq)
+import Data.Eq.Deriving(deriveEq1)
+import Data.Foldable(Foldable(foldMap))
+import Data.Functor(Functor(fmap), (<$>))
+import Data.Ord(Ord)
+import Data.Ord.Deriving(deriveOrd1)
+import Data.Monoid(mappend)
+import Data.Traversable(Traversable(traverse))
+import Prelude(Show)
+import Text.HTML.TagSoup.Navigate.Types.Attribute(Attribute)
+import Text.HTML.TagSoup.Navigate.Types.TagTree
+import Text.Show.Deriving(deriveShow1)
+
+data TagTreePosParent str =
+  TagTreePosParent 
+    [TagTree str]
+    str
+    [Attribute str]
+    [TagTree str]
+  deriving (Eq, Ord, Show)
+
+instance Functor TagTreePosParent where
+  fmap f (TagTreePosParent l x a r) =
+    TagTreePosParent (fmap (fmap f) l) (f x) (fmap (fmap f) a) (fmap (fmap f) r)
+
+instance Foldable TagTreePosParent where
+  foldMap f (TagTreePosParent l x a r) =
+    foldMap (foldMap f) l `mappend` f x `mappend` foldMap (foldMap f) a `mappend` foldMap (foldMap f) r
+
+instance Traversable TagTreePosParent where
+  traverse f (TagTreePosParent l x a r) =
+    TagTreePosParent <$> traverse (traverse f) l <*> f x <*> traverse (traverse f) a <*> traverse (traverse f) r
+
+instance Each (TagTreePosParent str) (TagTreePosParent str') str str' where
+  each =
+    traverse
+
+class HasTagTreePosParent a str | a -> str where
+  tagTreePosParent ::
+    Lens' a (TagTreePosParent str)
+  tagTreePosParentLeftSiblings ::
+    Lens' a [TagTree str]
+  tagTreePosParentLeftSiblings =
+    tagTreePosParent . tagTreePosParentLeftSiblings
+  tagTreePosParentFocus ::
+    Lens' a str
+  tagTreePosParentFocus =
+    tagTreePosParent . tagTreePosParentFocus
+  tagTreePosParentAttributes ::
+    Lens' a [Attribute str]
+  tagTreePosParentAttributes =
+    tagTreePosParent . tagTreePosParentAttributes
+  tagTreePosParentRightSiblings ::
+    Lens' a [TagTree str]
+  tagTreePosParentRightSiblings =
+    tagTreePosParent . tagTreePosParentRightSiblings
+
+instance HasTagTreePosParent (TagTreePosParent str) str where
+  tagTreePosParent =
+    id
+  tagTreePosParentLeftSiblings f (TagTreePosParent l x a r) =
+    fmap (\l' -> TagTreePosParent l' x a r) (f l)
+  tagTreePosParentFocus f (TagTreePosParent l x a r) =
+    fmap (\x' -> TagTreePosParent l x' a r) (f x)
+  tagTreePosParentAttributes f (TagTreePosParent l x a r) =
+    fmap (\a' -> TagTreePosParent l x a' r) (f a)
+  tagTreePosParentRightSiblings f (TagTreePosParent l x a r) =
+    fmap (\r' -> TagTreePosParent l x a r') (f r)
+
+class AsTagTreePosParent a str | a -> str where
+  _TagTreePosParent ::
+    Prism' a (TagTreePosParent str)
+
+instance AsTagTreePosParent (TagTreePosParent str) str where
+  _TagTreePosParent =
+    id
+
+deriveEq1 ''TagTreePosParent
+deriveOrd1 ''TagTreePosParent
+deriveShow1 ''TagTreePosParent
diff --git a/src/Text/HTML/TagSoup/Navigate/Types/TagTreePosState.hs b/src/Text/HTML/TagSoup/Navigate/Types/TagTreePosState.hs
new file mode 100644
--- /dev/null
+++ b/src/Text/HTML/TagSoup/Navigate/Types/TagTreePosState.hs
@@ -0,0 +1,344 @@
+{-# OPTIONS_GHC -Wall #-}
+{-# LANGUAGE NoImplicitPrelude #-}
+{-# LANGUAGE LambdaCase #-}
+{-# LANGUAGE FunctionalDependencies #-}
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE TypeFamilies #-}
+
+module Text.HTML.TagSoup.Navigate.Types.TagTreePosState(
+  TagTreePosStateT(..)
+, TagTreePosState
+, tagTreePosState
+, runTagTreePosStateT
+, evalTagTreePosStateT
+, execTagTreePosStateT
+, runTagTreePosState
+, evalTagTreePosState
+, execTagTreePosState
+, modifyTagTreePosStateT
+, modifyTagTreePosState
+, getsTagTreePosStateT
+, getsTagTreePosState
+, maybeTagTreePosStateT
+, maybeTagTreePosState
+, putTagTreePosStateT
+, putTagTreePosState
+, getTagTreePosT
+, getTagTreePos
+, root
+, parent
+, firstChild
+, lastChild
+, prevSibling
+, nextSibling
+, content
+, before
+, after
+, parents
+, liftTagTreePosState
+, putTagTree
+) where
+
+import Control.Applicative(Applicative((<*>), pure), Alternative((<|>), empty), liftA2)
+import Control.Category((.))
+import Control.Lens(Rewrapped, Wrapped, Unwrapped, _Wrapped', _Wrapped, iso, view, over, from, _1, _2)
+import Control.Monad(Monad(return, (>>=)))
+import Control.Monad.Morph
+import Control.Monad.Reader.Class
+import Control.Monad.State.Class
+import Control.Monad.Trans.Class(MonadTrans(lift))
+import Control.Monad.IO.Class(MonadIO(liftIO))
+import Data.Functor(Functor(fmap))
+import Data.Functor.Apply(Apply((<.>)))
+import Data.Functor.Alt(Alt((<!>)))
+import Data.Functor.Bind(Bind((>>-)))
+import Data.Functor.Identity(Identity(Identity, runIdentity))
+import Data.Maybe(Maybe(Nothing, Just))
+import Data.Semigroup(Semigroup((<>)))
+import Data.Monoid(Monoid(mempty, mappend))
+import Text.HTML.TagSoup.Navigate.Types.TagTree(TagTree)
+import Text.HTML.TagSoup.Navigate.Types.TagTreePos(TagTreePos, tagsoupTagTreePos, tagTreePosContent, tagTreePosBefore, tagTreePosAfter, tagTreePosParents, fromTagTree, toTagTree)
+import Text.HTML.TagSoup.Navigate.Types.TagTreePosParent(TagTreePosParent)
+import qualified Text.HTML.TagSoup.Tree.Zipper as TagSoup(prevSibling, nextSibling, parent, firstChild, lastChild, root)
+
+newtype TagTreePosStateT str f a =
+  TagTreePosStateT
+    (TagTreePos str -> f (Maybe (TagTreePos str, a)))
+
+type TagTreePosState str a =
+  TagTreePosStateT str Identity a
+
+tagTreePosState ::
+  (TagTreePos str -> Maybe (TagTreePos str, a))
+  -> TagTreePosState str a
+tagTreePosState k =
+  TagTreePosStateT (Identity . k)
+
+instance TagTreePosStateT str f a ~ t =>
+  Rewrapped (TagTreePosStateT str f' a') t
+
+instance Wrapped (TagTreePosStateT str f a) where
+  type Unwrapped (TagTreePosStateT str f a) =
+    TagTreePos str -> f (Maybe (TagTreePos str, a))
+  _Wrapped' =
+    iso (\(TagTreePosStateT x) -> x) TagTreePosStateT
+
+instance Functor f => Functor (TagTreePosStateT str f) where
+  fmap f (TagTreePosStateT x) =
+    TagTreePosStateT (fmap (fmap (fmap (fmap f))) x)
+
+instance Monad f => Apply (TagTreePosStateT str f) where
+  TagTreePosStateT f <.> TagTreePosStateT a =
+    TagTreePosStateT (\p -> 
+     f p >>= \case
+      Nothing ->
+        pure Nothing
+      Just (s, f') ->
+        fmap (fmap (fmap f')) (a s)
+    )
+
+instance Monad f => Applicative (TagTreePosStateT str f) where
+  pure a =
+    TagTreePosStateT (\p -> pure (pure (p, a)))
+  (<*>) =
+    (<.>)
+
+instance Monad f => Alt (TagTreePosStateT str f) where
+  TagTreePosStateT x <!> TagTreePosStateT y =
+    TagTreePosStateT (\p -> 
+      x p >>= \case
+        Nothing ->
+          y p
+        Just (s, a) ->
+          pure (Just (s, a))
+    )
+
+instance Monad f => Alternative (TagTreePosStateT str f) where
+  (<|>) =
+    (<!>)
+  empty =
+    TagTreePosStateT (pure (pure Nothing))
+
+instance Monad f => Bind (TagTreePosStateT str f) where
+  TagTreePosStateT x >>- f =
+    TagTreePosStateT (\p -> 
+      x p >>= \case
+        Nothing ->
+          pure Nothing
+        Just (s, a) ->
+          view _Wrapped (f a) s
+    )
+
+instance Monad f => Monad (TagTreePosStateT str f) where
+  return =
+    pure
+  (>>=) =
+    (>>-)
+
+instance MonadTrans (TagTreePosStateT str) where
+  lift x =
+    TagTreePosStateT (\p -> fmap (\a -> pure (p, a)) x)
+
+instance MonadIO f => MonadIO (TagTreePosStateT str f) where
+  liftIO x =
+    TagTreePosStateT (\p -> liftIO (fmap (\a -> pure (p, a)) x))
+
+instance Monad f => MonadState (TagTreePos str) (TagTreePosStateT str f) where
+  state k =
+    TagTreePosStateT (\p -> let (a, q) = k p in pure (pure (q, a)))
+  get =
+    TagTreePosStateT (\p -> pure (pure (p, p)))
+  put p =
+    TagTreePosStateT (pure (pure (pure (p, ()))))
+
+instance Monad f => MonadReader (TagTreePos str) (TagTreePosStateT str f) where
+  ask =
+    get
+  local k (TagTreePosStateT x) =
+    TagTreePosStateT (fmap (fmap (over _1 k)) . x)
+  reader k =
+    TagTreePosStateT (\p -> pure (pure (p, k p)))
+
+instance MFunctor (TagTreePosStateT str) where
+  hoist k (TagTreePosStateT x) =
+    TagTreePosStateT (k . x)
+
+instance (Monad f, Semigroup a) => Semigroup (TagTreePosStateT str f a) where
+  (<>) =
+    liftA2 (<>)
+
+instance (Monad f, Monoid a) => Monoid (TagTreePosStateT str f a) where
+  mappend =
+    liftA2 mappend
+  mempty =
+    pure mempty
+
+runTagTreePosStateT ::
+  TagTreePosStateT str f a
+  -> TagTreePos str
+  -> f (Maybe (TagTreePos str, a))
+runTagTreePosStateT =
+  view _Wrapped
+
+evalTagTreePosStateT ::
+  Functor f =>
+  TagTreePosStateT str f a
+  -> TagTreePos str
+  -> f (Maybe a)
+evalTagTreePosStateT s p =
+  fmap (fmap (view _2)) (runTagTreePosStateT s p)
+
+execTagTreePosStateT ::
+  Functor f =>
+  TagTreePosStateT str f a
+  -> TagTreePos str
+  -> f (Maybe (TagTreePos str))
+execTagTreePosStateT s p =
+  fmap (fmap (view _1)) (runTagTreePosStateT s p)
+
+runTagTreePosState ::
+  TagTreePosState str a
+  -> TagTreePos str
+  -> Maybe (TagTreePos str, a)
+runTagTreePosState s p =
+  runIdentity (runTagTreePosStateT s p)
+
+evalTagTreePosState ::
+  TagTreePosState str a
+  -> TagTreePos str
+  -> Maybe a
+evalTagTreePosState s p =
+  fmap (view _2) (runTagTreePosState s p)
+
+execTagTreePosState ::
+  TagTreePosState str a
+  -> TagTreePos str
+  -> Maybe (TagTreePos str)
+execTagTreePosState s p =
+  fmap (view _1) (runTagTreePosState s p)
+
+modifyTagTreePosStateT ::
+  Functor f =>
+  (TagTreePos x -> f (Maybe (TagTreePos x)))
+  -> TagTreePosStateT x f ()
+modifyTagTreePosStateT k =
+  TagTreePosStateT (fmap (fmap (\q -> (q, ()))) . k)
+
+modifyTagTreePosState ::
+  (TagTreePos x -> Maybe (TagTreePos x))
+  -> TagTreePosState x ()
+modifyTagTreePosState k =
+  modifyTagTreePosStateT (pure . k)
+
+getsTagTreePosStateT ::
+  Functor f =>
+  (TagTreePos x -> f (Maybe a))
+  -> TagTreePosStateT x f a
+getsTagTreePosStateT k =
+  TagTreePosStateT (\p -> fmap (fmap (\a -> (p, a))) (k p))
+
+getsTagTreePosState ::
+  (TagTreePos x -> Maybe a)
+  -> TagTreePosState x a
+getsTagTreePosState k =
+  getsTagTreePosStateT (pure . k)
+
+maybeTagTreePosStateT ::
+  Functor f =>
+  f (Maybe a)
+  -> TagTreePosStateT x f a
+maybeTagTreePosStateT =
+  getsTagTreePosStateT . pure
+
+maybeTagTreePosState ::
+  Maybe a
+  -> TagTreePosState x a
+maybeTagTreePosState =
+  getsTagTreePosState . pure
+
+putTagTreePosStateT ::
+  Functor f =>
+  f (Maybe (TagTreePos x))
+  -> TagTreePosStateT x f ()
+putTagTreePosStateT x =
+  TagTreePosStateT (pure (fmap (fmap (\p -> (p, ()))) x))
+
+putTagTreePosState ::
+  Maybe (TagTreePos x)
+  -> TagTreePosState x ()
+putTagTreePosState =
+  putTagTreePosStateT . Identity
+
+getTagTreePosT ::
+  Applicative f =>
+  TagTreePosStateT x f (TagTree x)
+getTagTreePosT =
+  liftTagTreePosState getTagTreePos
+
+getTagTreePos ::
+  TagTreePosState x (TagTree x)
+getTagTreePos =
+  reader toTagTree
+
+root ::
+  TagTreePosState str ()
+root =
+  modify (view (from tagsoupTagTreePos) . TagSoup.root . view tagsoupTagTreePos)
+  
+parent ::
+  TagTreePosState str ()
+parent =
+  modifyTagTreePosState (fmap (view (from tagsoupTagTreePos)) . TagSoup.parent . view tagsoupTagTreePos)
+  
+firstChild ::
+  TagTreePosState str ()
+firstChild =
+  modifyTagTreePosState (fmap (view (from tagsoupTagTreePos)) . TagSoup.firstChild . view tagsoupTagTreePos)
+  
+lastChild ::
+  TagTreePosState str ()
+lastChild =
+  modifyTagTreePosState (fmap (view (from tagsoupTagTreePos)) . TagSoup.lastChild . view tagsoupTagTreePos)
+  
+prevSibling ::
+  TagTreePosState str ()
+prevSibling =
+  modifyTagTreePosState (fmap (view (from tagsoupTagTreePos)) . TagSoup.prevSibling . view tagsoupTagTreePos)
+  
+nextSibling ::
+  TagTreePosState str ()
+nextSibling =
+  modifyTagTreePosState (fmap (view (from tagsoupTagTreePos)) . TagSoup.nextSibling . view tagsoupTagTreePos)
+  
+content ::
+  TagTreePosState x (TagTree x)
+content =
+  gets (view tagTreePosContent)
+
+before ::
+  TagTreePosState x [TagTree x]
+before =
+  gets (view tagTreePosBefore)
+
+after ::
+  TagTreePosState x [TagTree x]
+after =
+  gets (view tagTreePosAfter)
+
+parents ::
+  TagTreePosState x [TagTreePosParent x]
+parents =
+  gets (view tagTreePosParents)
+
+liftTagTreePosState ::
+  Applicative f =>
+  TagTreePosState str a
+  -> TagTreePosStateT str f a
+liftTagTreePosState (TagTreePosStateT x) =
+  TagTreePosStateT (pure . runIdentity . x)
+
+putTagTree ::
+  TagTree str
+  -> TagTreePosState str ()
+putTagTree =
+  put . fromTagTree
diff --git a/tagsoup-navigate.cabal b/tagsoup-navigate.cabal
new file mode 100644
--- /dev/null
+++ b/tagsoup-navigate.cabal
@@ -0,0 +1,52 @@
+name:                 tagsoup-navigate
+version:              0.1.0.0
+synopsis:             Tagsoup Navigate
+description:          Lenses and data types for navigating tagsoup
+license:              BSD3
+license-file:         LICENCE
+author:               Tony Morris <ʇǝu˙sıɹɹoɯʇ@ןןǝʞsɐɥ>
+maintainer:           Tony Morris <ʇǝu˙sıɹɹoɯʇ@ןןǝʞsɐɥ>
+copyright:            Copyright (C) 2019 Tony Morris
+category:             Test
+build-type:           Simple
+extra-source-files:   changelog.md
+cabal-version:        >=1.10
+homepage:             https://gitlab.com/tonymorris/tagsoup-navigate
+bug-reports:          https://gitlab.com/tonymorris/tagsoup-navigate/issues
+tested-with:          GHC == 8.0.2, GHC == 8.2.2, GHC == 8.4.3, GHC == 8.6.5
+
+source-repository     head
+  type:               git
+  location:           git@gitlab.com:tonymorris/tagsoup-navigate.git
+
+library
+  exposed-modules:    Text.HTML.TagSoup.Navigate
+                      Text.HTML.TagSoup.Navigate.Parse
+                      Text.HTML.TagSoup.Navigate.Parse.Parse
+                      Text.HTML.TagSoup.Navigate.Parse.ParseOptions
+                      Text.HTML.TagSoup.Navigate.Render
+                      Text.HTML.TagSoup.Navigate.Render.Render
+                      Text.HTML.TagSoup.Navigate.Render.RenderOptions
+                      Text.HTML.TagSoup.Navigate.Types
+                      Text.HTML.TagSoup.Navigate.Types.Attribute
+                      Text.HTML.TagSoup.Navigate.Types.Tag
+                      Text.HTML.TagSoup.Navigate.Types.TagTree
+                      Text.HTML.TagSoup.Navigate.Types.TagTreePos
+                      Text.HTML.TagSoup.Navigate.Types.TagTreePosParent
+                      Text.HTML.TagSoup.Navigate.Types.TagTreePosState
+
+  build-depends:        base >= 4.8 && < 5
+                      , lens >= 4 && < 5
+                      , semigroups >= 0.9 && < 0.19
+                      , semigroupoids >= 5.2 && < 6
+                      , mmorph >= 1.1 && < 2
+                      , mtl >= 2.2 && < 2.3
+                      , tagsoup >= 0.13 && < 0.14
+                      , tagsoup-selection >= 0.1.0.1 && < 0.2
+                      , transformers >= 0.5 && < 0.6
+                      , deriving-compat >= 0.5 && < 0.6
+
+  hs-source-dirs:     src
+  default-language:   Haskell2010
+  ghc-options:        -Wall
+                      
