{ "cells": [ { "cell_type": "code", "execution_count": 1, "id": "d0c84aa5", "metadata": {}, "outputs": [], "source": [ "#| default_exp xml" ] }, { "cell_type": "markdown", "id": "61bf8203", "metadata": {}, "source": [ "# XML\n", "\n", "> Concise generation of XML." ] }, { "cell_type": "code", "execution_count": 2, "id": "55944805", "metadata": {}, "outputs": [], "source": [ "#| export\n", "from fastcore.utils import *\n", "\n", "from dataclasses import dataclass, asdict\n", "import types\n", "from functools import partial\n", "from html import escape" ] }, { "cell_type": "code", "execution_count": 3, "id": "42d18e5c", "metadata": {}, "outputs": [], "source": [ "from IPython.display import Markdown\n", "from pprint import pprint" ] }, { "cell_type": "code", "execution_count": 4, "id": "4dbb9a59", "metadata": {}, "outputs": [], "source": [ "#| export\n", "def _attrmap(o):\n", " o = dict(htmlClass='class', cls='class', klass='class', fr='for', htmlFor='for').get(o, o)\n", " return o.lstrip('_').replace('_', '-')" ] }, { "cell_type": "code", "execution_count": 5, "id": "149067dd", "metadata": {}, "outputs": [], "source": [ "#|export\n", "class XT(list): pass" ] }, { "cell_type": "code", "execution_count": 6, "id": "06718948", "metadata": {}, "outputs": [], "source": [ "#| export\n", "def xt(tag:str, *c, **kw):\n", " \"Create an XML tag structure `[tag,children,attrs]` for `toxml()`\"\n", " if len(c)==1 and isinstance(c[0], types.GeneratorType): c = tuple(c[0])\n", " kw = {_attrmap(k):str(v) for k,v in kw.items() if v is not None}\n", " return XT([tag.lower(),c,kw])" ] }, { "cell_type": "code", "execution_count": 7, "id": "45489975", "metadata": {}, "outputs": [], "source": [ "#| export\n", "_g = globals()\n", "_all_ = ['Html', 'Head', 'Title', 'Meta', 'Link', 'Style', 'Body', 'Pre', 'Code',\n", " 'Div', 'Span', 'P', 'H1', 'H2', 'H3', 'H4', 'H5', 'H6', 'Strong', 'Em', 'B',\n", " 'I', 'U', 'S', 'Strike', 'Sub', 'Sup', 'Hr', 'Br', 'Img', 'A', 'Link', 'Nav',\n", " 'Ul', 'Ol', 'Li', 'Dl', 'Dt', 'Dd', 'Table', 'Thead', 'Tbody', 'Tfoot', 'Tr',\n", " 'Th', 'Td', 'Caption', 'Col', 'Colgroup', 'Form', 'Input', 'Textarea',\n", " 'Button', 'Select', 'Option', 'Label', 'Fieldset', 'Legend', 'Details',\n", " 'Summary', 'Main', 'Header', 'Footer', 'Section', 'Article', 'Aside', 'Figure',\n", " 'Figcaption', 'Mark', 'Small', 'Iframe', 'Object', 'Embed', 'Param', 'Video',\n", " 'Audio', 'Source', 'Canvas', 'Svg', 'Math', 'Script', 'Noscript', 'Template', 'Slot']\n", "\n", "for o in _all_: _g[o] = partial(xt, o.lower())" ] }, { "cell_type": "markdown", "id": "732e44ab", "metadata": {}, "source": [ "The main HTML tags are exported as `xt` partials.\n", "\n", "Attributes are passed as keywords. Use 'klass' and 'fr' instead of 'class' and 'for', to avoid Python reserved word clashes." ] }, { "cell_type": "code", "execution_count": 8, "id": "9a8b4ddb", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "['html',\n", " (['head', (['title', ('Some page',), {}],), {}],\n", " ['body',\n", " (['div',\n", " (['p', ('Some text',), {}],\n", " ['input', (), {'name': 'me'}],\n", " ['img', (), {'src': 'filename'}]),\n", " {'class': 'myclass'}],),\n", " {}]),\n", " {}]\n" ] } ], "source": [ "samp = Html(\n", " Head(Title('Some page')),\n", " Body(Div(P('Some text'), Input(name='me'), Img(src=\"filename\"), klass='myclass'))\n", ")\n", "pprint(samp)" ] }, { "cell_type": "code", "execution_count": 9, "id": "c7de63a4", "metadata": {}, "outputs": [], "source": [ "#| export\n", "voids = set('area base br col command embed hr img input keygen link meta param source track wbr'.split())" ] }, { "cell_type": "code", "execution_count": 10, "id": "b89d088a", "metadata": {}, "outputs": [], "source": [ "#| export\n", "def to_xml(elm, lvl=0):\n", " \"Convert `xt` element tree into an XML string\"\n", " if isinstance(elm, tuple): return '\\n'.join(to_xml(o) for o in elm)\n", " if hasattr(elm, '__xt__'): elm = elm.__xt__()\n", " sp = ' ' * lvl\n", " if not isinstance(elm, list):\n", " if isinstance(elm, str): elm = escape(elm)\n", " return f'{elm}\\n'\n", "\n", " tag,cs,attrs = elm\n", " stag = tag\n", " if attrs:\n", " sattrs = (f'{k}=\"{escape(str(v), quote=False)}\"' for k,v in attrs.items())\n", " stag += ' ' + ' '.join(sattrs)\n", " \n", " cltag = '' if tag in voids else f'{tag}>'\n", " if not cs: return f'{sp}<{stag}>{cltag}\\n'\n", " res = f'{sp}<{stag}>\\n'\n", " res += ''.join(to_xml(c, lvl=lvl+2) for c in cs)\n", " if tag not in voids: res += f'{sp}{cltag}\\n'\n", " return res" ] }, { "cell_type": "code", "execution_count": 11, "id": "d3d23c48", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", "
\n", "\n", "Some text\n", "
\n", " \n", "\n",
"{escape(to_xml(s))}\n",
"
\"\"\"\n",
"\n",
"XT._repr_html_ = showtags"
]
},
{
"cell_type": "markdown",
"id": "df973d4e",
"metadata": {},
"source": [
"# Export -"
]
},
{
"cell_type": "code",
"execution_count": 17,
"id": "ad32b076",
"metadata": {},
"outputs": [],
"source": [
"#|hide\n",
"import nbdev; nbdev.nbdev_export()"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "84fe290c",
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.11.8"
}
},
"nbformat": 4,
"nbformat_minor": 5
}