parsestar-1.4: Data/STAR/Path.hs
{-# LANGUAGE OverloadedStrings, ScopedTypeVariables #-}
module Data.STAR.Path((./), (/<>), (->//)
,starBlocks
,filterP
,blocksByName
,entriesByName
,entryValue
,allEntriesByName
,flattenEntries)
where
import Prelude hiding(String)
import Data.STAR.Type
-- ^ This module presents a convenient, compositional interface for filtering
-- Example use:
-- > test1 :: STAR -> [String]
-- > test1 = blocksByName "" ./ entriesByName "chemical_shifts" ./ entryValue
-- Another example:
-- > test2 :: STAR -> [String]
-- > test2 = starBlocks ./ entries ./ entryValue
-- | Path separator - serves as general function composition operator.
infixr 3 ./
(./) :: (a -> [a1]) -> (a1 -> [b]) -> a -> [b]
f ./ g = concatMap g . f
-- | Path predicate operator - serves as general function composition operator.
(/<>) :: (a -> b) -> (b -> Bool) -> a -> [b]
f /<> g = filterP g . f
infixl 1 ->//
-- | Applies a path to a set of elements (not just a document, or single entry.)
elts ->// path = concatMap path elts
starBlocks :: STAR -> [STARBlock]
starBlocks (STAR blocks) = blocks
filterP :: (t -> Bool) -> t -> [t]
f `filterP` x = [x | f x]
-- STAR selectors are typed, and always return a list of results
-- (in order to be conveniently used with concatMap and composition.)
-- | Selects all block matching a given name or GLOBAL block for empty string.
-- TODO: Regex for names?
blocksByName :: String -> STAR -> [STAREntry]
blocksByName name = starBlocks ./ filterP matches ./ entries
where
matches (Global _) = name ==""
matches (Data { dataKey = key }) = key == name
-- | Filter entries with a given name. Expand loops if necessary.
entriesByName :: String -> STAREntry -> [STAREntry]
entriesByName name es = matches es
where
matches (Loop table) = concatMap (concatMap matches) table
matches e = [e | key e == name]
-- | Extracts a string value from a flat entry.
entryValue :: STAREntry -> [String]
entryValue (Loop _) = []
entryValue (Frame _ _) = []
entryValue e = [value e]
-- | Expands a possibly complex entry into a list of flat entries.
flattenEntries :: STAREntry -> [STAREntry]
flattenEntries (Loop l) = concat l
flattenEntries (Frame _ l) = l
flattenEntries e = [e]
-- | Find all flat entries with a given name, and return their values.
allEntriesByName name = starBlocks ./ entries ./ flattenEntries ./ entriesByName name ./ entryValue