Files
2025-09-29 00:52:08 +02:00

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("\"","&quot;")
out_val = out_val.gsub("\r\n","&#x0D;&#x0A;")
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!("\"","&quot;")
s.gsub!("&amp;#x0D;&amp;#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