HTML Element Generator
In this kata, you will be creating a python function that will take arguments and turn them into an HTML element.
An HTML tag has three parts:

The opening tag, which consists of a tag name and potentially attributes, all in between angle brackets.
The element content, which is the data that is shown on the webpage.  This is in between the opening and closing tags.
And the closing tag, which is an opening angle bracket, a forward slash, the name of the tag, and a closing angle bracket


If you were to have multiple attributes, they would each appear with a single space separating them

Some tags do not require a closing tag.  These are called self-closing tags.  For this kata, any tag passed into the function without 'element content' (keyword arguments) will be treated in this way:  after the tag name (and any attributes), there will be a space and then a forward slash.  See the picture to the right.

Data will be passed into the html function as such: 

The first argument will be the tag name
Any other non-keyword arguments will be element content. If no element content is given, the return value will be expected to be a self-closing tag.  If more than one argument is given as element content, you will return multiple of the same element, just with different element content, separated by one or more newline characters.
Ex: 

<p class="paragraph-text" id="example">Hello World!</p>\n<p class="paragraph-text" id="example">This is HTML code!</p>

IMPORTANT:  Because class is a python keyword, and class is a very important HTML attribute, you will also have to implement a keyword argument named cls, as opposed to class.  This attribute will appear as class="variable" in the return value of your function
Any other keyword arguments of the function will be treated as attributes of the element.  The keyword is the attribute name (left of the equals sign), and the keyword's value is the attribute's value (right of the equals sign).
Element attributes will appear in the return value of your function in the order that they appear in the function's arguments when it is called.  If cls is an argument of the function, it will always appear first (before any other keyword arguments).
Several Examples are provided

Difficulty: EASY
Starter code: def html(tag_name, *args, **kwargs):
	

Solutions:
def html(tag, *contents, **attr):
	openTag = tag + ''.join((f''' {('class' if k == 'cls' else k)}="{v}"''' for (k, v) in attr.items()))
	return '\n'.join((f'<{openTag}>{c}</{tag}>' for c in contents)) or f'<{openTag} />'


def html(tag, *args, **kwargs):
	open = tag + ''.join((f''' {('class' if k == 'cls' else k)}="{v}"''' for (k, v) in kwargs.items()))
	return '\n'.join((f'<{open}>{a}</{tag}>' for a in args)) or f'<{open} />'


def html(tag, *content, **attributes):
	attrs = ''.join((f''' {('class' if name == 'cls' else name)}="{value}"''' for (name, value) in attributes.items()))
	return '\n'.join((f'<{tag}{attrs}>{element}</{tag}>' for element in content)) if content else f'<{tag}{attrs} />'


import re

def html(tag, *content, cls=None, **atts):
	attributes = str(atts).replace('{', '').replace('}', '')
	lst = attributes.split(',')
	lst = [i.replace("'", '', 2).replace("'", '"').replace(': ', '=', 1) for i in lst]
	attributes = ''.join(lst)
	if len(content) > 0:
		txt = ''
		for i in range(len(content)):
			if cls:
				if attributes:
					txt += '\n' + f'<{tag} class="{str(cls)}" {attributes}>{content[i]}</{tag}>'
				else:
					txt += '\n' + f'<{tag} class="{str(cls)}">{content[i]}</{tag}>'
			elif attributes:
				txt += '\n' + f'<{tag} {attributes}>{content[i]}</{tag}>'
			else:
				txt += '\n' + f'<{tag}>{content[i]}</{tag}>'
		return txt[1:]
	elif cls:
		if attributes:
			return f'<{tag} class="{str(cls)}" {attributes} />'
		else:
			return f'<{tag} class="{str(cls)}" />'
	elif attributes:
		return f'<{tag} {attributes} />'
	else:
		return f'<{tag} />'


ALIAS = {'cls': 'class'}

def html(tag, *contents, **attribs):
	attrib_repr = ' ' + ' '.join((f'{ALIAS.get(key, key)}="{value}"' for (key, value) in attribs.items())) if attribs else ''
	if not contents:
		return f'<{tag}{attrib_repr} />'
	return '\n'.join((f'<{tag}{attrib_repr}>{content}</{tag}>' for content in contents))


def html(tag, *content, **attributes):
	attrib_str = ''.join((f''' {(key if key != 'cls' else 'class')}="{value}"''' for (key, value) in attributes.items()))
	if not content:
		return f'<{tag}{attrib_str} />'
	return '\n'.join((f'<{tag}{attrib_str}>{cnt}</{tag}>' for cnt in content))


def html(tag, *contents, **attrs):
	attr_ls = [f'''{('class' if k == 'cls' else k)}="{v}"''' for (k, v) in attrs.items()]
	if not contents:
		return f"<{' '.join((tag, *attr_ls))} />"
	else:
		return '\n'.join((f"<{' '.join((tag, *attr_ls))}>{content}</{tag}>" for content in contents))


def html(t, *args, **kwargs):
	s = ''.join((f''' {('class' if x == 'cls' else x)}="{kwargs[x]}"''' for x in kwargs))
	return f'<{t}{s} />' if not args else '\n'.join((f'<{t}{s}>{x}</{t}>' for x in args))


def html(tag, *content, **kwargs):
	attributes = ''
	if kwargs:
		attribs = []
		for (k, v) in list(kwargs.items()):
			if k == 'cls':
				k = 'class'
			attribs.append(f'{k}="{v}"')
		attributes = ' ' + ' '.join(attribs)
	if not content:
		return f'<{tag}{attributes} />'
	lines = []
	for line in content:
		lines.append(f'<{tag}{attributes}>{line}</{tag}>')
	return '\n'.join(lines)


def html(*args, **kwargs):
	attributes = tuple((f'''{name.replace('cls', 'class')}="{value}"''' for (name, value) in kwargs.items()))
	if len(args) == 1:
		return f"<{' '.join(args + attributes)} />"
	return '\n'.join((f"<{' '.join(args[:1] + attributes)}>{content}</{args[0]}>" for content in args[1:]))


def html(A, *B, **C):
	Cs = ' '.join(('{}="{}"'.format('class' if i == 'cls' else i, C[i]) for i in C))
	if len(B) == 0:
		return '<{}{}{} />'.format(A, ' ' if Cs else '', Cs)
	return '\n'.join(('<{}{}{}>{}</{}>'.format(A, ' ' if Cs else '', Cs, i, A) for i in B))


def html(*args, **kwargs):
	(keywords, elements) = ([], [])
	if kwargs:
		for (key, value) in kwargs.items():
			if key == 'cls':
				key = 'class'
			keywords.append(f'{key}="{value}"')
	if len(args) == 1:
		if kwargs:
			element = f'<{args[0]}'
			for key in keywords:
				element += ' ' + key
			element += ' />'
			return element
		else:
			return f'<{args[0]} />'
	for (i, arg) in enumerate(args):
		if i == 0:
			tag = arg
		else:
			element = f'<{tag}'
			if kwargs:
				for key in keywords:
					element += ' ' + key
			element += f'>{arg}</{tag}>'
			elements.append(element)
	return '\n'.join((element for element in elements))


def html(tag_name, *args, **kwargs):
	attributes = []
	for (key, value) in kwargs.items():
		if key == 'cls':
			key = 'class'
		attributes.append(f' {key}="{value}"')
	if len(args) == 0:
		return f"<{tag_name}{''.join(attributes)} />"
	closing_tags = []
	for arg in args:
		closing_tags.append(f"<{tag_name}{''.join(attributes)}>{arg}</{tag_name}>")
	return '\n'.join(closing_tags)


def html(xn, *args, **kwargs):
	props = ''.join((' ' + ('class' if p == 'cls' else p) + '="' + kwargs[p] + '"' for p in kwargs))
	return '\n'.join((f'<{xn}{props}>{v}</{xn}>' for v in args)) if args else f'<{xn}{props} />'


def html(*args, **k_args):
	attrs = []
	for (k, v) in list(k_args.items()):
		if k == 'cls':
			k = 'class'
		attrs.append(k + '="' + v + '"')
	attrs = ' '.join(attrs)
	args = list(args)
	tag = args.pop(0)
	opentag = ' '.join(['<' + tag, attrs]).strip()
	if len(args) == 0:
		return opentag + ' />'
	return '\n'.join([opentag + '>' + txt + '</' + tag + '>' for txt in args])


def stringify_attrs(attrs):
	result = ''
	for attr in attrs:
		new_attr = attrs[attr]
		if attr == 'cls':
			attr = 'class'
		result += attr + '=' + '"' + new_attr + '"' + ' '
	if not result:
		return ''
	return ' ' + result.strip()

def html(tag, *bodies, **attrs):
	if not bodies:
		result = '<' + tag + stringify_attrs(attrs) + ' />'
		return result
	result = ''
	for body in bodies:
		result += '<' + tag + stringify_attrs(attrs) + '>' + body + '</' + tag + '>' + '\n'
	return result.strip()