287 lines
7.3 KiB
Ruby
Executable File
287 lines
7.3 KiB
Ruby
Executable File
#
|
|
# File:: xml2vsxml.rb
|
|
#
|
|
# Pipeline:: takes a generic xml file and converts it to an xml format
|
|
# that visual studio understands. this is because visual studio
|
|
# thinks it needs to 'upgrade' perfectly well formatted xml data.
|
|
# muppets
|
|
#
|
|
#
|
|
# Author:: Greg Smith <greg@rockstarnorth.com>
|
|
# Date:: 28 January 2010
|
|
#
|
|
#
|
|
|
|
#-----------------------------------------------------------------------------
|
|
# Uses
|
|
#-----------------------------------------------------------------------------
|
|
require "rexml/document"
|
|
|
|
#-----------------------------------------------------------------------------
|
|
# Implementation
|
|
#-----------------------------------------------------------------------------
|
|
module Pipeline
|
|
|
|
class VsXml < REXML::Formatters::Default
|
|
|
|
@@vs2010_format = false
|
|
|
|
def VsXml.convert_to_vsxml( input_filename, output_filename, vs2010_format = false )
|
|
|
|
@@vs2010_format = vs2010_format
|
|
|
|
file = File.open(input_filename,"r")
|
|
doc = REXML::Document.new(file)
|
|
file.close()
|
|
|
|
begin
|
|
file = File.open(output_filename,"w")
|
|
file.truncate(0)
|
|
|
|
formatter = VsXml.new()
|
|
|
|
formatter.write( doc, file )
|
|
|
|
rescue Exception => ex
|
|
print "Unable to write #{output_filename}!\n"
|
|
print "Exception: #{ex.message}\n"
|
|
print ex.backtrace.join( "\n" )
|
|
|
|
return false
|
|
ensure
|
|
file.close()
|
|
end
|
|
|
|
return true
|
|
end
|
|
|
|
# If compact is set to true, then the formatter will attempt to use as
|
|
# little space as possible
|
|
attr_accessor :compact
|
|
# The width of a page. Used for formatting text
|
|
attr_accessor :width
|
|
|
|
# Create a new pretty printer.
|
|
#
|
|
# output::
|
|
# An object implementing '<<(String)', to which the output will be written.
|
|
# indentation::
|
|
# An integer greater than 0. The indentation of each level will be
|
|
# this number of spaces. If this is < 1, the behavior of this object
|
|
# is undefined. Defaults to 2.
|
|
# ie_hack::
|
|
# If true, the printer will insert whitespace before closing empty
|
|
# tags, thereby allowing Internet Explorer's feeble XML parser to
|
|
# function. Defaults to false.
|
|
def initialize( indentation=1, ie_hack=false )
|
|
@indentation = indentation
|
|
@level = 0
|
|
@ie_hack = ie_hack
|
|
@width = 80
|
|
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
|
|
node.write( output,-1 )
|
|
|
|
when Instruction
|
|
write_instruction( node, output )
|
|
|
|
when DocType
|
|
node.write( output )
|
|
|
|
when XMLDecl
|
|
if @@vs2010_format == false
|
|
output << "<?xml version=\"1.0\" encoding=\"Windows-1252\"?>"
|
|
else
|
|
output << "<?xml version=\"1.0\" encoding=\"#{node.encoding}\"?>"
|
|
end
|
|
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
|
|
|
|
protected
|
|
|
|
def write_element(node, output)
|
|
|
|
output << "\t"*@level
|
|
output << "<#{node.expanded_name}"
|
|
|
|
node.attributes.each_attribute do |attr|
|
|
|
|
if @@vs2010_format == false
|
|
output << "\n"
|
|
output << "\t"*(@level + 1)
|
|
else
|
|
output << " " #Adds a space between attribute on each line.
|
|
end
|
|
|
|
out_val = attr.value.gsub("\"",""")
|
|
out_val = out_val.gsub("\r\n","
")
|
|
|
|
output << ( "#{attr.name}=\"#{out_val}\"" )
|
|
end unless node.attributes.empty?
|
|
|
|
if node.children.empty?
|
|
if @ie_hack
|
|
output << " "
|
|
end
|
|
|
|
if @@vs2010_format == false
|
|
output << "\n"
|
|
output << "\t"*@level
|
|
end
|
|
output << "/"
|
|
else
|
|
|
|
output << ">"
|
|
|
|
# If compact and all children are text, and if the formatted output
|
|
# is less than the specified width, then try to print everything on
|
|
# one line
|
|
skip = false
|
|
if compact
|
|
|
|
if node.children.inject(true) {|s,c| s & c.kind_of?(Text)}
|
|
|
|
string = ""
|
|
old_level = @level
|
|
@level = 0
|
|
node.children.each { |child| write( child, string ) }
|
|
@level = old_level
|
|
|
|
if string.length < @width
|
|
|
|
output << string
|
|
skip = true
|
|
end
|
|
end
|
|
end
|
|
|
|
unless skip
|
|
|
|
if @@vs2010_format == true
|
|
output << "\n" if node.children.size > 1
|
|
else
|
|
output << "\n"
|
|
end
|
|
|
|
@level += @indentation
|
|
node.children.each { |child|
|
|
|
|
next if child.kind_of?(Text) and child.to_s.strip.length == 0
|
|
write( child, output )
|
|
output << "\n" if @@vs2010_format == false
|
|
}
|
|
|
|
@level -= @indentation
|
|
output << "\t"*@level if @@vs2010_format == false
|
|
end
|
|
|
|
if @@vs2010_format == true
|
|
output << "\t"*@level if node.children.size > 1
|
|
end
|
|
output << "</#{node.expanded_name}"
|
|
end
|
|
|
|
output << ">"
|
|
output << "\n" if @@vs2010_format == true
|
|
end
|
|
|
|
def write_text( node, output )
|
|
|
|
s = node.to_s()
|
|
|
|
s.gsub!(/\s/,' ')
|
|
s.squeeze!(" ")
|
|
|
|
#Do not automatically wrap the contents of the text node in Visual Studio 2010.
|
|
#This results in multiple-line build steps being broken up with incorrect line breaks.
|
|
if @@vs2010_format == false
|
|
s = wrap(s, 80-@level)
|
|
end
|
|
|
|
s.gsub!("\"",""")
|
|
s.gsub!("&#x0D;&#x0A;", "\r\n")
|
|
|
|
if @@vs2010_format == false
|
|
s = indent_text(s, @level, " ", true)
|
|
output << (' '*@level + s)
|
|
end
|
|
|
|
output << s
|
|
end
|
|
|
|
def write_comment( node, output)
|
|
|
|
output << "\t" * @level
|
|
super
|
|
end
|
|
|
|
def write_cdata( node, output)
|
|
|
|
output << "\t" * @level
|
|
super
|
|
end
|
|
|
|
def write_document( node, output )
|
|
|
|
# Ok, this is a bit odd. All XML documents have an XML declaration,
|
|
# but it may not write itself if the user didn't specifically add it,
|
|
# either through the API or in the input document. If it doesn't write
|
|
# itself, then we don't need a carriage return... which makes this
|
|
# logic more complex.
|
|
node.children.each { |child|
|
|
next if child == node.children[-1] and child.instance_of?(Text)
|
|
unless child == node.children[0] or child.instance_of?(Text) or
|
|
(child == node.children[1] and !node.children[0].writethis)
|
|
output << "\n"
|
|
end
|
|
write( child, output )
|
|
}
|
|
end
|
|
|
|
private
|
|
|
|
def indent_text(string, level=1, style="\t", indentfirstline=true)
|
|
|
|
return string if level < 0
|
|
string.gsub(/\n/, "\n#{style*level}")
|
|
end
|
|
|
|
def wrap(string, width)
|
|
|
|
# Recursivly wrap string at width.
|
|
return string if string.length <= width
|
|
|
|
place = string.rindex(' ', width) # Position in string with last ' ' before cutoff
|
|
|
|
return string[0,place] + "\n" + wrap(string[place+1..-1], width) if place != nil
|
|
return string # Can not wrap this string.
|
|
end
|
|
end
|
|
end |