pangraph-0.2.0: src/Pangraph/Gml/Writer.hs
{-# LANGUAGE OverloadedStrings #-}
{-|
Module : Pangraph.Gml.Writer
Description : Functions for writing gml files
Functions for writing gml files. Follows the gml specification at
<http://www.fim.uni-passau.de/fileadmin/files/lehrstuhl/brandenburg/projekte/gml/gml-technical-report.pdf>
execpt for two cases:
1. all produced 'ByteString's are encoded in UTF8 instead of ASCII,
2. the line length limit is ignored.
-}
module Pangraph.Gml.Writer (writeGml, pangraphToGml, write, encodeStrings) where
import HTMLEntities.Text (text)
import Data.ByteString (ByteString, concat)
import Data.ByteString.Char8 (unpack, pack)
import Data.Text.Encoding (encodeUtf8, decodeUtf8)
import Prelude hiding (concat)
import Pangraph
import Pangraph.Gml.Ast
-- | Serializes a Pangraph into a GML file.
write :: Pangraph -> ByteString
write graph = let
gml = pangraphToGml graph
Just bs = writeGml gml
in bs
-- | Converts a 'Pangraph' into a 'Gml' syntax tree.
-- Automatically encodes special characters in strings.
pangraphToGml :: Pangraph -> Gml ByteString
pangraphToGml graph = let
vertices = vertexList graph
edges = edgeList graph
gmlVertices = map gmlVertex vertices
gmlEdges = map gmlEdge edges
in encodeStrings (Object [("graph", Object (gmlVertices ++ gmlEdges))])
-- | Encodes the string values in a 'Gml' syntax tree.
encodeStrings :: Gml ByteString -> Gml ByteString
encodeStrings = mapStrings (encodeUtf8 . text . decodeUtf8)
gmlVertex :: Vertex -> (ByteString, Gml ByteString)
gmlVertex vertex = let
vId = read (unpack (vertexID vertex))
filteredAttrs = filter (\(key, _) -> key /= "id") (vertexAttributes vertex)
attrs = map (\(x, y) -> (x, String y)) filteredAttrs
in ("node", Object (("id", Integer vId):attrs))
gmlEdge :: Edge -> (ByteString, Gml ByteString)
gmlEdge edge = let
(source, target) = edgeEndpoints edge
sId = read (unpack source)
tId = read (unpack target)
filteredAttrs = filter (\(key, _) -> (key `notElem` ["source", "target"]))
(edgeAttributes edge)
attrs = map (\(x, y) -> (x, String y)) filteredAttrs
in ("edge", Object (("source", Integer sId):("target", Integer tId):attrs))
-- | Serializes a 'Gml' syntax tree into a bytestring.
-- Produces 'Nothing' for all values except 'Object' since a gml file
-- must contain at least one top level object to hold all values.
writeGml :: Gml ByteString -> Maybe ByteString
writeGml (Object values) = Just $ concat (
(map (\(key, value) -> concat [key, " ", writeGml' value]) values))
writeGml _ = Nothing
writeGml' :: Gml ByteString -> ByteString
writeGml' (Object values) = concat ( ["["] ++
(map (\(key, value) -> concat [" ", key, " ", writeGml' value]) values) ++ ["]"])
writeGml' (String s) = concat ["\"", s , "\""]
writeGml' (Float d) = pack (show d)
writeGml' (Integer i) = pack (show i)