Don't like ads? PRO users don't see any ads ;-)
Guest

Untitled

By: a guest on May 2nd, 2012  |  syntax: None  |  size: 12.16 KB  |  hits: 12  |  expires: Never
download  |  raw  |  embed  |  report abuse  |  print
Text below is selected. Please press Ctrl+C to copy to your clipboard. (⌘+C on Mac)
  1. # coding: utf-8
  2. require 'nokogiri'
  3.  
  4. $default_style = 'Text_Style'
  5.  
  6. class TopicFile
  7.   attr_reader :filename
  8.   attr_accessor :styles
  9.  
  10.   def initialize(filename)
  11.     @filename = filename
  12.     @doc = nil
  13.     @styles = []
  14.     @processed_nodes = []
  15.   end
  16.  
  17.   def doc
  18.     @doc || @doc = Nokogiri::XML(open(@filename))
  19.   end
  20.  
  21.   # moves header and creates new header/para
  22.   def process_header!(header_node_text='ueNTP HA4UC/|EHUU')    
  23.     # getting header text
  24.     header_text = self.doc.xpath('//body/header/para').first.text
  25.    
  26.     # create para header
  27.     body_childs = self.doc.xpath('//body').first.children
  28.    
  29.     # getting header
  30.     h = body_childs.xpath('//header').first
  31.    
  32.     # getting header's para
  33.     h_para = h.xpath('//para').first
  34.    
  35.     # store page header text
  36.     h_para_content = h_para.content
  37.    
  38.     # replace header's para text
  39.     h_para.content = header_node_text
  40.    
  41.     # creating new para for header
  42.     para_header_node = Nokogiri::XML::Node.new('para', self.doc)
  43.     para_header_node['styleclass'] = 'Header2'
  44.  
  45.     # creating para's text note with page header text
  46.     para_header_text_node = Nokogiri::XML::Node.new('text', self.doc)
  47.     para_header_text_node['styleclass'] = 'Header2'
  48.     para_header_text_node['translate'] = 'true'
  49.     para_header_text_node.content = h_para_content
  50.    
  51.     # add para's text into para node
  52.     para_header_node.add_child(para_header_text_node)
  53.    
  54.     # insert para_header immedeatly after <header> node
  55.     h.after(para_header_node)          
  56.   end
  57.  
  58.   def replace_styles!
  59.     # get root nodes
  60.     base_nodes = [self.doc.root]
  61.    
  62.     # for every root node...
  63.     base_nodes.each do |base_node|
  64.       # for every style replacement...
  65.       @styles.each do |style|
  66.         # replace style if exists
  67.         process_node(base_node, style[:old], style[:new])
  68.       end
  69.     end
  70.    
  71.     # for every root node...
  72.     base_nodes.each do |base_node|
  73.       normalize_style(base_node)
  74.     end
  75.   end
  76.  
  77.   def clear_styles!
  78.     # get root nodes
  79.     base_nodes = [self.doc.root]
  80.     # clear styles
  81.     base_nodes.each {|base_node| clear_style(base_node) }
  82.   end
  83.  
  84.   def process_node(node, old_style, new_style)
  85.     if node
  86.       # if style matches -> replace
  87.       if node['styleclass'] == old_style
  88.         node['styleclass'] = new_style
  89.         @processed_nodes << node        
  90.       end
  91.      
  92.       # if have children -> proceed they
  93.       if node.children && !node.children.empty?
  94.         node.children.each {|n| process_node(n, old_style, new_style) }
  95.       end
  96.     end
  97.   end
  98.  
  99.   def normalize_style(node)
  100.     if node
  101.       if node['styleclass'] && !@processed_nodes.include?(node)
  102.         node['styleclass'] = 'Text_Style'
  103.         node['style'] = ''
  104.       end
  105.      
  106.       # if have children -> proceed they
  107.       if node.children && !node.children.empty?
  108.         node.children.each {|n| normalize_style(n) }
  109.       end
  110.     end
  111.   end
  112.  
  113.   def clear_style(node)
  114.     if node
  115.       if node['style']
  116.         node['style'] = ''
  117.       end
  118.      
  119.       # if have children -> proceed they
  120.       if node.children && !node.children.empty?
  121.         node.children.each {|n| clear_style(n) }
  122.       end
  123.     end
  124.   end  
  125.  
  126.   def process_tables!
  127.     @to_table_header = []
  128.     base_nodes = [self.doc.root]
  129.     base_nodes.each {|base_node| process_table(base_node) }
  130.     @to_table_header.each do |para|
  131.       para['styleclass'] = 'Table_Header'
  132.       para['style'] = ''
  133.     end
  134.   end
  135.  
  136.   def process_table(node)
  137.     if node
  138.       # check one level children for image tag
  139.       children_tr_first = node.xpath('child::table/tr').first
  140.       if children_tr_first
  141.         children_paras = children_tr_first.xpath('child::td/para')
  142.       # end
  143.       # children_paras = node.xpath('child::table/tr[1]/td/para')
  144.         if children_paras && !children_paras.empty?
  145.           children_paras.each do |p|
  146.             @to_table_header << p
  147.             p_text = p.xpath('child::text').first
  148.             @to_table_header << p_text if p_text
  149.           end
  150.         end
  151.       end
  152.      
  153.       # if have children -> proceed they
  154.       if node.children && !node.children.empty?
  155.         node.children.each {|n| process_table(n) }
  156.       end
  157.     end    
  158.   end
  159.  
  160.   def set_style_images!
  161.     @to_style_image = []
  162.     base_nodes = [self.doc.root]
  163.     base_nodes.each {|base_node| set_style_image(base_node) }
  164.     @to_style_image.each do |node_with_image|
  165.       node_with_image['styleclass'] = 'Image_Style'
  166.       node_with_image['style'] = ''
  167.     end
  168.   end
  169.  
  170.   def set_style_image(node)
  171.     if node
  172.       # check one level children for image tag
  173.       children_images = node.xpath('child::image')
  174.       if children_images && !children_images.empty?
  175.         @to_style_image << node
  176.         children_images.each {|x| @to_style_image << x }
  177.       end
  178.      
  179.       # if have children -> proceed they
  180.       if node.children && !node.children.empty?
  181.         node.children.each {|n| set_style_image(n) }
  182.       end
  183.     end
  184.   end
  185. end
  186.  
  187. class FileProcessor
  188.   def initialize(folder='.', is_batch=false)
  189.     @folder = folder
  190.     @is_batch = is_batch
  191.   end
  192.  
  193.   def process!(h=false, s=false, c=false)
  194.     if !h && !s
  195.       puts "Обрабатывать нечего..."
  196.       return
  197.     end
  198.  
  199.     folders = []
  200.    
  201.     if @is_batch
  202.     end
  203.    
  204.     puts @folder
  205.    
  206.     Dir.chdir(@folder)
  207.     Dir.chdir('Topics')
  208.    
  209.     xmls = Dir.glob('*.xml')
  210.    
  211.     @renames = []
  212.    
  213.     i = 1
  214.     wputs "\nОбработка файлов...\n\n"
  215.     xmls.each do |xml_filename|
  216.       wputs "#{i}: #{xml_filename}"
  217.      
  218.       tf = TopicFile.new(xml_filename)
  219.      
  220.       if h
  221.         tf.process_header!('Центр Начислений')
  222.         wputs "    Заголовок перемещен"
  223.       end
  224.      
  225.       if s
  226.         # new actual styles
  227.         tf.styles << { :old => 'Heading1',             :new => 'header2'       }        
  228.         tf.styles << { :old => 'List Number',          :new => 'Number1'       }
  229.         tf.styles << { :old => 'List Number 2',        :new => 'Number2'       }
  230.         tf.styles << { :old => 'List Number 3',        :new => 'Number3'       }        
  231.         tf.styles << { :old => 'List Bullet',          :new => 'Mark1'         }
  232.         tf.styles << { :old => 'List Bullet+',         :new => 'Mark2'         }
  233.         tf.styles << { :old => 'Термин +',             :new => 'Term'          }
  234.         tf.styles << { :old => 'Примечание',           :new => 'Note_Header'   }
  235.         tf.styles << { :old => 'annotation text',      :new => 'Style_Note'    }
  236.         tf.styles << { :old => 'Таблица Заголовок+',   :new => 'Table_Header'  }
  237.         tf.styles << { :old => 'Таблица текст',        :new => 'Table_Text'    }
  238.         tf.styles << { :old => 'Код',                  :new => 'ProgramCod'    }
  239.         tf.styles << { :old => 'Код рамка',            :new => 'ProgramCod_Border' }
  240.         # tf.styles << { :old => 'Body Text Indent+',    :new => 'Style_Image'   }
  241.         tf.styles << { :old => 'Body Text Indent+',    :new => 'Image_Style'   }
  242.         tf.styles << { :old => 'Hyperlink',            :new => 'Style_Link'    }
  243.         tf.styles << { :old => 'Доп. стиль заголовка 6',:new => 'Header3'      }
  244.         tf.styles << { :old => 'Доп. стиль заголовка 7',:new => 'Header3'      }
  245.  
  246.         # removed 'cos Text_Style is $default_style
  247.         # tf.styles << { :old => 'Основной текст без отступа',    
  248.                        # :new => 'Text_Style' }
  249.         # tf.styles << { :old => 'Body Text Indent',     :new => 'Text_Style'  }
  250.        
  251.         # New actual good styles
  252.         tf.styles << { :old => 'header2',          :new => 'header2'           }        
  253.         tf.styles << { :old => 'Number1',          :new => 'Number1'           }
  254.         tf.styles << { :old => 'Number2',          :new => 'Number2'           }
  255.         tf.styles << { :old => 'Number3',          :new => 'Number3'           }        
  256.         tf.styles << { :old => 'Mark1',            :new => 'Mark1'             }
  257.         tf.styles << { :old => 'Mark2',            :new => 'Mark2'             }
  258.         tf.styles << { :old => 'Term',             :new => 'Term'              }
  259.         tf.styles << { :old => 'Note_Header',      :new => 'Note_Header'       }
  260.         tf.styles << { :old => 'Style_Note',       :new => 'Style_Note'        }
  261.         tf.styles << { :old => 'Table_Header',     :new => 'Table_Header'      }
  262.         tf.styles << { :old => 'Table_Text',       :new => 'Table_Text'        }
  263.         tf.styles << { :old => 'ProgramCod',       :new => 'ProgramCod'        }
  264.         tf.styles << { :old => 'ProgramCod_Border',:new => 'ProgramCod_Border' }
  265.         # tf.styles << { :old => 'Style_Image',      :new => 'Style_Image'       }
  266.         tf.styles << { :old => 'Image_Style',      :new => 'Image_Style'       }
  267.         tf.styles << { :old => 'Style_Link',       :new => 'Style_Link'        }
  268.         tf.styles << { :old => 'Header3',          :new => 'Header3'           }
  269.         tf.styles << { :old => 'Header2',          :new => 'Header2'           }
  270.         tf.styles << { :old => 'Header1',          :new => 'Header1'           }
  271.        
  272.         tf.styles << { :old => 'Style_Header1',        :new => 'Style_Header1' }
  273.         tf.styles << { :old => 'Style_Header2',        :new => 'Style_Header2' }
  274.         tf.styles << { :old => 'Style_Header2',        :new => 'Header2' }
  275.         tf.styles << { :old => 'Style_Header3',        :new => 'Style_Header3' }
  276.        
  277.         tf.replace_styles!
  278.         tf.set_style_images!
  279.         tf.process_tables!
  280.         wputs "    Стили заменены"
  281.       end
  282.      
  283.       if c
  284.         tf.clear_styles!
  285.         wputs "    Дополнительные стили очищены"
  286.       end
  287.      
  288.       Dir.mkdir('_new') if !Dir.exists?('_new')
  289.      
  290.       File.open("_new/#{i}.xml", 'w') do |file|
  291.         file.write(tf.doc.to_xml)
  292.         wputs "    => #{i}.xml"        
  293.         @renames << { :old => xml_filename.split('.')[0], :new => i.to_s}
  294.       end    
  295.       i += 1      
  296.     end    
  297.    
  298.     Dir.chdir('..')
  299.     # rename topic is in table of content
  300.     toc = Nokogiri::XML(open('Maps/table_of_contents.xml'))
  301.    
  302.     # get root nodes
  303.     base_nodes = [toc.root]
  304.    
  305.     wputs "\n\nОбработка содержания..."
  306.    
  307.     # for every root node...
  308.     base_nodes.each do |base_node|
  309.       # for every style replacement...
  310.       @renames.each do |rename|
  311.         # replace style if exists
  312.         process_toc(base_node, rename[:old], rename[:new])
  313.       end
  314.     end
  315.     wputs 'Содержание обработано, необходимо вручную переименовать новый'
  316.     wputs 'файл Maps\table_of_contents_NEW.xml в файл table_of_contents.xml,'
  317.     wputs 'старый файл необходимо удалить.'
  318.    
  319.     # puts toc.to_xml
  320.     File.open('Maps/table_of_contents_NEW.xml', 'w') do |toc_file|
  321.       toc_file.write(toc.to_xml)
  322.     end
  323.    
  324.   end
  325.  
  326.   def process_toc(node, old_href, new_href)
  327.     if node
  328.       # if style matches -> replace
  329.       if node['href'] == old_href
  330.         node['href'] = new_href
  331.       end
  332.      
  333.       # if have children -> proceed they
  334.       if node.children && !node.children.empty?
  335.         node.children.each {|n| process_toc(n, old_href, new_href) }
  336.       end
  337.     end
  338.   end
  339. end
  340.  
  341. def check(arg, s, f)
  342.   arg == "-#{s}" || arg == "--#{f}"
  343. end
  344.  
  345. def wputs(str='')
  346.   begin
  347.     puts str.encode('cp866')
  348.   rescue
  349.     puts str
  350.   end
  351. end
  352.  
  353. if ARGV.empty? || ARGV.count < 2
  354.   wputs "Конвертер отчетов, заменяет стили и перемещает заголовки.\n\n"
  355.   wputs "Способ использования: ruby ham_edit.rb [опции] [путь до распакованной папки]"
  356.   wputs "  Примечание: распакованная папка должна содержать папку Topics."
  357.   wputs ""
  358.   wputs "Возможные опции:"
  359.   wputs "    -s - замена стилей"
  360.   wputs "    -h - перемещение заголовков"
  361.   # wputs "    -c - очистка прямого указания форматирования"
  362.   exit
  363. end
  364.  
  365. fp = FileProcessor.new(ARGV[-1])
  366.  
  367. s, h, c = false, false, false
  368.  
  369. ARGV.each do |arg|
  370.   s ||= check arg, :s, :styles
  371.   h ||= check arg, :h, :headers
  372.   # c ||= check arg, :c, :clear
  373. end
  374.  
  375. fp.process!(h, s, c)