Skip to content

Commit 3c2f006

Browse files
committed
Merge pull request #10 from cybercode/stylesheet-output
Migrate stylesheet output methods from the r19mingw1 fork.
2 parents b06a3e9 + 713a28a commit 3c2f006

10 files changed

Lines changed: 183 additions & 8 deletions

File tree

ext/libxslt/libxslt.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ VALUE cXMLDocument;
99
VALUE cLibXSLT;
1010
VALUE cXSLT;
1111
VALUE eXSLTError;
12+
VALUE eXMLXSLTStylesheetRequireParsedDoc;
1213

1314
/*
1415
* Document-class: LibXSLT::XSLT
@@ -58,6 +59,7 @@ Init_libxslt_ruby(void) {
5859
rb_define_const(cXSLT, "NAMESPACE_XALAN", rb_str_new2((const char*)XSLT_XALAN_NAMESPACE));
5960

6061
eXSLTError = rb_define_class_under(cLibXSLT, "XSLTError", rb_eRuntimeError);
62+
eXMLXSLTStylesheetRequireParsedDoc = rb_define_class_under(cLibXSLT, "ResultError", rb_eRuntimeError);
6163

6264
ruby_init_xslt_stylesheet();
6365
ruby_init_exslt();

ext/libxslt/libxslt.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,5 +32,6 @@
3232

3333
extern VALUE cXSLT;
3434
extern VALUE eXSLTError;
35+
extern VALUE eXMLXSLTStylesheetRequireParsedDoc;
3536

3637
#endif

ext/libxslt/ruby_xslt_stylesheet.c

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
/* See the LICENSE file for copyright and distribution information. */
44

55
#include "libxslt.h"
6-
76
/*
87
* Document-class: LibXSLT::XSLT::Stylesheet
98
*
@@ -254,6 +253,39 @@ ruby_xslt_stylesheet_print(int argc, VALUE *argv, VALUE self) {
254253
return(INT2NUM(bytes));
255254
}*/
256255

256+
/* call-seq:
257+
* stylesheet.output(doc) => string
258+
*
259+
* Output an xml document, usually the result of an xslt
260+
* transformation, and return the result as a string. Output will be
261+
* done according to the output specification in the xslt
262+
* stylesheet. Note that this includes the encoding of the string.
263+
*/
264+
VALUE
265+
ruby_xslt_stylesheet_output(VALUE self, VALUE document) {
266+
// FIXME: set string encoding in ruby 1.9?
267+
xmlDocPtr xdoc;
268+
xsltStylesheetPtr xstylesheet;
269+
xmlChar *result = NULL;
270+
int len = 0, bytes = 0;
271+
VALUE rresult;
272+
273+
if (!rb_obj_is_kind_of(document, cXMLDocument))
274+
rb_raise(rb_eTypeError, "Must pass in an XML::Document instance.");
275+
276+
Data_Get_Struct(document, xmlDoc, xdoc);
277+
Data_Get_Struct(self, xsltStylesheet, xstylesheet);
278+
279+
bytes = xsltSaveResultToString(&result, &len,
280+
xdoc, xstylesheet);
281+
if ( bytes == -1 ) {
282+
rb_raise(rb_eRuntimeError, "error dumping document");
283+
}
284+
285+
rresult=rb_str_new((const char*)result,len);
286+
xmlFree(result);
287+
return rresult;
288+
}
257289

258290
#ifdef RDOC_NEVER_DEFINED
259291
cLibXSLT = rb_define_module("LibXSLT");
@@ -266,4 +298,5 @@ ruby_init_xslt_stylesheet(void) {
266298
rb_define_alloc_func(cXSLTStylesheet, ruby_xslt_stylesheet_alloc);
267299
rb_define_method(cXSLTStylesheet, "initialize", ruby_xslt_stylesheet_initialize, 1);
268300
rb_define_method(cXSLTStylesheet, "apply", ruby_xslt_stylesheet_apply, -1);
301+
rb_define_method(cXSLTStylesheet, "output", ruby_xslt_stylesheet_output, 1);
269302
}

ext/libxslt/version.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
#define RUBY_LIBXSLT_VERSION "1.0.9"
1+
#define RUBY_LIBXSLT_VERSION "1.1.0"
22
#define RUBY_LIBXSLT_VERNUM 1
3-
#define RUBY_LIBXSLT_VER_MAJ 0
4-
#define RUBY_LIBXSLT_VER_MIN 9
3+
#define RUBY_LIBXSLT_VER_MAJ 1
4+
#define RUBY_LIBXSLT_VER_MIN 0
55
#define RUBY_LIBXSLT_VER_MIC 0

lib/libxslt.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,4 @@
1313

1414
# And add support for deprecated functions
1515
require 'libxslt/deprecated'
16+
require 'libxslt/stylesheet'

lib/libxslt/stylesheet.rb

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
module LibXSLT
2+
module XSLT
3+
class Stylesheet
4+
# options to be used for parsing stylesheets
5+
PARSE_OPTIONS = LibXML::XML::Parser::Options::NOCDATA | LibXML::XML::Parser::Options::NOENT
6+
class << self
7+
# create a xslt stylesheet from a string
8+
def string(xml)
9+
doc = LibXML::XML::Parser.string(xml, :options => PARSE_OPTIONS).parse
10+
return new(doc)
11+
end
12+
# create a xslt stylesheet from a file specified by its filename
13+
def file(filename)
14+
doc = LibXML::XML::Parser.file(filename, :options => PARSE_OPTIONS).parse
15+
return new(doc)
16+
end
17+
# create a xslt stylesheet from an io object
18+
def io(io_object)
19+
doc = LibXML::XML::Parser.io(io_object, :options => PARSE_OPTIONS).parse
20+
return new(doc)
21+
end
22+
end
23+
# transform a xml to a string
24+
def transform(doc)
25+
return output(apply(doc))
26+
end
27+
# transform a xml to a file (specified by an output stream)
28+
end
29+
end
30+
end

test/test_deprecated.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# encoding: UTF-8
2-
require './test_helper'
2+
require 'test_helper'
33
require 'test/unit'
44

55
class TestDeprecated < Test::Unit::TestCase

test/test_exslt.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# encoding: UTF-8
22
require 'test/unit'
3-
require './test_helper'
3+
require 'test_helper'
44

55
class TestExslt < Test::Unit::TestCase
66
def setup

test/test_libxslt.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# encoding: UTF-8
22
require 'test/unit'
3-
require './test_helper'
3+
require 'test_helper'
44

55
class TextLibXslt < Test::Unit::TestCase
66
def test_constants

test/test_stylesheet.rb

Lines changed: 109 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# encoding: UTF-8
22
require 'test/unit'
3-
require './test_helper'
3+
require 'test_helper'
44

55
class TestStylesheet < Test::Unit::TestCase
66
def setup
@@ -103,4 +103,112 @@ def test_result_ownership
103103
GC.start
104104
end
105105
end
106+
107+
#RAF#
108+
def test_stylesheet_string
109+
filename = File.join(File.dirname(__FILE__), 'files/params.xsl')
110+
style = File.open(filename).readline(nil)
111+
stylesheet = XSLT::Stylesheet.string(style)
112+
assert_instance_of(XSLT::Stylesheet, stylesheet)
113+
end
114+
115+
def test_stylesheet_file
116+
filename = File.join(File.dirname(__FILE__), 'files/params.xsl')
117+
stylesheet = XSLT::Stylesheet.file(filename)
118+
assert_instance_of(XSLT::Stylesheet, stylesheet)
119+
end
120+
121+
def test_stylesheet_io
122+
filename = File.join(File.dirname(__FILE__), 'files/params.xsl')
123+
stylesheet = XSLT::Stylesheet.io(File.open(filename))
124+
assert_instance_of(XSLT::Stylesheet, stylesheet)
125+
end
126+
127+
def test_output
128+
filename = File.join(File.dirname(__FILE__), 'files/fuzface.xsl')
129+
sdoc = XML::Document.file(filename)
130+
stylesheet = XSLT::Stylesheet.new(sdoc)
131+
132+
rdoc = stylesheet.apply(doc)
133+
134+
xml = stylesheet.output(rdoc)
135+
136+
# output method is html -> no xml decl, empty tags not closed...
137+
assert xml =~ /^<html>/
138+
assert xml =~ /<meta http-equiv="Content-Type" content="text\/html; charset=UTF-8">\n<title>/
139+
end
140+
141+
def test_transform
142+
filename = File.join(File.dirname(__FILE__), 'files/fuzface.xsl')
143+
sdoc = XML::Document.file(filename)
144+
stylesheet = XSLT::Stylesheet.new(sdoc)
145+
146+
xml = stylesheet.transform(doc)
147+
148+
assert xml =~ /<meta http-equiv="Content-Type" content="text\/html; charset=UTF-8">\n<title>/
149+
end
150+
151+
def test_entities
152+
style = <<EOF
153+
<!DOCTYPE xsl:stylesheet [
154+
<!ENTITY foo 'bar'>
155+
]>
156+
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
157+
<xsl:template match="a">
158+
<out><xsl:text>&foo;</xsl:text>
159+
<xsl:apply-templates/></out>
160+
</xsl:template>
161+
</xsl:stylesheet>
162+
EOF
163+
164+
styledoc = LibXML::XML::Parser.string(style, :options => XSLT::Stylesheet::PARSE_OPTIONS).parse
165+
stylesheet = XSLT::Stylesheet.new(styledoc)
166+
167+
xml = "<!DOCTYPE a [<!ENTITY bla 'fasel'>]><a>&bla;</a>"
168+
doc = XML::Parser.string(xml, :options => XSLT::Stylesheet::PARSE_OPTIONS).parse
169+
170+
out = stylesheet.apply( doc )
171+
dump = stylesheet.output( out )
172+
assert_match( /<out>barfasel<\/out>/, dump)
173+
174+
# no entity replacement in document
175+
doc = XML::Parser.string(xml, :options => 0).parse
176+
out = stylesheet.apply( doc )
177+
dump = stylesheet.output( out )
178+
179+
assert_match(/<out>bar<\/out>/, dump) # entity content is missing
180+
181+
# note: having entities in your stylesheet that are not replaced during
182+
# parse, will crash libxslt (segfault)
183+
# seems to be a libxslt problem; you should not do that anyway
184+
# styledoc = LibXML::XML::Parser.string(style, : options => 0).parse
185+
# stylesheet = XSLT::Stylesheet.new(styledoc)
186+
end
187+
188+
def test_cdatasection
189+
doc = XML::Parser.string("<a/>").parse
190+
191+
style = <<EOF
192+
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
193+
<xsl:template match="a">
194+
<out><xsl:text disable-output-escaping="yes"><![CDATA[<>]]></xsl:text></out>
195+
</xsl:template>
196+
</xsl:stylesheet>
197+
EOF
198+
199+
styledoc = LibXML::XML::Parser.string(style, :options => XSLT::Stylesheet::PARSE_OPTIONS).parse
200+
stylesheet = XSLT::Stylesheet.new(styledoc)
201+
202+
out = stylesheet.apply( doc )
203+
dump = stylesheet.output( out )
204+
assert_match( /<out><><\/out>/, dump)
205+
206+
# without propper parse options (result is wrong from an xml/xslt point of view)
207+
styledoc = LibXML::XML::Parser.string(style).parse
208+
stylesheet = XSLT::Stylesheet.new(styledoc)
209+
210+
out = stylesheet.apply( doc )
211+
dump = stylesheet.output( out )
212+
assert_match( /<out>&lt;&gt;<\/out>/, dump)
213+
end
106214
end

0 commit comments

Comments
 (0)