diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,23 @@
+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 the author nor the names of 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.lhs b/Setup.lhs
new file mode 100644
--- /dev/null
+++ b/Setup.lhs
@@ -0,0 +1,4 @@
+#! /usr/bin/env runhaskell
+
+> import Distribution.Simple
+> main = defaultMain
diff --git a/Text/XML/Expat/TagSoup.hs b/Text/XML/Expat/TagSoup.hs
new file mode 100644
--- /dev/null
+++ b/Text/XML/Expat/TagSoup.hs
@@ -0,0 +1,66 @@
+{-# LANGUAGE OverloadedStrings #-}
+-- | An integration of the /tagsoup/ and /hexpat/ packages, allowing HTML to be parsed to a
+-- hexpat tree, tolerant of errors.
+--
+-- The real work is done by Neil Mitchell's /tagsoup/ package.
+module Text.XML.Expat.TagSoup (
+        parseTags,
+        parseTagsOptions,
+        TS.ParseOptions(..),
+        parseOptions,
+        parseOptionsFast
+    ) where
+
+import Control.Arrow ((***))
+import Data.Maybe (mapMaybe)
+import Text.XML.Expat.SAX
+import Text.XML.Expat.Tree
+import qualified Text.HTML.TagSoup as TS
+import Text.HTML.TagSoup (Tag(..), ParseOptions(..),
+    parseOptions, parseOptionsFast, canonicalizeTags)
+import Text.StringLike (StringLike, toString)
+
+
+-- | Parse tags using TagSoup, invoke canonicalizeTags to convert them all to
+-- lower case, automatically self-close tags like @img@ and @input@, then
+-- convert to a hexpat tree.
+parseTags :: (StringLike s, GenericXMLString text) => s -> UNode text
+parseTags = tagsToTree . TS.parseTags
+
+-- | Variant that accepts options.
+parseTagsOptions :: (StringLike s, GenericXMLString text) =>
+                    TS.ParseOptions s -> s -> UNode text
+parseTagsOptions opts = tagsToTree . TS.parseTagsOptions opts
+
+tagsToTree :: (StringLike s, GenericXMLString text) => [Tag s] -> UNode text
+tagsToTree = fst . saxToTree . selfClose . mapMaybe tag2sax . canonicalizeTags
+  where
+    tag2sax (TagOpen str attrs) = Just $ StartElement (toText str) (map (toText *** toText) attrs)
+    tag2sax (TagClose str)      = Just $ EndElement (toText str)
+    tag2sax (TagText str)       = Just $ CharacterData (toText str)
+    tag2sax _                   = Nothing
+
+    toText = gxFromString . toString
+
+-- | To do - this list is not very authoritative.
+-- Also, more efficient would be nice.
+isSelfClosing :: String -> Bool
+isSelfClosing "area" = True
+isSelfClosing "base" = True
+isSelfClosing "br" = True
+isSelfClosing "col" = True
+isSelfClosing "hr" = True
+isSelfClosing "img" = True
+isSelfClosing "input" = True
+isSelfClosing "link" = True
+isSelfClosing "meta" = True
+isSelfClosing "param" = True
+isSelfClosing _ = False
+
+selfClose :: GenericXMLString text => [SAXEvent text text] -> [SAXEvent text text]
+selfClose (start@(StartElement name1 atts) : end@(EndElement name2) : rem) | name1 == name2 =
+    start : end : selfClose rem
+selfClose (start@(StartElement name atts) : rem) | isSelfClosing (gxToString name) =
+    start : EndElement name : selfClose rem
+selfClose (tag : rem) = tag : selfClose rem
+selfClose [] = []
diff --git a/hexpat-tagsoup.cabal b/hexpat-tagsoup.cabal
new file mode 100644
--- /dev/null
+++ b/hexpat-tagsoup.cabal
@@ -0,0 +1,56 @@
+name: hexpat-tagsoup
+version: 0.1
+cabal-version: -any
+build-type: Simple
+license: BSD3
+license-file: LICENSE
+copyright: Copyright (c) 2011 by Stephen Blackheath
+maintainer: Stephen Blackheath <http://blacksapphire.com/antispam>
+build-depends: base >=4 && <5, hexpat >=0.19.6 && <1,
+               tagsoup >=0.12 && <1
+stability: Alpha
+homepage:
+package-url:
+bug-reports:
+synopsis: Parse (possibly malformed) HTML to hexpat tree
+description: An integration of the /tagsoup/ and /hexpat/ packages, allowing HTML to be parsed to a
+             hexpat tree, tolerant of errors.
+             .
+             The real work is done by Neil Mitchell's /tagsoup/ package.
+             .
+             darcs repo: @http://code.haskell.org/hexpat-tagsoup/@
+category: XML
+author: Stephen Blackheath <http://blacksapphire.com/antispam>
+tested-with:
+data-files:
+data-dir: ""
+extra-source-files:
+extra-tmp-files:
+exposed-modules: Text.XML.Expat.TagSoup
+exposed: True
+buildable: True
+build-tools:
+cpp-options:
+cc-options:
+ld-options:
+pkgconfig-depends:
+frameworks:
+c-sources:
+default-language:
+other-languages:
+default-extensions:
+other-extensions:
+extensions:
+extra-libraries:
+extra-lib-dirs:
+includes:
+install-includes:
+include-dirs:
+hs-source-dirs: .
+other-modules:
+ghc-prof-options:
+ghc-shared-options:
+ghc-options:
+hugs-options:
+nhc98-options:
+jhc-options:
