class Phlex::SGML

def __attributes__(attributes, buffer = +"")

def __attributes__(attributes, buffer = +"")
	attributes.each do |k, v|
		next unless v
		name = case k
			when String then k
			when Symbol then k.name.tr("_", "-")
			else raise Phlex::ArgumentError.new("Attribute keys should be Strings or Symbols.")
		end
		value = case v
		when true
			true
		when String
			v.gsub('"', """)
		when Symbol
			v.name.tr("_", "-").gsub('"', """)
		when Integer, Float
			v.to_s
		when Hash
			case k
			when :style
				__styles__(v).gsub('"', """)
			else
				__nested_attributes__(v, "#{name}-", buffer)
			end
		when Array
			case k
			when :style
				__styles__(v).gsub('"', """)
			else
				__nested_tokens__(v)
			end
		when Set
			case k
			when :style
				__styles__(v).gsub('"', """)
			else
				__nested_tokens__(v.to_a)
			end
		when Phlex::SGML::SafeObject
			v.to_s.gsub('"', """)
		else
			raise Phlex::ArgumentError.new("Invalid attribute value for #{k}: #{v.inspect}.")
		end
		lower_name = name.downcase
		unless Phlex::SGML::SafeObject === v
			normalized_name = lower_name.delete("^a-z-")
			if value != true && REF_ATTRIBUTES.include?(normalized_name)
				case value
				when String
					if value.downcase.delete("^a-z:").start_with?("javascript:")
						# We just ignore these because they were likely not specified by the developer.
						next
					end
				else
					raise Phlex::ArgumentError.new("Invalid attribute value for #{k}: #{v.inspect}.")
				end
			end
			if normalized_name.bytesize > 2 && normalized_name.start_with?("on") && !normalized_name.include?("-")
				raise Phlex::ArgumentError.new("Unsafe attribute name detected: #{k}.")
			end
			if UNSAFE_ATTRIBUTES.include?(normalized_name)
				raise Phlex::ArgumentError.new("Unsafe attribute name detected: #{k}.")
			end
		end
		if name.match?(/[<>&"']/)
			raise Phlex::ArgumentError.new("Unsafe attribute name detected: #{k}.")
		end
		if lower_name.to_sym == :id && k != :id
			raise Phlex::ArgumentError.new(":id attribute should only be passed as a lowercase symbol.")
		end
		case value
		when true
			buffer << " " << name
		when String
			buffer << " " << name << '="' << value << '"'
		end
	end
	buffer
end