diff --git a/app/App/Commands/Count.hs b/app/App/Commands/Count.hs
--- a/app/App/Commands/Count.hs
+++ b/app/App/Commands/Count.hs
@@ -31,7 +31,6 @@
 import qualified App.Commands.Types as Z
 import qualified App.Naive          as NAIVE
 import qualified App.XPath.Parser   as XPP
-import qualified Data.Text          as T
 import qualified System.Exit        as IO
 import qualified System.IO          as IO
 
@@ -47,7 +46,7 @@
   { plants :: [Plant]
   } deriving (Eq, Show, Generic)
 
-tags :: Value -> String -> [Value]
+tags :: Value -> Text -> [Value]
 tags xml@(XmlElement n _ _) elemName = if n == elemName
   then [xml]
   else []
@@ -59,9 +58,9 @@
 
 countAtPath :: [Text] -> Value -> DecodeResult Int
 countAtPath []  _   = return 0
-countAtPath [t] xml = return (length (tags xml (T.unpack t)))
+countAtPath [t] xml = return (length (tags xml t))
 countAtPath (t:ts) xml = do
-  counts <- forM (tags xml (T.unpack t) >>= kids) $ countAtPath ts
+  counts <- forM (tags xml t >>= kids) $ countAtPath ts
   return (sum counts)
 
 runCount :: Z.CountOptions -> IO ()
diff --git a/app/App/Commands/Demo.hs b/app/App/Commands/Demo.hs
--- a/app/App/Commands/Demo.hs
+++ b/app/App/Commands/Demo.hs
@@ -13,6 +13,7 @@
 import Data.Foldable
 import Data.Maybe
 import Data.Semigroup                             ((<>))
+import Data.Text                                  (Text)
 import HaskellWorks.Data.TreeCursor
 import HaskellWorks.Data.Xml.Decode
 import HaskellWorks.Data.Xml.DecodeResult
@@ -29,10 +30,10 @@
 class ParseText a where
   parseText :: Value -> DecodeResult a
 
-instance ParseText String where
+instance ParseText Text where
   parseText (XmlText text)      = DecodeOk text
   parseText (XmlCData text)     = DecodeOk text
-  parseText (XmlElement _ _ cs) = DecodeOk $ concat $ concat $ toList . parseText <$> cs
+  parseText (XmlElement _ _ cs) = DecodeOk $ mconcat $ mconcat $ toList . parseText <$> cs
   parseText _                   = DecodeOk ""
 
 -- | Convert a decode result to a maybe
@@ -44,8 +45,8 @@
 -- the data in the XML document.  In fact, having a smaller model may improve
 -- query performance.
 data Plant = Plant
-  { common :: String
-  , price  :: String
+  { common :: Text
+  , price  :: Text
   } deriving (Eq, Show)
 
 newtype Catalog = Catalog
diff --git a/app/App/Naive.hs b/app/App/Naive.hs
--- a/app/App/Naive.hs
+++ b/app/App/Naive.hs
@@ -23,7 +23,7 @@
 
 -- | Load an XML file into memory and return a raw cursor initialised to the
 -- start of the XML document.
-loadSlowCursor :: String -> IO SlowCursor
+loadSlowCursor :: FilePath -> IO SlowCursor
 loadSlowCursor path = do
   !bs <- BS.readFile path
   let !cursor = fromByteString bs :: SlowCursor
@@ -31,7 +31,7 @@
 
 -- | Load an XML file into memory and return a query-optimised cursor initialised
 -- to the start of the XML document.
-loadFastCursor :: String -> IO FastCursor
+loadFastCursor :: FilePath -> IO FastCursor
 loadFastCursor filename = do
   -- Load the XML file into memory as a raw cursor.
   -- The raw XML data is `text`, and `ib` and `bp` are the indexes.
diff --git a/hw-xml.cabal b/hw-xml.cabal
--- a/hw-xml.cabal
+++ b/hw-xml.cabal
@@ -1,7 +1,7 @@
 cabal-version: 2.2
 
 name:                 hw-xml
-version:              0.4.0.6
+version:              0.5.0.0
 synopsis:             XML parser based on succinct data structures.
 description:          XML parser based on succinct data structures. Please see README.md
 category:             Data, XML, Succinct Data Structures, Data Structures
@@ -81,6 +81,7 @@
                     , mmap
                     , mtl
                     , resourcet
+                    , text
                     , transformers
                     , vector
                     , word8
@@ -96,6 +97,7 @@
                       HaskellWorks.Data.Xml.Internal.ByteString
                       HaskellWorks.Data.Xml.Internal.Blank
                       HaskellWorks.Data.Xml.Internal.List
+                      HaskellWorks.Data.Xml.Internal.Show
                       HaskellWorks.Data.Xml.Internal.Tables
                       HaskellWorks.Data.Xml.Internal.ToIbBp64
                       HaskellWorks.Data.Xml.Internal.Words
diff --git a/src/HaskellWorks/Data/Xml/Decode.hs b/src/HaskellWorks/Data/Xml/Decode.hs
--- a/src/HaskellWorks/Data/Xml/Decode.hs
+++ b/src/HaskellWorks/Data/Xml/Decode.hs
@@ -1,12 +1,16 @@
+{-# LANGUAGE OverloadedStrings #-}
+
 module HaskellWorks.Data.Xml.Decode where
 
 import Control.Applicative
 import Control.Lens
 import Control.Monad
 import Data.Foldable
-import Data.Semigroup                     ((<>))
+import Data.Semigroup                      ((<>))
+import Data.Text                           (Text)
 import HaskellWorks.Data.Xml.DecodeError
 import HaskellWorks.Data.Xml.DecodeResult
+import HaskellWorks.Data.Xml.Internal.Show
 import HaskellWorks.Data.Xml.Value
 
 class Decode a where
@@ -16,39 +20,39 @@
   decode = DecodeOk
   {-# INLINE decode #-}
 
-failDecode :: String -> DecodeResult a
+failDecode :: Text -> DecodeResult a
 failDecode = DecodeFailed . DecodeError
 
-(@>) :: Value -> String -> DecodeResult String
+(@>) :: Value -> Text -> DecodeResult Text
 (@>) (XmlElement _ as _) n = case find (\v -> fst v == n) as of
   Just (_, text) -> DecodeOk text
-  Nothing        -> failDecode $ "No such attribute " <> show n
-(@>) _ n = failDecode $ "Not an element whilst looking up attribute " <> show n
+  Nothing        -> failDecode $ "No such attribute " <> tshow n
+(@>) _ n = failDecode $ "Not an element whilst looking up attribute " <> tshow n
 
-(/>) :: Value -> String -> DecodeResult Value
+(/>) :: Value -> Text -> DecodeResult Value
 (/>) (XmlElement _ _ cs) n = go cs
-  where go []   = failDecode $ "Unable to find element " <> show n
+  where go []   = failDecode $ "Unable to find element " <> tshow n
         go (r:rs) = case r of
           e@(XmlElement n' _ _) | n' == n -> DecodeOk e
           _                               -> go rs
-(/>) _ n = failDecode $ "Expecting parent of element " <> show n
+(/>) _ n = failDecode $ "Expecting parent of element " <> tshow n
 
 (?>) :: Value -> (Value -> DecodeResult Value) -> DecodeResult Value
 (?>) v f = f v <|> pure v
 
-(~>) :: Value -> String -> DecodeResult Value
+(~>) :: Value -> Text -> DecodeResult Value
 (~>) e@(XmlElement n' _ _)  n | n' == n = DecodeOk e
-(~>) _                      n = failDecode $ "Expecting parent of element " <> show n
+(~>) _                      n = failDecode $ "Expecting parent of element " <> tshow n
 
-(/>>) :: Value -> String -> DecodeResult [Value]
+(/>>) :: Value -> Text -> DecodeResult [Value]
 (/>>) v n = v ^. childNodes <&> (~> n) <&> toList & join & pure
 
 -- Contextful
 
-(</>) :: DecodeResult Value -> String -> DecodeResult Value
+(</>) :: DecodeResult Value -> Text -> DecodeResult Value
 (</>) ma n = ma >>= (/> n)
 
-(<@>) :: DecodeResult Value -> String -> DecodeResult String
+(<@>) :: DecodeResult Value -> Text -> DecodeResult Text
 (<@>) ma n = ma >>= (@> n)
 
 (<?>) :: DecodeResult Value -> (Value -> DecodeResult Value) -> DecodeResult Value
diff --git a/src/HaskellWorks/Data/Xml/DecodeError.hs b/src/HaskellWorks/Data/Xml/DecodeError.hs
--- a/src/HaskellWorks/Data/Xml/DecodeError.hs
+++ b/src/HaskellWorks/Data/Xml/DecodeError.hs
@@ -4,6 +4,7 @@
 module HaskellWorks.Data.Xml.DecodeError where
 
 import Control.DeepSeq
+import Data.Text       (Text)
 import GHC.Generics
 
-newtype DecodeError = DecodeError String deriving (Eq, Show, Generic, NFData)
+newtype DecodeError = DecodeError Text deriving (Eq, Show, Generic, NFData)
diff --git a/src/HaskellWorks/Data/Xml/DecodeResult.hs b/src/HaskellWorks/Data/Xml/DecodeResult.hs
--- a/src/HaskellWorks/Data/Xml/DecodeResult.hs
+++ b/src/HaskellWorks/Data/Xml/DecodeResult.hs
@@ -1,4 +1,5 @@
-{-# LANGUAGE DeriveFunctor #-}
+{-# LANGUAGE DeriveFunctor     #-}
+{-# LANGUAGE OverloadedStrings #-}
 
 module HaskellWorks.Data.Xml.DecodeResult where
 
diff --git a/src/HaskellWorks/Data/Xml/Grammar.hs b/src/HaskellWorks/Data/Xml/Grammar.hs
--- a/src/HaskellWorks/Data/Xml/Grammar.hs
+++ b/src/HaskellWorks/Data/Xml/Grammar.hs
@@ -10,36 +10,39 @@
 import Control.Applicative
 import Data.Char
 import Data.String
+import Data.Text                (Text)
 import Data.Word
-import HaskellWorks.Data.Parser as P
+import HaskellWorks.Data.Parser
 
-import qualified Data.Attoparsec.Types as T
+import qualified Data.Attoparsec.Types    as T
+import qualified Data.Text                as T
+import qualified HaskellWorks.Data.Parser as P
 
 data XmlElementType
   = XmlElementTypeDocument
-  | XmlElementTypeElement String
+  | XmlElementTypeElement Text
   | XmlElementTypeComment
   | XmlElementTypeCData
-  | XmlElementTypeMeta String
+  | XmlElementTypeMeta Text
 
-parseXmlString :: (P.Parser t Word8) => T.Parser t String
+parseXmlString :: (P.Parser t Word8) => T.Parser t Text
 parseXmlString = do
   q <- satisfyChar (=='"') <|> satisfyChar (=='\'')
-  many (satisfyChar (/= q))
+  T.pack <$> many (satisfyChar (/= q))
 
 parseXmlElement :: (P.Parser t Word8, IsString t) => T.Parser t XmlElementType
 parseXmlElement = comment <|> cdata <|> doc <|> meta <|> element
   where
-  comment = const XmlElementTypeComment  <$> string "!--"
-  cdata   = const XmlElementTypeCData    <$> string "![CDATA["
-  meta    = XmlElementTypeMeta           <$> (string "!" >> parseXmlToken)
-  doc     = const XmlElementTypeDocument <$> string "?xml"
-  element = XmlElementTypeElement        <$> parseXmlToken
+  comment = const XmlElementTypeComment   <$> string "!--"
+  cdata   = const XmlElementTypeCData     <$> string "![CDATA["
+  meta    = XmlElementTypeMeta            <$> (string "!" >> parseXmlToken)
+  doc     = const XmlElementTypeDocument  <$> string "?xml"
+  element = XmlElementTypeElement         <$> parseXmlToken
 
-parseXmlToken :: (P.Parser t Word8) => T.Parser t String
-parseXmlToken = many $ satisfyChar isNameChar <?> "invalid string character"
+parseXmlToken :: (P.Parser t Word8) => T.Parser t Text
+parseXmlToken = T.pack <$> many (satisfyChar isNameChar <?> "invalid string character")
 
-parseXmlAttributeName :: (P.Parser t Word8) => T.Parser t String
+parseXmlAttributeName :: (P.Parser t Word8) => T.Parser t Text
 parseXmlAttributeName = parseXmlToken
 
 isNameStartChar :: Char -> Bool
diff --git a/src/HaskellWorks/Data/Xml/Internal/Show.hs b/src/HaskellWorks/Data/Xml/Internal/Show.hs
new file mode 100644
--- /dev/null
+++ b/src/HaskellWorks/Data/Xml/Internal/Show.hs
@@ -0,0 +1,10 @@
+module HaskellWorks.Data.Xml.Internal.Show
+  ( tshow
+  ) where
+
+import Data.Text (Text)
+
+import qualified Data.Text as T
+
+tshow :: Show a => a -> Text
+tshow = T.pack . show
diff --git a/src/HaskellWorks/Data/Xml/Lens.hs b/src/HaskellWorks/Data/Xml/Lens.hs
--- a/src/HaskellWorks/Data/Xml/Lens.hs
+++ b/src/HaskellWorks/Data/Xml/Lens.hs
@@ -1,11 +1,12 @@
 module HaskellWorks.Data.Xml.Lens where
 
 import Control.Lens
+import Data.Text                   (Text)
 import HaskellWorks.Data.Xml.Value
 
-isTagNamed :: String -> Value -> Bool
+isTagNamed :: Text -> Value -> Bool
 isTagNamed a (XmlElement b _ _) | a == b  = True
-isTagNamed _     _                        = False
+isTagNamed _     _              = False
 
-tagNamed :: (Applicative f, Choice p) => String -> Optic' p f Value Value
+tagNamed :: (Applicative f, Choice p) => Text -> Optic' p f Value Value
 tagNamed = filtered . isTagNamed
diff --git a/src/HaskellWorks/Data/Xml/RawValue.hs b/src/HaskellWorks/Data/Xml/RawValue.hs
--- a/src/HaskellWorks/Data/Xml/RawValue.hs
+++ b/src/HaskellWorks/Data/Xml/RawValue.hs
@@ -9,40 +9,44 @@
   , RawValueAt(..)
   ) where
 
+import Data.ByteString                      (ByteString)
 import Data.List
 import Data.Semigroup                       ((<>))
+import Data.Text                            (Text)
 import HaskellWorks.Data.Xml.Grammar
+import HaskellWorks.Data.Xml.Internal.Show
 import HaskellWorks.Data.Xml.Succinct.Index
 import Text.PrettyPrint.ANSI.Leijen         hiding ((<$>), (<>))
 
 import qualified Data.Attoparsec.ByteString.Char8 as ABC
 import qualified Data.ByteString                  as BS
+import qualified Data.Text                        as T
 
 data RawValue
   = RawDocument [RawValue]
-  | RawText String
-  | RawElement String [RawValue]
-  | RawCData String
-  | RawComment String
-  | RawMeta String [RawValue]
-  | RawAttrName String
-  | RawAttrValue String
+  | RawText Text
+  | RawElement Text [RawValue]
+  | RawCData Text
+  | RawComment Text
+  | RawMeta Text [RawValue]
+  | RawAttrName Text
+  | RawAttrValue Text
   | RawAttrList [RawValue]
-  | RawError String
+  | RawError Text
   deriving (Eq, Show)
 
 instance Pretty RawValue where
   pretty mjpv = case mjpv of
-    RawText s       -> ctext $ text s
-    RawAttrName s   -> text s
-    RawAttrValue s  -> (ctext . dquotes . text) s
+    RawText s       -> ctext $ text (T.unpack s)
+    RawAttrName s   -> text (T.unpack s)
+    RawAttrValue s  -> (ctext . dquotes . text) (T.unpack s)
     RawAttrList ats -> formatAttrs ats
     RawComment s    -> text $ "<!-- " <> show s <> "-->"
-    RawElement s xs -> formatElem s xs
+    RawElement s xs -> formatElem (T.unpack s) xs
     RawDocument xs  -> formatMeta "?" "xml" xs
-    RawError s      -> red $ text "[error " <> text s <> text "]"
-    RawCData s      -> cangle "<!" <> ctag (text "[CDATA[") <> text s <> cangle (text "]]>")
-    RawMeta s xs    -> formatMeta "!" s xs
+    RawError s      -> red $ text "[error " <> text (T.unpack s) <> text "]"
+    RawCData s      -> cangle "<!" <> ctag (text "[CDATA[") <> text (T.unpack s) <> cangle (text "]]>")
+    RawMeta s xs    -> formatMeta "!" (T.unpack s) xs
     where
       formatAttr at = case at of
         RawAttrName a  -> text " " <> pretty (RawAttrName a)
@@ -69,28 +73,31 @@
 
 instance RawValueAt XmlIndex where
   rawValueAt i = case i of
-    XmlIndexCData s      -> parseTextUntil "]]>" s `as` RawCData
-    XmlIndexComment s    -> parseTextUntil "-->" s `as` RawComment
-    XmlIndexMeta s cs    -> RawMeta s       (rawValueAt <$> cs)
-    XmlIndexElement s cs -> RawElement s    (rawValueAt <$> cs)
-    XmlIndexDocument cs  -> RawDocument     (rawValueAt <$> cs)
-    XmlIndexAttrName cs  -> parseAttrName cs       `as` RawAttrName
-    XmlIndexAttrValue cs -> parseString cs         `as` RawAttrValue
+    XmlIndexCData s      -> parseTextUntil "]]>" s `as` (RawCData   . T.pack)
+    XmlIndexComment s    -> parseTextUntil "-->" s `as` (RawComment . T.pack)
+    XmlIndexMeta s cs    -> RawMeta           s (rawValueAt <$> cs)
+    XmlIndexElement s cs -> RawElement        s (rawValueAt <$> cs)
+    XmlIndexDocument cs  -> RawDocument             (rawValueAt <$> cs)
+    XmlIndexAttrName cs  -> parseAttrName     cs `as` RawAttrName
+    XmlIndexAttrValue cs -> parseString       cs `as` RawAttrValue
     XmlIndexAttrList cs  -> RawAttrList     (rawValueAt <$> cs)
-    XmlIndexValue s      -> parseTextUntil "<" s   `as` RawText
+    XmlIndexValue s      -> parseTextUntil "<" s `as` (RawText . T.pack)
     XmlIndexError s      -> RawError s
     --unknown                -> XmlError ("Not yet supported: " <> show unknown)
     where
       parseUntil s = ABC.manyTill ABC.anyChar (ABC.string s)
 
+      parseTextUntil :: ByteString -> ByteString -> Either Text [Char]
       parseTextUntil s bs = case ABC.parse (parseUntil s) bs of
-        ABC.Fail    {}  -> decodeErr ("Unable to find " <> show s <> ".") bs
-        ABC.Partial _   -> decodeErr ("Unexpected end, expected " <> show s <> ".") bs
+        ABC.Fail    {}  -> decodeErr ("Unable to find " <> tshow s <> ".") bs
+        ABC.Partial _   -> decodeErr ("Unexpected end, expected " <> tshow s <> ".") bs
         ABC.Done    _ r -> Right r
+      parseString :: ByteString -> Either Text Text
       parseString bs = case ABC.parse parseXmlString bs of
         ABC.Fail    {}  -> decodeErr "Unable to parse string" bs
         ABC.Partial _   -> decodeErr "Unexpected end of string, expected" bs
         ABC.Done    _ r -> Right r
+      parseAttrName :: ByteString -> Either Text Text
       parseAttrName bs = case ABC.parse parseXmlAttributeName bs of
         ABC.Fail    {}  -> decodeErr "Unable to parse attribute name" bs
         ABC.Partial _   -> decodeErr "Unexpected end of attr name, expected" bs
@@ -116,9 +123,8 @@
   RawAttrList  _ -> True
   _              -> False
 
-as :: Either String a -> (a -> RawValue) -> RawValue
+as :: Either Text a -> (a -> RawValue) -> RawValue
 as = flip $ either RawError
 
-decodeErr :: String -> BS.ByteString -> Either String a
-decodeErr reason bs =
-  Left $ reason <>" (" <> show (BS.take 20 bs) <> "...)"
+decodeErr :: Text -> BS.ByteString -> Either Text a
+decodeErr reason bs = Left $ reason <> " (" <> tshow (BS.take 20 bs) <> "...)"
diff --git a/src/HaskellWorks/Data/Xml/Succinct/Cursor/Load.hs b/src/HaskellWorks/Data/Xml/Succinct/Cursor/Load.hs
--- a/src/HaskellWorks/Data/Xml/Succinct/Cursor/Load.hs
+++ b/src/HaskellWorks/Data/Xml/Succinct/Cursor/Load.hs
@@ -12,10 +12,10 @@
 
 -- | Load an XML file into memory and return a raw cursor initialised to the
 -- start of the XML document.
-loadSlowCursor :: String -> IO SlowCursor
+loadSlowCursor :: FilePath -> IO SlowCursor
 loadSlowCursor = fmap byteStringAsSlowCursor . BS.readFile
 
 -- | Load an XML file into memory and return a query-optimised cursor initialised
 -- to the start of the XML document.
-loadFastCursor :: String -> IO FastCursor
+loadFastCursor :: FilePath -> IO FastCursor
 loadFastCursor = fmap byteStringAsFastCursor . BS.readFile
diff --git a/src/HaskellWorks/Data/Xml/Succinct/Cursor/MMap.hs b/src/HaskellWorks/Data/Xml/Succinct/Cursor/MMap.hs
--- a/src/HaskellWorks/Data/Xml/Succinct/Cursor/MMap.hs
+++ b/src/HaskellWorks/Data/Xml/Succinct/Cursor/MMap.hs
@@ -23,7 +23,7 @@
 import qualified HaskellWorks.Data.Xml.Internal.ToIbBp64 as I
 import qualified System.IO.MMap                          as IO
 
-mmapSlowCursor :: String -> IO SlowCursor
+mmapSlowCursor :: FilePath -> IO SlowCursor
 mmapSlowCursor filePath = do
   (fptr :: ForeignPtr Word8, offset, size) <- IO.mmapFileForeignPtr filePath IO.ReadOnly Nothing
   let !bs = BSI.fromForeignPtr (castForeignPtr fptr) offset size
@@ -38,7 +38,7 @@
 
   return cursor
 
-mmapFastCursor :: String -> IO FastCursor
+mmapFastCursor :: FilePath -> IO FastCursor
 mmapFastCursor filename = do
   -- Load the XML file into memory as a raw cursor.
   -- The raw XML data is `text`, and `ib` and `bp` are the indexes.
diff --git a/src/HaskellWorks/Data/Xml/Succinct/Index.hs b/src/HaskellWorks/Data/Xml/Succinct/Index.hs
--- a/src/HaskellWorks/Data/Xml/Succinct/Index.hs
+++ b/src/HaskellWorks/Data/Xml/Succinct/Index.hs
@@ -3,6 +3,7 @@
 {-# LANGUAGE FlexibleInstances     #-}
 {-# LANGUAGE InstanceSigs          #-}
 {-# LANGUAGE MultiParamTypeClasses #-}
+{-# LANGUAGE OverloadedStrings     #-}
 
 module HaskellWorks.Data.Xml.Succinct.Index
 ( XmlIndex(..)
@@ -12,6 +13,7 @@
 
 import Control.Arrow
 import Data.Monoid
+import Data.Text                                 (Text)
 import HaskellWorks.Data.Bits.BitWise
 import HaskellWorks.Data.Drop
 import HaskellWorks.Data.Positioning
@@ -28,19 +30,20 @@
 import qualified Data.Attoparsec.ByteString.Char8 as ABC
 import qualified Data.ByteString                  as BS
 import qualified Data.List                        as L
+import qualified Data.Text                        as T
 import qualified HaskellWorks.Data.BalancedParens as BP
 
 data XmlIndex
   = XmlIndexDocument [XmlIndex]
-  | XmlIndexElement String [XmlIndex]
+  | XmlIndexElement Text [XmlIndex]
   | XmlIndexCData BS.ByteString
   | XmlIndexComment BS.ByteString
-  | XmlIndexMeta String [XmlIndex]
+  | XmlIndexMeta Text [XmlIndex]
   | XmlIndexAttrList [XmlIndex]
   | XmlIndexValue BS.ByteString
   | XmlIndexAttrName BS.ByteString
   | XmlIndexAttrValue BS.ByteString
-  | XmlIndexError String
+  | XmlIndexError Text
   deriving (Eq, Show)
 
 data XmlIndexState
@@ -65,12 +68,12 @@
 
 getIndexAt :: (BP.BalancedParens w, Rank0 w, Rank1 w, Select1 v, TestBit w) => XmlIndexState -> XmlCursor BS.ByteString v w -> XmlIndex
 getIndexAt state k = case uncons remainder of
-  Just (!c, cs) | isElementStart c          -> parseElem cs
-  Just (!c, _ ) | isSpace c                 -> XmlIndexAttrList $ mapValuesFrom InAttrList (firstChild k)
-  Just (!c, _ ) | isAttribute && isQuote c  -> XmlIndexAttrValue remainder
-  Just _        | isAttribute               -> XmlIndexAttrName remainder
-  Just _        -> XmlIndexValue remainder
-  Nothing       -> XmlIndexError "End of data"
+  Just (!c, cs) | isElementStart c         -> parseElem cs
+  Just (!c, _ ) | isSpace c                -> XmlIndexAttrList $ mapValuesFrom InAttrList (firstChild k)
+  Just (!c, _ ) | isAttribute && isQuote c -> XmlIndexAttrValue remainder
+  Just _        | isAttribute              -> XmlIndexAttrName remainder
+  Just _                                   -> XmlIndexValue remainder
+  Nothing                                  -> XmlIndexError "End of data"
   where remainder         = remText k
         mapValuesFrom s   = L.unfoldr (fmap (getIndexAt s &&& nextSibling))
         isAttribute = case state of
@@ -78,7 +81,7 @@
           InElement  -> False
           Unknown    -> case remText <$> parent k >>= uncons of
             Just (!c, _) | isSpace c -> True
-            _            -> False
+            _                        -> False
 
         parseElem bs =
           case ABC.parse parseXmlElement bs of
@@ -92,5 +95,4 @@
               XmlElementTypeDocument  -> XmlIndexDocument  (mapValuesFrom InElement (firstChild k) <> mapValuesFrom InElement (nextSibling k))
 
 decodeErr :: String -> BS.ByteString -> XmlIndex
-decodeErr reason bs =
-  XmlIndexError $ reason <>": " <> show (BS.take 20 bs) <> "...'"
+decodeErr reason bs = XmlIndexError . T.pack $ reason <>": " <> show (BS.take 20 bs) <> "...'"
diff --git a/src/HaskellWorks/Data/Xml/Value.hs b/src/HaskellWorks/Data/Xml/Value.hs
--- a/src/HaskellWorks/Data/Xml/Value.hs
+++ b/src/HaskellWorks/Data/Xml/Value.hs
@@ -19,7 +19,9 @@
   ) where
 
 import Control.Lens
-import Data.Semigroup                  ((<>))
+import Data.Semigroup                      ((<>))
+import Data.Text                           (Text)
+import HaskellWorks.Data.Xml.Internal.Show
 import HaskellWorks.Data.Xml.RawDecode
 import HaskellWorks.Data.Xml.RawValue
 
@@ -28,25 +30,25 @@
     { _childNodes :: [Value]
     }
   | XmlText
-    { _textValue :: String
+    { _textValue :: Text
     }
   | XmlElement
-    { _name       :: String
-    , _attributes :: [(String, String)]
+    { _name       :: Text
+    , _attributes :: [(Text, Text)]
     , _childNodes :: [Value]
     }
   | XmlCData
-    { _cdata :: String
+    { _cdata :: Text
     }
   | XmlComment
-    { _comment :: String
+    { _comment :: Text
     }
   | XmlMeta
-    { _name       :: String
+    { _name       :: Text
     , _childNodes :: [Value]
     }
   | XmlError
-    { _errorMessage :: String
+    { _errorMessage :: Text
     }
   deriving (Eq, Show)
 
@@ -62,14 +64,14 @@
   rawDecode (RawMeta      n cs      ) = XmlMeta       n (rawDecode <$> cs)
   rawDecode (RawAttrName  nameValue ) = XmlError      ("Can't decode attribute name: "  <> nameValue)
   rawDecode (RawAttrValue attrValue ) = XmlError      ("Can't decode attribute value: " <> attrValue)
-  rawDecode (RawAttrList  as        ) = XmlError      ("Can't decode attribute list: "  <> show as)
+  rawDecode (RawAttrList  as        ) = XmlError      ("Can't decode attribute list: "  <> tshow as)
   rawDecode (RawError     msg       ) = XmlError      msg
 
-mkXmlElement :: String -> [RawValue] -> Value
+mkXmlElement :: Text -> [RawValue] -> Value
 mkXmlElement n (RawAttrList as:cs) = XmlElement n (mkAttrs as) (rawDecode <$> cs)
 mkXmlElement n cs                  = XmlElement n []           (rawDecode <$> cs)
 
-mkAttrs :: [RawValue] -> [(String, String)]
+mkAttrs :: [RawValue] -> [(Text, Text)]
 mkAttrs (RawAttrName n:RawAttrValue v:cs) = (n, v):mkAttrs cs
 mkAttrs (_:cs)                            = mkAttrs cs
 mkAttrs []                                = []
diff --git a/test/HaskellWorks/Data/Xml/RawValueSpec.hs b/test/HaskellWorks/Data/Xml/RawValueSpec.hs
--- a/test/HaskellWorks/Data/Xml/RawValueSpec.hs
+++ b/test/HaskellWorks/Data/Xml/RawValueSpec.hs
@@ -15,6 +15,7 @@
 import Control.Monad
 import Data.Semigroup                                  ((<>))
 import Data.String
+import Data.Text                                       (Text)
 import Data.Word
 import HaskellWorks.Data.BalancedParens.BalancedParens
 import HaskellWorks.Data.BalancedParens.Simple
@@ -41,7 +42,7 @@
 fc = TC.firstChild
 ns = TC.nextSibling
 
-attrs :: [(String, String)] -> RawValue
+attrs :: [(Text, Text)] -> RawValue
 attrs as = RawAttrList $ as >>= (\(k, v) -> [RawAttrName k, RawAttrValue v])
 
 spec :: Spec
