packages feed

libxslt-0.1: src/Text/XML/XSLT.hs

module Text.XML.XSLT
    ( Stylesheet
    , parseFile
    , parseFile_
    , applyStylesheet
    , saveResultToString
    , saveResultToString_
    , cleanupGlobals
    , freeStylesheet
    ) where

import Foreign.C
import Foreign
import Control.Monad

import qualified Data.ByteString as BS
import Data.ByteString (ByteString)

import qualified Text.XML.LibXML as XML
import qualified Text.XML.LibXML.Internals as XML
import Text.XML.LibXML (Document)

newtype Stylesheet = Stylesheet (ForeignPtr Stylesheet)

freeStylesheet :: Stylesheet -> IO ()
freeStylesheet (Stylesheet ptr) =
#if defined(__GLASGOW_HASKELL__)
  finalizeForeignPtr ptr
#else
  return ()
#endif


-- xsltStylesheetPtr xsltParseStylesheetFile(const xmlChar * filename)
foreign import ccall unsafe xsltParseStylesheetFile :: CString -> IO (Ptr Stylesheet)

parseFile :: FilePath -> IO Stylesheet
parseFile path
    = do mbSheet <- parseFile_ path
         case mbSheet of
           Nothing -> error $ "Text.XML.XSLT.parseFile: failed to parse input from: " ++ path
           Just sheet -> return sheet

parseFile_ :: FilePath -> IO (Maybe Stylesheet)
parseFile_ path
    = do ptr <- xsltParseStylesheetFile =<< newCString path
         if ptr == nullPtr
            then return Nothing
            else liftM Just $ mkFinalizedStylesheet ptr

-- xmlDocPtr xsltApplyStylesheet(xsltStylesheetPtr style, xmlDocPtr doc, const char ** params)
foreign import ccall unsafe xsltApplyStylesheet :: Ptr Stylesheet -> Ptr Document -> Ptr CString -> IO (Ptr Document)

-- FIXME: don't ignore the params
applyStylesheet :: Stylesheet -> Maybe Document -> [(ByteString,ByteString)] -> IO Document
applyStylesheet (Stylesheet stylesheet) mbDocument _params
    = withForeignPtr stylesheet $ \sheetptr ->
      withMbDoc mbDocument $ \docPtr ->
      do ptr <- xsltApplyStylesheet sheetptr docPtr nullPtr
         XML.mkFinalizedDocument ptr
    where withMbDoc Nothing x = x nullPtr
          withMbDoc (Just doc) x = XML.withDocument doc x

--int xsltSaveResultToString(xmlChar ** doc_txt_ptr, 
--                           int * doc_txt_len, 
--                            xmlDocPtr result, 
--                                       xsltStylesheetPtr style)
foreign import ccall unsafe xsltSaveResultToString
    :: Ptr CString -> Ptr CInt -> Ptr Document -> Ptr Stylesheet -> IO CInt

saveResultToString :: Document -> Stylesheet -> IO ByteString
saveResultToString doc stylesheet
    = do mbStr <- saveResultToString_ doc stylesheet
         case mbStr of
           Nothing -> error "Text.XML.XSLT.saveResultToString: failed to save result"
           Just str -> return str

saveResultToString_ :: Document -> Stylesheet -> IO (Maybe ByteString)
saveResultToString_ doc (Stylesheet sheet)
    = withForeignPtr sheet $ \sheetPtr ->
      XML.withDocument doc $ \docPtr ->
      alloca $ \strPtr ->
      alloca $ \lenPtr ->
      do ret <- xsltSaveResultToString strPtr lenPtr docPtr sheetPtr
         case ret of
           (-1) -> return Nothing
           _    -> do cstr <- peek strPtr
                      str <- BS.packCString cstr
                      return $! Just $! str

foreign import ccall unsafe "xsltCleanupGlobals" cleanupGlobals :: IO ()

foreign import ccall unsafe "&xsltFreeStylesheet" xsltFreeStylesheet :: FunPtr (Ptr Stylesheet -> IO ())

mkFinalizedStylesheet :: Ptr Stylesheet -> IO Stylesheet
mkFinalizedStylesheet = liftM Stylesheet . newForeignPtr xsltFreeStylesheet