diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,30 @@
+Copyright (c) 2014, Robert Reitmeier
+
+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 Robert Reitmeier 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/Text/XML/ToFromXML.hs b/Text/XML/ToFromXML.hs
new file mode 100644
--- /dev/null
+++ b/Text/XML/ToFromXML.hs
@@ -0,0 +1,372 @@
+{-# LANGUAGE DeriveGeneric,DefaultSignatures,UndecidableInstances,ScopedTypeVariables,
+	OverlappingInstances,TypeOperators,FlexibleContexts,FlexibleInstances #-}
+{-# OPTIONS_GHC -fcontext-stack=50 #-}
+
+{-|
+Module      : Text.XML.ToFromXML
+Description : A library for reading and writing Haskell data from/to XML files
+Copyright   : (C) Robert Reitmeier, 2014
+License     : GPL-3
+Maintainer  : concat ["public","< a t >","thinking","-","machines",".","net"]
+Stability   : experimental
+Portability : n/a
+
+In order to write a Haskell value to an XML file, the value's type just has to be an instance of 'Generic'
+(usually one would use the @deriving 'Generic'@ clause in the @data@ defintion).
+Then, the 'writeToXMLFile' will write an XML file representing the value.
+This value can be read again using 'readFromXMLFile'. See the following example
+(pragma syntax below is broken, how can one correctly incorporate comments in a haddock code block?):
+
+>{ -# LANGUAGE DeriveGeneric #- }
+>{ -# OPTIONS_GHC -fcontext-stack=50 #- }
+>
+>import Text.XML.ToFromXML
+>-- GHC.Generics is exported by ToFromXML
+>
+>data Test = Test { str::String, something::(Int,Char) }
+>	deriving (Generic,Show,Eq)
+>
+>main = do
+>	let test = Test "abc" (42,'z')
+>	writeToXMLFile "test.xml" test
+>	putStrLn $ "writeToXMLFile : " ++ show test
+>
+>	-- readFromXMLFile's return type can be inferred in this example,
+>	-- otherwise it would have to be declared
+>	test' <- readFromXMLFile "test.xml"
+>	putStrLn $ "readFromXMLFile: " ++ show test'
+>	
+>	putStrLn $ if test==test' then "OK." else "ERROR!"
+
+Remark: Both 'writeToXMLFile' and 'readFromXMLFile' require the value type
+@a@'s generic represention @Rep a@ be an instance of @GFromToXML@, but this is automatically fulfilled.
+
+The generated XML file is
+
+><?xml version="1.0" encoding="UTF-8"?>
+><CONSTRUCTOR name="Test">
+>  <ARG-1 selector="str">abc</ARG-1>
+>  <ARG-2 selector="something">
+>    <PAIR>
+>      <FIRST>42</FIRST>
+>      <SECOND>z</SECOND>
+>    </PAIR>
+>  </ARG-2>
+></CONSTRUCTOR>
+
+The general intention of this module is to keep the generated XML as intuitive and
+easy to read as possible. For example, we do flatten nested pairs used by "GHC.Generics"
+to represent n-tuples, and TABs and CRs are used to encode long text,
+so it keeps its formatting (unfortunately, CDATA sections are not supported with
+the Node types used in "Text.XML.Expat.Pickle").
+
+One might need to increase the context stack size with the @-fcontext-stack@ option
+when compiling code using this module.
+
+A test suite is included in the package, see @TestToFromXML.hs@ in the package's test directory.
+-}
+module Text.XML.ToFromXML (
+	ToFromXML(..),
+	toXML,fromXML,fromXMLEither,
+	readFromXMLFile,writeToXMLFile,
+	module GHC.Generics
+	) where
+
+import GHC.Generics
+
+import qualified Data.ByteString as BS
+
+import Text.XML.Expat.Pickle
+import Text.XML.Expat.Tree
+import qualified Text.XML.Expat.Format as Format
+
+import Text.Printf
+
+import Data.Char
+import Data.Word
+import Data.Ratio
+import Data.Int
+import qualified Data.Set as Set
+import qualified Data.Map as Map
+import qualified Data.IntMap as IntMap
+import Data.Complex
+import Data.Array.IArray
+
+-- | For the picklers, are using nodes with both tag and text being Strings.
+type Pickler a = PU (ListOf (UNode String)) a
+
+class GToFromXML f where
+	gXMLPickler :: Pickler (f p)
+
+{-|
+We do not want our XML to be cluttered with nested tuples, so we flatten
+these in the XML representation.
+-}
+class PickleProdN f where
+	-- | Given the current index in the flattened tuple, pickleProdN returns the incremented index and the pickler.
+	pickleProdN :: Int -> (Int,Pickler (f p))
+
+{-|
+Pickling a product is done by first pickling the first component, and then pickling the second
+component with the current index @i1@ returned by the first @pickleProdN i@.
+The current index @i2@ after @pickleProdN i1@ is returned.
+-}
+instance (PickleProdN f1,PickleProdN f2) => PickleProdN (f1 :*: f2) where
+	pickleProdN i = (i2,xpWrap (uncurry (:*:),\ (a :*: b) -> (a,b)) $ xpPair p1 p2) where
+		(i1,p1) = pickleProdN i
+		(i2,p2) = pickleProdN i1
+
+argTagNames = [ "ARG-" ++ show i | i <- [1..] ]
+
+instance (GToFromXML f) => PickleProdN (M1 S NoSelector f) where
+	pickleProdN i = (i+1,xpElemNodes (argTagNames!!i) gXMLPickler)
+
+{-|
+For constructor arguments, one can also leave out the selector attribute
+(like Haskell syntax allows leaving out record syntax).
+This makes it easier to manually write data XML.
+-}
+instance (GToFromXML f,Selector s) => PickleProdN (M1 S s f) where
+	pickleProdN i = (i+1,picklearg) where
+		selname = selName (undefined :: M1 S s f p)
+		picklearg = xpAlt (\_->0) [
+			xpElemWithAttr (argTagNames!!i) "selector" selname gXMLPickler,
+			xpElemNodes (argTagNames!!i) gXMLPickler ]
+
+instance (PickleProdN (f1 :*: f2)) => GToFromXML (f1 :*: f2) where
+	gXMLPickler = snd (pickleProdN 0)
+
+instance (GToFromXML f1,GToFromXML f2) => GToFromXML (f1 :+: f2) where
+	gXMLPickler = xpAlt selfun [
+		xpWrap (L1,\ (L1 x) -> x) gXMLPickler,
+		xpWrap (R1,\ (R1 x) -> x) gXMLPickler ] where
+		selfun (L1 _) = 0
+		selfun (R1 _) = 1
+
+{-|
+We won't construct a tag for @M1 D@, since it is unnecessary and cluttering the XML.
+Although, it might add to safety...
+-}
+instance (GToFromXML f,Datatype d) => GToFromXML (M1 D d f) where
+	gXMLPickler = xpWrap (M1,unM1) gXMLPickler
+
+{-|
+The CONSTRUCTOR tag contains a name attribute with the constructor's name.
+Strictly speaking it is unnecessary to encode the name as well, but improves readability
+and might add to safety...
+-}
+instance (GToFromXML f,Constructor c) => GToFromXML (M1 C c f) where
+	gXMLPickler = xpWrap (M1,unM1) $ xpElemWithAttr "CONSTRUCTOR" "name" conname gXMLPickler where
+		conname = conName (undefined :: M1 C c f p)
+
+-- | No tag created for @M1 S NoSelector@, this is handled in 'PickleProdN'.
+instance (GToFromXML f) => GToFromXML (M1 S NoSelector f) where
+	gXMLPickler = xpWrap (M1,unM1) gXMLPickler
+
+-- | No tag created for @M1 S s@, this is handled in 'PickleProdN'.
+instance (GToFromXML f,Selector s) => GToFromXML (M1 S s f) where
+	gXMLPickler = xpWrap (M1,unM1) gXMLPickler
+
+-- | A helper function injecting an attribute with a given/fixed value in a tag.
+xpElemWithAttr tag attrname attrval pickler = xpWrap (snd,\b->((),b)) $
+	xpElem tag (xpAttrFixed attrname attrval) pickler
+
+{-
+@V1@ is not an instance of 'GToFromXML', because we can't serialize data of an empty type since there
+are no constructors. It shouldn't be necessary to serialize an empty type, so @V1@ should be rejected by the type checker.
+-}
+
+instance GToFromXML U1 where
+	gXMLPickler = xpLift U1
+
+instance (ToFromXML a) => GToFromXML (K1 R a) where
+	gXMLPickler = xpWrap (K1,unK1) xMLPickler
+
+{-|
+The class 'ToFromXML' declares that there is a pickler for the instance type
+wrapped by the generic representation's @K1@ constructor.
+There are instances for data types that we do want to encode in more precise way, not
+following the generic pattern. For example, we want to encode unit @()@ as a
+distinct tag @\<UNIT\/\>@, not as text content generated with show/read.
+We give a default signature and definition which we can use conveniently by
+just stating @instance ToFromXML Word32@ for numeric types, for example.
+
+Special chars are represented in XML by Haskell's escape sequences.
+A char is not embraced by single quotes in the tag content (as it would be using the default instance).
+
+Since unfortunately CDATA sections are not supported with
+the Node types used in "Text.XML.Expat.Pickle" we are relying on,
+a String has to be represented in XML as a tag's text content, using the common Haskell escape sequences.
+For better readability and prevention of very long lines in the XML file, after each @'\r'@, @'\n'@ and @'\t'@
+the same character is inserted unescaped after the character's escape sequence.
+The unescaped character is removed again when parsing the String.
+For example, @"abc\ndef"@ will be written in the XML file as @"abc\\n\ndef"@,
+with the LF escaped (i.e. @"\\n"@) and followed by a real LF (@'\n'@).
+Injecting line breaks and tabs makes long text much more readable und editable by humans
+(which is one of the original purposes of XML).
+The real LF will be filtered out again while parsing the XML file String.
+
+-}
+class ToFromXML a where
+	-- | An instance of 'ToFromXML' provides a pickler for type @a@.
+	xMLPickler :: Pickler a
+	-- | The default signature of 'xMLPickler' requires 'Read' and 'Show' instances
+	default xMLPickler :: (Read a,Show a) => Pickler a
+	-- | The default definition via 'xpPrim' uses show and read to convert the value to XML tag text content.
+	xMLPickler = xpContent xpPrim
+
+instance ToFromXML () where
+	xMLPickler = xpElemNodes "UNIT" xpUnit
+
+instance (ToFromXML a) => ToFromXML [a] where
+	xMLPickler = xpElemNodes "LIST" $ xpList0 $ xpElemNodes "ITEM" xMLPickler
+
+instance ToFromXML Int
+instance ToFromXML Int8
+instance ToFromXML Int16
+instance ToFromXML Int32
+instance ToFromXML Int64
+instance ToFromXML Integer
+instance ToFromXML Word
+instance ToFromXML Word8
+instance ToFromXML Word16
+instance ToFromXML Word32
+instance ToFromXML Word64
+instance ToFromXML Float
+instance ToFromXML Double
+instance (Show a,Read a,Integral a) => ToFromXML (Ratio a)
+instance (Show a,Read a) => ToFromXML (Complex a)
+
+instance ToFromXML Bool where
+	xMLPickler = xpAlt selfun [
+		xpElemNodes "TRUE"  $ xpLift True,
+		xpElemNodes "FALSE" $ xpLift False ] where
+		selfun True  = 0
+		selfun False = 1
+
+instance ToFromXML Char where
+	xMLPickler = xpContent $ xpWrap ( fst.head.readLitChar, (`showLitChar` "") ) xpText
+
+instance ToFromXML String where
+	xMLPickler = xpContent pickleContentString
+
+skipPickleString = (`elem` ['\r','\n','\t'])
+
+{-|
+Pickles a string to/from text content with escaping 
+-}
+pickleContentString :: PU String String
+pickleContentString = xpWrap ( readLitString, showLitString ) xpText0 where
+	readLitString "" = ""
+	readLitString (c:ss) | skipPickleString c = readLitString ss
+	readLitString s  = let [(c,ss)] = readLitChar s in c : readLitString ss
+	showLitString "" = ""
+	showLitString (c:ss) | skipPickleString c = showLitChar c $ c : showLitString ss
+	showLitString (c:ss) = showLitChar c $ showLitString ss
+
+{-
+Pickler for a Map.
+Didn't use 'xpMap' because @show@ing keys as attributes might be inconvenient/unreadable for more complex key types.
+-}
+instance (Ord k,ToFromXML k,ToFromXML v) => ToFromXML (Map.Map k v) where
+	xMLPickler = xpElemNodes "MAP" $ xpWrap (Map.fromList,Map.toList) $ xpList $ 
+		xpElemNodes "ASSOC" $ xpPair
+			(xpElemNodes "KEY"  xMLPickler)
+			(xpElemNodes "ELEM" xMLPickler)
+
+instance (ToFromXML v) => ToFromXML (IntMap.IntMap v) where
+	xMLPickler = xpElemNodes "INTMAP" $ xpWrap (IntMap.fromList,IntMap.toList) $ xpList $ 
+		xpElem "ELEM" (xpAttr "index" xpPrim) xMLPickler
+
+-- Didn't use an attribute for the dimension of the tuple because this is not checkable by a schema.
+instance (ToFromXML a,ToFromXML b) => ToFromXML (a,b) where
+	xMLPickler = xpElemNodes "PAIR" $ xpPair (xpComponent 0) (xpComponent 1)
+
+instance (ToFromXML a,ToFromXML b,ToFromXML c) => ToFromXML (a,b,c) where
+	xMLPickler = xpElemNodes "TRIPLE" $ xpTriple (xpComponent 0) (xpComponent 1) (xpComponent 2)
+
+instance (ToFromXML a,ToFromXML b,ToFromXML c,ToFromXML d) => ToFromXML (a,b,c,d) where
+	xMLPickler = xpElemNodes "QUADRUPLE" $ xp4Tuple (xpComponent 0) (xpComponent 1) (xpComponent 2) (xpComponent 3)
+
+instance (ToFromXML a,ToFromXML b,ToFromXML c,ToFromXML d,ToFromXML e) => ToFromXML (a,b,c,d,e) where
+	xMLPickler = xpElemNodes "QUINTUPLE" $ xp5Tuple (xpComponent 0) (xpComponent 1) (xpComponent 2) (xpComponent 3) (xpComponent 4)
+
+instance (ToFromXML a,ToFromXML b,ToFromXML c,ToFromXML d,ToFromXML e,ToFromXML f) => ToFromXML (a,b,c,d,e,f) where
+	xMLPickler = xpElemNodes "SEXTUPLE" $ xp6Tuple (xpComponent 0) (xpComponent 1) (xpComponent 2) (xpComponent 3) (xpComponent 4) (xpComponent 5)
+
+-- | Pickle a tuple's i\'th component. The component tag names are distinct, otherwise hexpat-pickle confuses this with a list and gives a parse error.
+xpComponent :: (ToFromXML a) => Int -> Pickler a
+xpComponent i = xpElemNodes (componentnames!!i) xMLPickler where
+	componentnames = [ "FIRST","SECOND","THIRD","FOURTH","FIFTH","SIXTH" ]
+
+instance (ToFromXML a) => ToFromXML (Maybe a) where
+	xMLPickler = xpAlt selfun [
+		xpElemNodes "NOTHING" $ xpLift Nothing,
+		xpElemNodes "JUST"    $ xpWrap (Just, \ (Just a) -> a ) xMLPickler ] where
+		selfun Nothing  = 0
+		selfun (Just _) = 1
+
+instance (ToFromXML a,ToFromXML b) => ToFromXML (Either a b) where
+	xMLPickler = xpAlt selfun [
+		xpElemNodes "LEFT"  $ xpWrap ( Left,  \ (Left  a) -> a ) xMLPickler,
+		xpElemNodes "RIGHT" $ xpWrap ( Right, \ (Right b) -> b ) xMLPickler ] where
+		selfun (Left  _) = 0
+		selfun (Right _) = 1
+
+instance (ToFromXML a,Ord a) => ToFromXML (Set.Set a) where
+	xMLPickler = xpElemNodes "SET" $ xpWrap (Set.fromList,Set.toList) $ xpList $
+		xpElemNodes "ELEM" xMLPickler
+
+-- TODO: Insert ToFromXML instances for date and time types, maybe in conformance to XSD types?
+
+-- Here we assume that array index types (usually 'Int') are sufficiently simple to be represented as string in an attribute.
+instance (Ix i,Show i,Read i,ToFromXML e) => ToFromXML (Array i e) where
+	xMLPickler = xpWrap (list2arr,arr2list) $ xpElem "ARRAY" xpbounds $ xpList $
+		xpElemNodes "ELEM" xMLPickler where
+			xpbounds = xpPair (xpAttr "lowerBound" xpPrim) (xpAttr "upperBound" xpPrim)
+			arr2list arr = (bounds arr,elems arr)
+			list2arr (bounds,arrelems) = listArray bounds arrelems
+
+-- This is the catch-all instance, leading to the generic @Rep a@ representation
+instance (Generic a,GToFromXML (Rep a)) => ToFromXML a where
+	xMLPickler = xpWrap (to,from) gXMLPickler
+
+{-|
+Converts generic Haskell data to a (strict) 'ByteString' containing the XML representation.
+In most cases, the data type would probably be @deriving 'Generic'@ using the @DeriveGeneric@ language pragma.
+-}
+toXML :: (Generic a,GToFromXML (Rep a)) => a -> BS.ByteString
+toXML x = Format.format' $ Format.indent 2 $ pickleTree (xpRoot gXMLPickler) (from x)
+
+{-|
+Construct generic Haskell data from a (strict) 'ByteString' containing the XML representation.
+fromXMLEither will return 'Left' in case of a 'XMLParseError', 'Right' otherwise.
+-}
+fromXMLEither :: (GToFromXML f) => BS.ByteString -> Either String (f p)
+fromXMLEither bs = case parse' defaultParseOptions bs of
+	Left (XMLParseError errmsg loc) ->
+		Left $ printf "XMLParseError at %s:\n    %s" (show loc) errmsg
+	Right tree ->
+		unpickleTree' (xpRoot gXMLPickler) tree
+
+{-|
+Convenience function wrapping around 'fromXMLEither', throwing an error in case of a parsing error.
+-}
+fromXML :: (Generic a,GToFromXML (Rep a)) => BS.ByteString -> a
+fromXML bs = case fromXMLEither bs of
+	Left  errmsg -> error errmsg
+	Right x      -> to x
+
+{-|
+Action writing an XML representation of generic Haskell data to a file.
+The underlying writeFile operation is strict.
+-}
+writeToXMLFile :: (Generic a,GToFromXML (Rep a)) => FilePath -> a -> IO ()
+writeToXMLFile filepath a = BS.writeFile filepath $ toXML a
+
+{-|
+Action reading generic Haskell data from an XML file.
+The underlying readFile operation is strict.
+-}
+readFromXMLFile :: (Generic a,GToFromXML (Rep a)) => FilePath -> IO a
+readFromXMLFile filepath = BS.readFile filepath >>= return . fromXML
diff --git a/test/Example.hs b/test/Example.hs
new file mode 100644
--- /dev/null
+++ b/test/Example.hs
@@ -0,0 +1,20 @@
+{-# LANGUAGE DeriveGeneric #-}
+{-# OPTIONS_GHC -fcontext-stack=50 #-}
+
+import Text.XML.ToFromXML
+-- GHC.Generics is exported by ToFromXML
+
+data Test = Test { str::String, something::(Int,Char) }
+	deriving (Generic,Show,Eq)
+
+main = do
+	let test = Test "abc" (42,'z')
+	writeToXMLFile "test.xml" test
+	putStrLn $ "writeToXMLFile : " ++ show test
+
+	-- readFromXMLFile's return type can be inferred in this example,
+	-- otherwise it would have to be declared
+	test' <- readFromXMLFile "test.xml"
+	putStrLn $ "readFromXMLFile: " ++ show test'
+	
+	putStrLn $ if test==test' then "OK." else "ERROR!"
diff --git a/test/TestToFromXML.hs b/test/TestToFromXML.hs
new file mode 100644
--- /dev/null
+++ b/test/TestToFromXML.hs
@@ -0,0 +1,105 @@
+{-# LANGUAGE DeriveGeneric #-}
+{-# OPTIONS_GHC -fcontext-stack=50 #-}
+
+module Main where
+
+import Text.XML.ToFromXML
+
+import System.Exit
+import Data.Char
+import qualified Data.Map.Lazy as Map
+import qualified Data.IntMap as IntMap
+import qualified Data.Set as Set
+import Data.Array.IArray
+import Data.Complex
+import Data.Ratio
+import Text.Printf
+import System.FilePath
+
+testTest :: (Eq i,Eq e,Eq a,Ix i,Ord a,Show a,Show i,Read i,Show e,ToFromXML e,ToFromXML a) => (Int,Test a i e) -> IO Bool
+testTest (i,test) = do
+	putStrLn $ "\n-------------------------\nTest " ++ show i
+
+	let testfilename = "Test" ++ show i ++ ".xml"
+
+	writeToXMLFile testfilename test
+
+	test' <- readFromXMLFile testfilename
+
+	rc <- case test==test' of
+		True -> putStrLn "OK." >> return ExitSuccess
+		False -> do
+			putStrLn $ printf "/= ERROR!\nWRITTEN: %s\n/=\nREAD   : %s" (show test) (show test')
+			return $ ExitFailure 1
+	exitWith rc
+
+data Test a i e =
+	Test1 Int Char () |
+	Test2 { str::String, subtest::(Test a i e) } |
+	Test3 [(String,Int)] |
+	Test4 [Test a i e] |
+	Test5 |
+	Test6 (Float,Double,Bool) |
+	Test7 [Int] |
+	Test8 (Map.Map String (Test a i e)) |
+	Test9 (Maybe (Test a i e)) (Maybe Int) (Either (Test a i e) Char) (Either (Test a i e) Int) |
+	Test10 (Set.Set a) |
+	Test11 (Array i e) |
+	Test12 (Ratio Int) (Complex Double) |
+	Test13 (String,Int) |
+	Test14 (Int,Int) |
+	Test15 (IntMap.IntMap (Test () Int ())) |
+	Test16 [TestSel] |
+	Test17 { first::String, second::Int, third::Float } |
+	Test18 Int Char Bool String |
+	Test19 Int Char Bool String Int |
+	Test20 Int Char Bool (String,Char) Int Float |
+	Test21 Int Char Bool (String,Char,Int) Int Float Int Double Bool Char
+	deriving (Show,Eq,Generic)
+
+data TestSel = TestSel1 Int | TestSel2 Char | TestSel3 TestSel | TestSel4 (Test () Int ()) | TestSel5
+	deriving (Show,Eq,Generic)
+
+main = do
+	longstring <- readFile $ "test" </> "TestToFromXML.hs"
+	oks <- sequence $ map testTest $ zip [1..] ([
+		Test13 (longstring,0),
+		Test3 [(map chr [8..16],99)],
+		Test4 [
+			Test4 $
+				Test2 "  teststr  " (Test1 2 '\'' ()) :
+					map (\ i -> Test1 (0-i) (chr i) ()) [0..255],
+			Test3 [("<DATATYPE name=\"Test\">",100)],
+			Test3 [(map chr [0..255],99)],
+			Test13 ("abc",3),
+			Test14 (3,4),
+			Test5,
+			Test4 [],
+			Test3 [("",0)],
+			Test6 (pi,pi,True),
+			Test6 (1.2345678e+37,1.2345678e-250,False),
+			Test7 [1..10] ],
+		Test8 $ Map.fromList [("abc",Test4 []),("def",Test5),("ghi",Test7 [1,2,3])],
+		Test4 [ Test3 [("first",2)], Test6 (1.23,1.23456,False) ],
+		Test9 (Just $ Test7 [1,2,3]) Nothing (Left $ Test1 7 'v' ()) (Right 8),
+		Test10 (Set.fromList [10,27,-1,1,3,5,7,9]),
+		Test11 (listArray (10,12) [3.3,4.4,5.5]),
+		Test12 (27 % 8) (1.23 :+ (-3.45)),
+		Test15 $ IntMap.fromList $ zip [-2..] [Test5, Test7 [-2,-1,0], Test13 ("test15",666) ],
+		Test16 [
+			TestSel1 4,
+			TestSel2 'f',
+			TestSel3 $ TestSel3 $ TestSel3 $ TestSel1 9999,
+			TestSel4 $ Test16 [TestSel1 5, TestSel4 $ Test5, TestSel5 ],
+			TestSel5 ],
+		Test17 "abc" 123 3.14,
+		Test1 12 'c' (),
+		Test18 13 'd' False "test18",
+		Test19 13 'd' False "test19" 14,
+		Test20 13 'd' False ("test20",'a') 15 2.71,
+		Test21 13 'd' False ("test21",'b',3) 15 2.71 (-1) 3.1 True 'e'
+		] :: [Test Integer Int Float])
+	rc <- case all id oks of
+		True -> putStrLn "All tests OK." >> return ExitSuccess
+		False -> putStrLn "Some tests failed!" >> return (ExitFailure 1)
+	exitWith rc
diff --git a/test/test.xml b/test/test.xml
new file mode 100644
--- /dev/null
+++ b/test/test.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<CONSTRUCTOR name="Test">
+  <ARG-1 selector="str">abc</ARG-1>
+  <ARG-2 selector="something">
+    <PAIR>
+      <FIRST>42</FIRST>
+      <SECOND>z</SECOND>
+    </PAIR>
+  </ARG-2>
+</CONSTRUCTOR>
diff --git a/tofromxml.cabal b/tofromxml.cabal
new file mode 100644
--- /dev/null
+++ b/tofromxml.cabal
@@ -0,0 +1,33 @@
+name:                tofromxml
+version:             0.1.0.0
+synopsis:            Reading/writing Haskell data from/to XML
+description:         A library for reading/writing Haskell data from/to XML. Only prerequisite is that the data type derives Generic.
+license:             BSD3
+license-file:        LICENSE
+author:              Robert Reitmeier
+maintainer:          Robert Reitmeier <concat ["public"," a t ","thinking-machines","dot",".net"]>
+stability:           provisional
+copyright:           (c) 2014 Robert Reitmeier
+category:            XML
+build-type:          Simple
+cabal-version:       >=1.10
+extra-source-files:  test/Example.hs test/TestToFromXML.hs test/test.xml
+
+library
+  exposed-modules:   Text.XML.ToFromXML
+  other-extensions:  DeriveGeneric, DefaultSignatures, UndecidableInstances, ScopedTypeVariables, OverlappingInstances, TypeOperators, FlexibleContexts, FlexibleInstances
+  build-depends:     base >=4.7 && <4.8, bytestring >=0.10 && <0.11, hexpat-pickle >=0.6 && <0.7, hexpat >=0.20 && <0.21, containers >=0.5 && <0.6, array >=0.5 && <0.6
+  hs-source-dirs:    .
+  default-language:  Haskell2010
+  ghc-options:       -fcontext-stack=50
+
+Test-Suite test
+  type:              exitcode-stdio-1.0
+  main-is:           test/TestToFromXML.hs
+  build-depends:     base,tofromxml,array,containers,hexpat,hexpat-pickle,bytestring,filepath
+  default-language:  Haskell2010
+
+source-repository head
+  type:              git
+  location:          https://github.com/theoremprover/tofromxml.git
+  subdir:            work
