#!/usr/bin/ruby # This file is part of html2trac. # Copyright (C) 2008-2009 Dennis Schridde # # html2trac is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # html2trac is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with html2trac. If not, see . require 'rexml/document' module REXML # Trac Wiki formatter # Transforms XHTML 1.1 into Trac Wiki syntax # # This worked for Warzone 2100's ScriptingManual and likely has to be adapted to suit more generic needs. # Do no forget to look at write_element()'s "skip" variable when adjusting it to your documents. class Formatters::Trac < Formatters::Default def initialize() super() @listtype = [] @listdepth = 0 @idmap = {} end def write( node, output ) case node when Document if node.xml_decl.encoding != "UTF-8" && !output.kind_of?(Output) output = Output.new( output, node.xml_decl.encoding ) end write_document( node, output ) when Element write_element( node, output ) when Declaration, ElementDecl, NotationDecl, ExternalEntity, Entity, Attribute, AttlistDecl # Ignore when Instruction write_instruction( node, output ) when DocType, XMLDecl # Ignore when Comment write_comment( node, output ) when CData write_cdata( node, output ) when Text write_text( node, output ) else raise Exception.new("XML FORMATTING ERROR") end end def write_cdata(node, output) fail end def write_comment(node, output) output << "\n{{{\n" output << "#!\n" output << node.to_s output << "\n}}}\n" end def build_string(node) result = "" case node when Text: result << node.to_s when Element: node.children.each { |child| result << build_string(child) } end result end def write_document( node, output ) node.elements.each("//*[@id]") { |id| @idmap[id.attributes["id"]] = build_string(id).delete("(){}[]/+ ") } node.children.each { |child| write( child, output ) } end def write_element(node, output) begin_tag = "" end_tag = "" skip = nil # Set this for nodes you want to skip in your file case node.name when "html": when "head": skip = true when "body": when "div": skip = node.elements["p/a[@href='top']"] when "span": when "pre": begin_tag = "\n{{{\n#!c\n" ; end_tag = "\n}}}\n" when "table": begin_tag = "\n" when "tr": begin_tag = "|" ; end_tag = "|\n" when "td": begin_tag = "|" ; end_tag = "|" when "th": begin_tag = "|'''" ; end_tag = "'''|" when "p": begin_tag = "\n" ; end_tag = "\n" when "h1": begin_tag = "\n= " ; end_tag = " =\n" when "h2": begin_tag = "\n== " ; end_tag = " ==\n" when "h3": begin_tag = "\n=== " ; end_tag = " ===\n" when "h4": begin_tag = "\n==== " ; end_tag = " ====\n" when "h5": begin_tag = "\n===== " ; end_tag = " =====\n" when "b": begin_tag = "'''" ; end_tag = "'''" when "i": begin_tag = "''" ; end_tag = "''" when "u": begin_tag = "__" ; end_tag = "__" when "br": begin_tag = "[[BR]]\n" when "hr": begin_tag = "\n----\n" when "dl": begin_tag = "\n" when "dt": begin_tag = " " ; end_tag = "::\n" when "dd": begin_tag = " " ; end_tag = "\n" if node.next_element when "ol": if node.elements["ancestor::table"]: # Trac does not support lists/linebreaks inside tables! begin_tag = "[[BR]]" else begin_tag = "\n" end @listtype.push "ol" @listdepth += 1 when "ul": if node.elements["ancestor::table"]: # Trac does not support lists/linebreaks inside tables! begin_tag = "[[BR]]" else begin_tag = "\n" end @listtype.push "ul" @listdepth += 1 when "li": case @listtype.last when "ol": if (@listdepth % 2) == 0: begin_tag = " " * @listdepth + "1. " else begin_tag = " " * @listdepth + "a. " end when "ul": begin_tag = " " * @listdepth + "* " end if node.elements["ancestor::table"]: # Trac does not support lists/linebreaks inside tables! end_tag = "[[BR]]" elsif node.next_element: end_tag = "\n" end when "a": href = node.attributes["href"] if href == "#top": skip = true end if href[0,1] == "#": id = href[1..-1] begin_tag = "[#" + @idmap[id] + " " else begin_tag = "[" + href + " " end end_tag = "]" when "acronym": begin_tag = "''" ; end_tag = "''" # Use italic style when "code": begin_tag = "`" ; end_tag = "`" else raise Exception.new("XHTML FORMATTING ERROR: Unexpected tag: " + node.name) end if node.children.empty? output << begin_tag else output << begin_tag node.children.each { |child| write( child, output ) } output << end_tag end unless skip case node.name when "ol": @listtype.pop ; @listdepth -= 1 when "ul": @listtype.pop ; @listdepth -= 1 end end def write_instruction(node, output) fail end def write_text( node, output ) text = node.to_s if ["table", "tr", "dl", "ol", "ul"].include?(node.parent.name): text.gsub!(/[[:space:]]+/, '') elsif node.parent.name != "pre" text.gsub!(/[[:space:]]+/, ' ') end output << Text::unnormalize(text) end end end xml = REXML::Document.new( STDIN ) REXML::Formatters::Trac.new.write(xml, STDOUT)