"""functions to add css to html"""
import os
import re
import sys
import lxml.etree as etree
import filing
from nitpo import Nitpo
from sheets import Sheets
from xpaths import Xpaths
import docing
class Inces(Nitpo):
def __init__(self, do_verbose=False):
super().__init__()
self.sheets = Sheets()
self.do_verbose = do_verbose
self.css_doc = self.load_css()
# # parse for variable substitution
self.x = Xpaths()
self.var = None
self.prefix = None
self.doc = None
def trans_fufi(self, fufi, locs=None):
"""external callers transform a fufi"""
if not os.path.isfile(fufi):
if self.do_verbose:
print(f"inces does not see {fufi}", file=sys.stderr)
return None
if not fufi.endswith('.xhtml'):
print("inces needs .xhtml input",
file=sys.stderr)
doc = filing.parse_lax(fufi)
# # if we run from the comand line, do don’t have the locs
locs = self.read_locs()
out_doc = self.trans_doc(doc, locs)
out_fufi = fufi[:-6] + '.html'
string = docing.show(out_doc)
has_it_been_written = filing.srite(out_fufi, string,
do_verbose=self.do_verbose)
return has_it_been_written
def trans_doc(self, doc, locs):
"""external callers by doc"""
self.prefix = '{' + self.get_ns(doc) + '}'
self.remove_css_link(doc)
eles = self.x.run(doc, '//*')
for ele in eles:
self.trans_ele(ele, locs)
return doc
def remove_css_link(self, doc):
xp = "/h:html/h:head/h:link[@rel='stylesheet']"
link_ele = self.x.none_or_one(doc, xp)
if link_ele is None:
return False
link_ele.getparent().remove(link_ele)
return True
def get_ns(self, doc):
"""there should be a better way to do this"""
root_ele = doc.getroot()
tag = root_ele.tag
tag = tag[1:]
ns = tag.partition('}')[0]
self.ns_len = len(ns)
self.const['nsmap']['h'] = ns
## makes is available to self.x
self.x.const['nsmap'] = self.const['nsmap']
return ns
def trans_ele(self, ele, locs):
if 'class' in ele.attrib:
the_class = '.' + ele.attrib['class']
if the_class in locs['class']:
self.add_style(ele, locs['class'][the_class])
if 'id' in ele.attrib:
the_id = '#' + ele.attrib['id']
if the_id in locs['id']:
self.add_style(ele, locs['id'][the_id])
## the should be a better way to get the local name
name = ele.tag.replace(self.prefix, '')
if name in locs['name']:
self.add_style(ele, locs['name'][name])
def add_style(self, ele, string):
if 'style' in ele.attrib:
ele.attrib['style'] += ' ' + string
return
ele.attrib['style'] = string
def get_res(self):
res = {}
## simple class
res['class'] = re.compile(r'\.[a-z_]+$')
res['id'] = re.compile(r'#[a-z_]+$')
res['name'] = re.compile(r'[a-z]([a-z]+|[0-9])$')
return res
def get_var(self):
xp = '/n:rules/n:var'
var_eles = self.x.run(self.css_doc, xp)
var = {}
for var_ele in var_eles:
if 'name' not in var_ele.attrib:
err = docing.show(var_ele)
print("inces: no name for variable {err}",
file=sys.stderr)
continue
if 'value' not in var_ele.attrib:
err = docing.show(var_ele)
print("inces: no value for variable {err}",
file=sys.stderr)
continue
var[var_ele.attrib['name']] = var_ele.attrib['value']
return var
def read_locs(self):
"""externel caller gets the locs"""
# # populate self.css_doc
self.css_doc = self.load_css()
# # variable names set in css.xml (var= vs lit=)
self.var = self.get_var()
# # regular expressions to parse element
self.res = self.get_res()
# # we don't use /n:rules/n:media, should be obsoleted anyway
xp = '/n:rules/n:rule/n:loc'
loc_eles = self.x.run(self.css_doc, xp)
locs = {}
# # make sure these always exist
locs['id'] = {}
locs['class'] = {}
locs['name'] = {}
for loc_ele in loc_eles:
loc = loc_ele.text
found = False
for name in self.res:
if self.res[name].match(loc):
found = True
rules = self.get_rules(loc)
locs[name][loc] = rules
break
if not found and self.do_verbose:
print(f"inces can not implement '{loc}'")
continue
return locs
def load_css(self):
if not self.has_conf('files', 'css_xml'):
print("inces needs Ф[files][css_xml]")
quit()
css_fufi = self.conf['files']['css_xml']
css_doc = filing.parse_lax(css_fufi)
return css_doc
def get_rules(self, loc):
xp = f"/n:rules/n:rule/n:loc[text()='{loc}']"
rule_eles = self.x.run(self.css_doc, xp)
if len(rule_eles) == 0:
if self.do_verbose:
print(f"inces can not find a rule for {loc}")
return None
xp = '../n:prop'
rules = {}
for rule_ele in rule_eles:
prop_eles = self.x.run(rule_ele, xp)
for prop_ele in prop_eles:
if 'name' not in prop_ele.attrib:
err = docing.show(prop_ele)
print("inces: no name for variable {err}",
file=sys.stderr)
continue
name = prop_ele.attrib['name']
if name in rules:
if self.do_verbose:
print(f"inces find duplicate rule {name} in {loc}")
else:
rules[name] = ''
# # normal case
if 'lit' in prop_ele.attrib:
rules[name] += prop_ele.attrib['lit']
continue
# # no @lit, no @var
if 'var' not in prop_ele.attrib:
if self.do_verbose:
print("inces: no lit= and no var= in {name} at {loc}")
continue
# # var case
var = prop_ele.attrib['var']
if var not in self.var:
if self.do_verbose:
print("inces sees refer error for {name} in {loc}")
continue
rules[name] += self.var[var]
out = self.format_rules(rules)
return out
def format_rules(self, rules):
out = ''
for name in rules:
out += name + ': ' + rules[name] + '; '
out = out[:-2]
return out