XML

Concise generation of XML.
from IPython.display import Markdown
from pprint import pprint

from fastcore.test import test_eq, test_ne

FT functions


source

attrmap


def attrmap(
    o
):

source

valmap


def valmap(
    o
):

source

FT


def FT(
    tag:str, cs:tuple, attrs:dict=None, void_:bool=False, kwargs:VAR_KEYWORD
):

A ‘Fast Tag’ structure, containing tag,children,and attrs


source

ft


def ft(
    tag:str, c:VAR_POSITIONAL, void_:bool=False, attrmap:callable=<function attrmap at 0x7fac34d0bc70>,
    valmap:callable=<function valmap at 0x7fac34d0bd00>, ft_cls:type=<class '__main__.FT'>, kw:VAR_KEYWORD
):

Create an FT structure for to_xml()

The main HTML tags are exported as ft partials.

Attributes are passed as keywords. Use ‘klass’ and ‘fr’ instead of ‘class’ and ‘for’, to avoid Python reserved word clashes.


source

Html


def Html(
    c:VAR_POSITIONAL, doctype:bool=True, kwargs:VAR_KEYWORD
)->FT:

An HTML tag, optionally preceeded by !DOCTYPE HTML

samp = Html(
    Head(Title('Some page')),
    Body(Div('Some text\nanother line', (Input(name="jph's"), Img(src="filename", data=1)),
             cls=['myclass', 'another'],
             style={'padding':1, 'margin':2}))
)
pprint(samp)
(!doctype((),{'html': True}),
 html((head((title(('Some page',),{}),),{}), body((div(('Some text\nanother line', input((),{'name': "jph's"}), img((),{'src': 'filename', 'data': 1})),{'class': 'myclass another', 'style': 'padding:1; margin:2'}),),{})),{}))
elem = P('Some text', id="myid")
print(elem.tag)
print(elem.children)
print(elem.attrs)
p
('Some text',)
{'id': 'myid'}

You can get and set attrs directly:

elem.id = 'newid'
print(elem.id, elem.get('id'), elem.get('foo', 'missing'))
elem
newid newid missing
p(('Some text',),{'id': 'newid'})

source

Safe


def Safe(
    args:VAR_POSITIONAL, kwargs:VAR_KEYWORD
):

str(object=’’) -> str str(bytes_or_buffer[, encoding[, errors]]) -> str

Create a new string object from the given object. If encoding or errors is specified, then the object must expose a data buffer that will be decoded using the given encoding and error handler. Otherwise, returns the result of object.__str__() (if defined) or repr(object). encoding defaults to sys.getdefaultencoding(). errors defaults to ‘strict’.

Conversion to XML/HTML


source

to_xml


def to_xml(
    elm, lvl:int=0, indent:bool=True, do_escape:bool=True
):

Convert ft element tree into an XML string


source

FT.__html__


def __html__(
    
):
to_xml(Div("<script>alert('XSS')</script>"), do_escape=True)
"<div>&lt;script&gt;alert('XSS')&lt;/script&gt;</div>\n"
h = to_xml(samp, do_escape=False)
print(h)
<!doctype html>
<html>
  <head>
    <title>Some page</title>
  </head>
  <body>
    <div class="myclass another" style="padding:1; margin:2">
Some text
another line      <input name="jph's">
<img src="filename" data="1">    </div>
  </body>
</html>
c = I('hello')
print(c)
<i>hello</i>
c
hello
class PageTitle:
    def __ft__(self): return H1("Hello")

class HomePage:
    def __ft__(self): return Div(PageTitle(), Div('hello'))

h = to_xml(Div(HomePage()))
expected_output = """<div>
  <div>
    <h1>Hello</h1>
    <div>hello</div>
  </div>
</div>
"""
assert h == expected_output
print(h)
<div>
  <div>
    <h1>Hello</h1>
    <div>hello</div>
  </div>
</div>
h = to_xml(samp, indent=False)
print(h)
<!doctype html><html><head><title>Some page</title></head><body><div class="myclass another" style="padding:1; margin:2">Some text
another line<input name="jph's"><img src="filename" data="1"></div></body></html>

Interoperability both directions with Django and Jinja using the html() protocol:

def _esc(s): return s.__html__() if hasattr(s, '__html__') else Safe(escape(s))

r = Safe('<b>Hello from Django</b>')
print(to_xml(Div(r)))
print(_esc(Div(P('Hello from fastcore <3'))))
<div><b>Hello from Django</b></div>

<div><p>Hello from fastcore &lt;3</p></div>

FT attributes are rendered with to_xml:

print(to_xml(P('hi', value=Div('ho'))))
<p value="<div>ho</div>">hi</p>

FT components also stringify with to_xml:

print(Div('ho'))
<div>ho</div>

source

FT.__hash__


def __hash__(
    
):

Return hash(self).


source

FT.__eq__


def __eq__(
    other
):

Return self==value.

FT object equality and hashing is based on tag, attrs, and children.

test_eq(Div('hello', id='x'), Div('hello', id='x'))
test_ne(Div('hello'), Div('goodbye'))
test_ne(Div('hello', id='a'), Div('hello', id='b'))
test_ne(P('hello'), Div('hello'))

test_eq(hash(Div('hello', id='x')), hash(Div('hello', id='x')))
assert hash(Div('hello')), hash(Div('goodbye'))

Display


source

highlight


def highlight(
    s, lang:str='html'
):

Markdown to syntax-highlight s in language lang


source

showtags


def showtags(
    s
):

You can also reorder the children to come after the attrs, if you use this alternative syntax for FT where the children are in a second pair of () (behind the scenes this is because FT implements __call__ to add children).

hl_md(
Body(klass='myclass')(
    Div(style='padding:3px')(
        'Some text 1<2',
        I(spurious=True)('in italics'),
        Input(name='me'),
        Img(src="filename", data=1)
    )
))
<body class="myclass">
  <div style="padding:3px">
Some text 1&lt;2<i spurious>in italics</i>    <input name="me">
<img src="filename" data="1">  </div>
</body>

source

getattr


def __getattr__(
    tag
):