Managed to answer someone’s question on haskell-cafe about parsing semi-structured text with Parsec:

S. Doaitse Swierstra pointed out that the Data.List.Grouping package may be more appropriate here.

https://gist.github.com/carlohamalainen/5087207

{-# LANGUAGE FlexibleContexts #-}

import Text.Parsec
import Control.Applicative hiding ((<|>),many)

-- Example input:

{-
top 1:

some text ... bla

top 2:

more text ... bla bla

-}

data Top = Top String deriving (Show)
data Content = Content [String] deriving (Show)
data Section = Section Top Content deriving (Show)

headline = do
    t <- many1 (noneOf ":\n")
    char ':'
    newline

    return $ Top t

contentLine = do
    x <- many (noneOf ":\n")
    newline
    return x

content = do
    line <- optionMaybe (try contentLine)

    case line of Just x -> do xs <- content
                              return (x:xs)
                 _      -> return []

section = do
    h <- headline
    c <- Content <$> content
    return $ Section h c

main = do
    x <- readFile "simple.txt"
    print $ parse (many section) "" x