Xalan with Ruby (either command line or via Jrb)?

Does anyone have any experience will using Xalan from a Ruby program
(Rails app. especially useful)?

I’m willing to entertain running command lines but would like to use Jrb
(I’ve already got that working).

I’d consider JRuby but feel like that might be too heavyweight.

Any advice/feedback would be appreciated.

Thanks,
Wes

Wes G. wrote:

Does anyone have any experience will using Xalan from a Ruby program
(Rails app. especially useful)?

I’m willing to entertain running command lines but would like to use Jrb
(I’ve already got that working).

I’d consider JRuby but feel like that might be too heavyweight.

Any advice/feedback would be appreciated.

Thanks,
Wes

I seem to have gotten this working - a basic Xalan XSL transform from
one file to another. The do_XSL_transform takes the input file name,
output file name, and XSL stylesheet file name as parameters.

Wes

==========================================

require ‘rjb’

require_gem ‘rjb’, ‘>= 1.0.2’

module XalanSupport
def XalanSupport.load_Xalan_libraries
[‘serializer.jar’, ‘xml-apis.jar’, ‘xercesImpl.jar’,
‘xalan.jar’].each do |lib_name|
Rjb::load("#{RAILS_ROOT}/lib/#{lib_name}", [’-Xmx512M’])
end
end

def XalanSupport.do_XSL_transform(infile, outfile, xsl)
#Load all of the Jars
XalanSupport.load_Xalan_libraries

#Load all the classes
stream_source_class = 

Rjb::import(‘javax.xml.transform.stream.StreamSource’)
stream_result_class =
Rjb::import(‘javax.xml.transform.stream.StreamResult’)
file_output_stream_class = Rjb::import(‘java.io.FileOutputStream’)
transformer_factory_class =
Rjb::import(‘javax.xml.transform.TransformerFactory’)

#Create the XSL transformer
transformer_factory = transformer_factory_class.newInstance
transformer = 

transformer_factory.newTransformer(stream_source_class.new(xsl))

#Set up the input and output
source = stream_source_class.new(infile)
result = 

stream_result_class.new(file_output_stream_class.new(outfile))

transformer.transform(source, result)

end
end

What I’d like to do with this, however, is to be able to return the
output of the transform directly to the browser, which would imply that
I would need to be able to grab output from a
javax.xml.transform.stream.StreamResult object and stream it back to the
browser. That way I don’t have to generate an output file which I’m
just going to send back to the browser anyway.

But what would be the best way to connect a Java stream to a Ruby IO
object? Seems like I would have to have some mediator between the two
that would shuttle the data off the Java IO object onto the Ruby one.

Make sense?

Wes

A better solution - use strings for input/output and no need to write
files. The return value from this method is the transformed XML.

==============================================================================
require ‘rjb’

require_gem ‘rjb’, ‘>= 1.0.2’

module XalanSupport
def XalanSupport.load_Xalan_libraries
[‘serializer.jar’, ‘xml-apis.jar’, ‘xercesImpl.jar’,
‘xalan.jar’].each do |lib_name|
Rjb::load("#{RAILS_ROOT}/lib/#{lib_name}", [’-Xmx512M’])
end
end

def XalanSupport.do_XSL_transform(instring, xsl_file_name)
#Load all of the Jars
XalanSupport.load_Xalan_libraries

#Load all the classes
string_reader_class = Rjb::import('java.io.StringReader')
string_writer_class = Rjb::import('java.io.StringWriter')
stream_source_class = 

Rjb::import(‘javax.xml.transform.stream.StreamSource’)
stream_result_class =
Rjb::import(‘javax.xml.transform.stream.StreamResult’)
transformer_factory_class =
Rjb::import(‘javax.xml.transform.TransformerFactory’)

#Set up the input and output
input_string_reader = string_reader_class.new(instring)
output_string_writer = string_writer_class.new
source = stream_source_class.new(input_string_reader)
result = stream_result_class.new(output_string_writer)

#Create the XSL transformer
transformer_factory = transformer_factory_class.newInstance
transformer = 

transformer_factory.newTransformer(stream_source_class.new(xsl_file_name))

transformer.transform(source, result)

result.getWriter.getBuffer.toString

end
end

Two more things:

  1. This:

[‘serializer.jar’, ‘xml-apis.jar’, ‘xercesImpl.jar’, ‘xalan.jar’].each
do |lib_name|
Rjb::load("#{RAILS_ROOT}/lib/#{lib_name}", [’-Xmx512M’])
end

is not the best way to do the Rjb::load business, since Rjb::load is
what establishes the JVM. What the code above does is attempt to load
the JVM and change the classpath 4 different times, which doesn’t really
make sense. What that probably should be is:

classpath = ‘’

[‘serializer.jar’, ‘xml-apis.jar’, ‘xercesImpl.jar’, ‘xalan.jar’].each
do |lib_name|
classpath << “#{lib_name}:” #Use ; for Windows
end

Rjb::load("#{classpath}", [’-Xmx512M’])

In fact, I ended up doing the Rjb::load once in my application.

  1. As it turns out, under J2SE 1.5.0 (Java 5, whatever), you don’t
    actually need Xalan to do XSL transformations if you are ok with the
    default implementation provided with the JDK. So the solution posted
    previously works without any Rjb::load() statements and just the
    contents of the XalanSupport.do_XSL_transform method.

Wes