Skip to content

Commit

Permalink
fixes #626
Browse files Browse the repository at this point in the history
  • Loading branch information
jph00 committed Sep 14, 2024
1 parent 950edb4 commit a8e1c7e
Show file tree
Hide file tree
Showing 5 changed files with 248 additions and 94 deletions.
2 changes: 1 addition & 1 deletion fastcore/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = "1.7.7"
__version__ = "1.7.8"
1 change: 1 addition & 0 deletions fastcore/_modidx.py
Original file line number Diff line number Diff line change
Expand Up @@ -599,6 +599,7 @@
'fastcore.xml.__getattr__': ('xml.html#__getattr__', 'fastcore/xml.py'),
'fastcore.xml._escape': ('xml.html#_escape', 'fastcore/xml.py'),
'fastcore.xml._flatten_tuple': ('xml.html#_flatten_tuple', 'fastcore/xml.py'),
'fastcore.xml._is_whitespace_significant': ('xml.html#_is_whitespace_significant', 'fastcore/xml.py'),
'fastcore.xml._noescape': ('xml.html#_noescape', 'fastcore/xml.py'),
'fastcore.xml._preproc': ('xml.html#_preproc', 'fastcore/xml.py'),
'fastcore.xml._to_attr': ('xml.html#_to_attr', 'fastcore/xml.py'),
Expand Down
61 changes: 41 additions & 20 deletions fastcore/xml.py
Original file line number Diff line number Diff line change
Expand Up @@ -118,8 +118,6 @@ def __html__(self): return self

# %% ../nbs/11_xml.ipynb
def _escape(s): return '' if s is None else s.__html__() if hasattr(s, '__html__') else escape(s) if isinstance(s, str) else s

# %% ../nbs/11_xml.ipynb
def _noescape(s): return '' if s is None else s.__html__() if hasattr(s, '__html__') else s

# %% ../nbs/11_xml.ipynb
Expand All @@ -137,34 +135,57 @@ def _to_attr(k,v):
return f'{k}={qt}{v}{qt}'

# %% ../nbs/11_xml.ipynb
def _to_xml(elm, lvl, indent, do_escape):
_block_tags = {'div', 'p', 'ul', 'ol', 'li', 'table', 'thead', 'tbody', 'tfoot',
'html', 'head', 'body', 'meta', '!doctype', 'input', 'script', 'link', 'style',
'tr', 'th', 'td', 'section', 'article', 'nav', 'aside', 'header',
'footer', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'blockquote'}
_inline_tags = {'a', 'span', 'b', 'i', 'u', 'em', 'strong', 'img', 'br', 'small',
'big', 'sub', 'sup', 'label', 'input', 'select', 'option'}

def _is_whitespace_significant(elm):
return elm.tag in {'pre', 'code', 'textarea', 'script'} or elm.get('contenteditable') == 'true'

# %% ../nbs/11_xml.ipynb
def _to_xml(elm, lvl=0, indent=True, do_escape=True):
"Convert `FT` element tree into an XML string"
esc_fn = _escape if do_escape else _noescape
nl = '\n'
if not indent: lvl,nl = 0,''
if elm is None: return ''
if hasattr(elm, '__ft__'): elm = elm.__ft__()
if isinstance(elm, tuple): return f'{nl}'.join(_to_xml(o, lvl=lvl, indent=indent, do_escape=do_escape) for o in elm)
if isinstance(elm, tuple):
return ''.join(_to_xml(o, lvl=lvl, indent=indent, do_escape=do_escape) for o in elm)
if isinstance(elm, bytes): return elm.decode('utf-8')
sp = ' ' * lvl
if not isinstance(elm, FT): return f'{esc_fn(elm)}{nl}'
if not isinstance(elm, FT): return f'{esc_fn(elm)}'

tag, cs, attrs = elm.list
is_void = getattr(elm, 'void_', False)
is_block = tag in _block_tags
if _is_whitespace_significant(elm): indent = False

sp,nl = (' ' * lvl,'\n') if indent and is_block else ('','')
nl_end = nl

tag,cs,attrs = elm.list
stag = tag
if attrs:
sattrs = (_to_attr(k,v) for k,v in attrs.items())
stag += ' ' + ' '.join(sattrs)

isvoid = getattr(elm, 'void_', False)
cltag = '' if isvoid else f'</{tag}>'
if not cs: return f'{sp}<{stag}>{cltag}{nl}'
if len(cs)==1 and not isinstance(cs[0],(list,tuple,FT)) and not hasattr(cs[0],'__ft__'):
return f'{sp}<{stag}>{esc_fn(cs[0])}{cltag}{nl}'
sattrs = ' '.join(_to_attr(k, v) for k, v in attrs.items() if v not in (False, None, ''))
stag += f' {sattrs}' if sattrs else stag

cltag = '' if is_void else f'</{tag}>'

if not cs:
if is_void: return f'{sp}<{stag}>{nl_end}'
else: return f'{sp}<{stag}>{cltag}{nl_end}'
if len(cs) == 1 and not isinstance(cs[0], (list, tuple, FT)) and not hasattr(cs[0], '__ft__'):
content = esc_fn(cs[0])
return f'{sp}<{stag}>{content}{cltag}{nl_end}'

res = f'{sp}<{stag}>{nl}'
res += ''.join(_to_xml(c, lvl=lvl+2, indent=indent, do_escape=do_escape) for c in cs)
if not isvoid: res += f'{sp}{cltag}{nl}'
for c in cs:
res += _to_xml(c, lvl=lvl+2 if indent else 0, indent=indent, do_escape=do_escape)
if not is_void: res += f'{sp}{cltag}{nl_end}'
return Safe(res)

def to_xml(elm, lvl=0, indent:bool=True, do_escape:bool=True):
# %% ../nbs/11_xml.ipynb
def to_xml(elm, lvl=0, indent=True, do_escape=True):
"Convert `ft` element tree into an XML string"
return Safe(_to_xml(elm, lvl, indent, do_escape=do_escape))

Expand Down
Loading

0 comments on commit a8e1c7e

Please sign in to comment.