#!/usr/bin/env python # coding: utf-8 # In[1]: #| default_exp xml # # XML # # > Concise generation of XML. # In[2]: #| export from fastcore.utils import * from dataclasses import dataclass, asdict import types from functools import partial from html import escape # In[3]: from IPython.display import Markdown from pprint import pprint # In[4]: #| export def _attrmap(o): o = dict(htmlClass='class', cls='class', klass='class', fr='for', htmlFor='for').get(o, o) return o.lstrip('_').replace('_', '-') # In[5]: #|export class XT(list): pass # In[6]: #| export def xt(tag:str, *c, **kw): "Create an XML tag structure `[tag,children,attrs]` for `toxml()`" if len(c)==1 and isinstance(c[0], types.GeneratorType): c = tuple(c[0]) kw = {_attrmap(k):str(v) for k,v in kw.items() if v is not None} return XT([tag.lower(),c,kw]) # In[7]: #| export _g = globals() _all_ = ['Html', 'Head', 'Title', 'Meta', 'Link', 'Style', 'Body', 'Pre', 'Code', 'Div', 'Span', 'P', 'H1', 'H2', 'H3', 'H4', 'H5', 'H6', 'Strong', 'Em', 'B', 'I', 'U', 'S', 'Strike', 'Sub', 'Sup', 'Hr', 'Br', 'Img', 'A', 'Link', 'Nav', 'Ul', 'Ol', 'Li', 'Dl', 'Dt', 'Dd', 'Table', 'Thead', 'Tbody', 'Tfoot', 'Tr', 'Th', 'Td', 'Caption', 'Col', 'Colgroup', 'Form', 'Input', 'Textarea', 'Button', 'Select', 'Option', 'Label', 'Fieldset', 'Legend', 'Details', 'Summary', 'Main', 'Header', 'Footer', 'Section', 'Article', 'Aside', 'Figure', 'Figcaption', 'Mark', 'Small', 'Iframe', 'Object', 'Embed', 'Param', 'Video', 'Audio', 'Source', 'Canvas', 'Svg', 'Math', 'Script', 'Noscript', 'Template', 'Slot'] for o in _all_: _g[o] = partial(xt, o.lower()) # The main HTML tags are exported as `xt` partials. # # Attributes are passed as keywords. Use 'klass' and 'fr' instead of 'class' and 'for', to avoid Python reserved word clashes. # In[8]: samp = Html( Head(Title('Some page')), Body(Div(P('Some text'), Input(name='me'), Img(src="filename"), klass='myclass')) ) pprint(samp) # In[9]: #| export voids = set('area base br col command embed hr img input keygen link meta param source track wbr'.split()) # In[10]: #| export def to_xml(elm, lvl=0): "Convert `xt` element tree into an XML string" if isinstance(elm, tuple): return '\n'.join(to_xml(o) for o in elm) if hasattr(elm, '__xt__'): elm = elm.__xt__() sp = ' ' * lvl if not isinstance(elm, list): if isinstance(elm, str): elm = escape(elm) return f'{elm}\n' tag,cs,attrs = elm stag = tag if attrs: sattrs = (f'{k}="{escape(str(v), quote=False)}"' for k,v in attrs.items()) stag += ' ' + ' '.join(sattrs) cltag = '' if tag in voids else f'' if not cs: return f'{sp}<{stag}>{cltag}\n' res = f'{sp}<{stag}>\n' res += ''.join(to_xml(c, lvl=lvl+2) for c in cs) if tag not in voids: res += f'{sp}{cltag}\n' return res # In[11]: print(to_xml(samp)) # In[12]: #| export def highlight(s, lang='html'): "Markdown to syntax-highlight `s` in language `lang`" return f'```{lang}\n{to_xml(s)}\n```' # In[16]: #| export def showtags(s): return f"""
{escape(to_xml(s))}
""" XT._repr_html_ = showtags # # Export - # In[17]: #|hide import nbdev; nbdev.nbdev_export() # In[ ]: