Chris@0: module CodeRay Chris@0: module Encoders Chris@0: Chris@0: # = XML Encoder Chris@0: # Chris@0: # Uses REXML. Very slow. Chris@0: class XML < Encoder Chris@0: Chris@0: include Streamable Chris@0: register_for :xml Chris@0: Chris@0: FILE_EXTENSION = 'xml' Chris@0: Chris@0: require 'rexml/document' Chris@0: Chris@0: DEFAULT_OPTIONS = { Chris@0: :tab_width => 8, Chris@0: :pretty => -1, Chris@0: :transitive => false, Chris@0: } Chris@0: Chris@0: protected Chris@0: Chris@0: def setup options Chris@0: @doc = REXML::Document.new Chris@0: @doc << REXML::XMLDecl.new Chris@0: @tab_width = options[:tab_width] Chris@0: @root = @node = @doc.add_element('coderay-tokens') Chris@0: end Chris@0: Chris@0: def finish options Chris@0: @out = '' Chris@0: @doc.write @out, options[:pretty], options[:transitive], true Chris@0: @out Chris@0: end Chris@0: Chris@0: def text_token text, kind Chris@0: if kind == :space Chris@0: token = @node Chris@0: else Chris@0: token = @node.add_element kind.to_s Chris@0: end Chris@0: text.scan(/(\x20+)|(\t+)|(\n)|[^\x20\t\n]+/) do |space, tab, nl| Chris@0: case Chris@0: when space Chris@0: token << REXML::Text.new(space, true) Chris@0: when tab Chris@0: token << REXML::Text.new(tab, true) Chris@0: when nl Chris@0: token << REXML::Text.new(nl, true) Chris@0: else Chris@0: token << REXML::Text.new($&) Chris@0: end Chris@0: end Chris@0: end Chris@0: Chris@0: def open_token kind Chris@0: @node = @node.add_element kind.to_s Chris@0: end Chris@0: Chris@0: def close_token kind Chris@0: if @node == @root Chris@0: raise 'no token to close!' Chris@0: end Chris@0: @node = @node.parent Chris@0: end Chris@0: Chris@0: end Chris@0: Chris@0: end Chris@0: end