RosettaCodeData/Task/Create-an-HTML-table/Python/create-an-html-table-3.py

118 lines
2.8 KiB
Python

from functools import (reduce)
import itertools
import random
# HTML RENDERING ----------------------------------------
# treeHTML :: tree
# {tag :: String, text :: String, kvs :: Dict}
# -> HTML String
def treeHTML(tree):
return foldTree(
lambda x: lambda xs: (
f"<{x['tag'] + attribString(x)}>" + (
str(x['text']) if 'text' in x else '\n'
) + ''.join(xs) + f"</{x['tag']}>\n"
)
)(tree)
# attribString :: Dict -> String
def attribString(dct):
kvs = dct['kvs'] if 'kvs' in dct else None
return ' ' + reduce(
lambda a, k: a + k + '="' + kvs[k] + '" ',
kvs.keys(), ''
).strip() if kvs else ''
# HTML TABLE FROM GENERATED DATA ------------------------
def main():
# Number of columns and rows to generate.
n = 3
# Table details -------------------------------------
strCaption = 'Table generated with Python'
colNames = take(n)(enumFrom('A'))
dataRows = map(
lambda x: (x, map(
lambda _: random.randint(100, 9999),
colNames
)), take(n)(enumFrom(1)))
tableStyle = {
'style': "width:25%; border:2px solid silver;"
}
trStyle = {
'style': "border:1px solid silver;text-align:right;"
}
# TREE STRUCTURE OF TABLE ---------------------------
tableTree = Node({'tag': 'table', 'kvs': tableStyle})([
Node({
'tag': 'caption',
'text': strCaption
})([]),
# HEADER ROW --------------------------------
(Node({'tag': 'tr'})(
Node({
'tag': 'th',
'kvs': {'style': 'text-align:right;'},
'text': k
})([]) for k in ([''] + colNames)
))
] +
# DATA ROWS ---------------------------------
list(Node({'tag': 'tr', 'kvs': trStyle})(
[Node({'tag': 'th', 'text': tpl[0]})([])] +
list(Node(
{'tag': 'td', 'text': str(v)})([]) for v in tpl[1]
)
) for tpl in dataRows)
)
print(
treeHTML(tableTree)
# dataRows
)
# GENERIC -----------------------------------------------
# Node :: a -> [Tree a] -> Tree a
def Node(v):
return lambda xs: {'type': 'Node', 'root': v, 'nest': xs}
# enumFrom :: Enum a => a -> [a]
def enumFrom(x):
return itertools.count(x) if type(x) is int else (
map(chr, itertools.count(ord(x)))
)
# foldTree :: (a -> [b] -> b) -> Tree a -> b
def foldTree(f):
def go(node):
return f(node['root'])(
list(map(go, node['nest']))
)
return lambda tree: go(tree)
# take :: Int -> [a] -> [a]
# take :: Int -> String -> String
def take(n):
return lambda xs: (
xs[0:n]
if isinstance(xs, list)
else list(itertools.islice(xs, n))
)
if __name__ == '__main__':
main()