I'd use
(defun table--generate-source-html-tag (tag &optional body attrs)
(when table-uppercase-html-tags (setq tag (upcase tag)))
(concat "<" tag (if attrs " ") attrs
(if body (concat ">" body "</" tag) "/") ">"))
giving
(table--generate-source-html-tag "a" "b" "c=d")
=> "<a c=d>b</a>"
(table--generate-source-html-tag "a")
=> "<a/>"
I removed the spaces around the body because they could break things and
are trivial to include in the argument. I'd really be tempted to make
attrs an alist, but that might be overengineering the problem. The
XML-style empty tags might be undesirable, but they're optional: