# File lib/html5/serializer/htmlserializer.rb, line 42
    def serialize(treewalker, encoding=nil)
      in_cdata = false
      @errors = []

      if encoding and @inject_meta_charset
        require 'html5/filters/inject_meta_charset'
        treewalker = Filters::InjectMetaCharset.new(treewalker, encoding)
      end

      if @strip_whitespace
        require 'html5/filters/whitespace'
        treewalker = Filters::WhitespaceFilter.new(treewalker)
      end

      if @sanitize
        require 'html5/filters/sanitizer'
        treewalker = Filters::HTMLSanitizeFilter.new(treewalker)
      end

      if @omit_optional_tags
        require 'html5/filters/optionaltags'
        treewalker = Filters::OptionalTagFilter.new(treewalker)
      end

      result = []
      treewalker.each do |token|
        type = token[:type]
        if type == :Doctype
          doctype = "<!DOCTYPE %s>" % token[:name]
          result << doctype

        elsif [:Characters, :SpaceCharacters].include? type
          if type == :SpaceCharacters or in_cdata
            if in_cdata and token[:data].include?("</")
              serialize_error("Unexpected </ in CDATA")
            end
            result << token[:data]
          else
            result << escape(token[:data])
          end

        elsif [:StartTag, :EmptyTag].include? type
          name = token[:name]
          if RCDATA_ELEMENTS.include?(name) and not @escape_rcdata
            in_cdata = true
          elsif in_cdata
            serialize_error(_("Unexpected child element of a CDATA element"))
          end
          attributes = []
          for k,v in attrs = token[:data].to_a.sort
            attributes << ' '

            attributes << k
            if not @minimize_boolean_attributes or \
                (!(BOOLEAN_ATTRIBUTES[name]||[]).include?(k) \
                and !BOOLEAN_ATTRIBUTES[:global].include?(k))
              attributes << "="
              if @quote_attr_values or v.empty?
                quote_attr = true
              else
                quote_attr = (SPACE_CHARACTERS + %w(< > " ')).any? {|c| v.include?(c)}
              end
              v = v.gsub("&", "&amp;")
              v = v.gsub("<", "&lt;") if @escape_lt_in_attrs
              if quote_attr
                quote_char = @quote_char
                if @use_best_quote_char
                  if v.index("'") and !v.index('"')
                    quote_char = '"'
                  elsif v.index('"') and !v.index("'")
                    quote_char = "'"
                  end
                end
                if quote_char == "'"
                  v = v.gsub("'", "&#39;")
                else
                  v = v.gsub('"', "&quot;")
                end
                attributes << quote_char << v << quote_char
              else
                attributes << v
              end
            end
          end
          if VOID_ELEMENTS.include?(name) and @use_trailing_solidus
            if @space_before_trailing_solidus
              attributes << " /"
            else
              attributes << "/"
            end
          end
          result << "<%s%s>" % [name, attributes.join('')]

        elsif type == :EndTag
          name = token[:name]
          if RCDATA_ELEMENTS.include?(name)
            in_cdata = false
          elsif in_cdata
            serialize_error(_("Unexpected child element of a CDATA element"))
          end
          end_tag = "</#{name}>"
          result << end_tag

        elsif type == :Comment
          data = token[:data]
          serialize_error(_("Comment contains --")) if data.index("--")
          comment = "<!--%s-->" % token[:data]
          result << comment

        else
          serialize_error(token[:data])
        end
      end

      if encoding and encoding != 'utf-8'
        require 'iconv'
        Iconv.iconv(encoding, 'utf-8', result.join('')).first
      else
        result.join('')
      end
    end