ruby-xslt 0.9.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,5 @@
1
+ <?xml version="1.0" encoding="ISO-8859-1" standalone="no"?>
2
+ <nodes>
3
+ <node number="1">Hello, </node>
4
+ <node number="2">World!</node>
5
+ </nodes>
@@ -0,0 +1,18 @@
1
+ <?xml version="1.0" encoding="ISO-8859-1"?>
2
+ <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
3
+ <xsl:output method="text" encoding="iso-8859-1" indent="no"/>
4
+ <xsl:param name="p1"/>
5
+ <xsl:param name="p2"/>
6
+
7
+ <xsl:template match="/">
8
+ p1:<xsl:value-of select="$p1"/>&#10;
9
+ p2:<xsl:value-of select="$p2"/>&#10;
10
+ <xsl:apply-templates/>
11
+ </xsl:template>
12
+
13
+ <xsl:template match="node">
14
+ <xsl:value-of select="."/>(<xsl:value-of select="@number"/>)&#10;
15
+ </xsl:template>
16
+
17
+ </xsl:stylesheet>
18
+
@@ -0,0 +1,18 @@
1
+ require "../xslt"
2
+
3
+ class XML::XSLT
4
+ def round_trip( arg )
5
+ arg
6
+ end
7
+ def type( arg )
8
+ arg.class.to_s
9
+ end
10
+ end
11
+
12
+ xslt = XML::XSLT.new()
13
+ xslt.xsl = "functions.xsl"
14
+ xslt.xml = "test.xml"
15
+ XML::XSLT.extFunction("round-trip", "http://test.none", xslt)
16
+ XML::XSLT.extFunction("type", "http://test.none", xslt)
17
+
18
+ puts xslt.serve
@@ -0,0 +1,13 @@
1
+ require "../xslt"
2
+
3
+ xslt = XML::XSLT.new()
4
+ xslt.xsl = "test.xsl"
5
+ xslt.xml = "test.xml"
6
+ xslt.parameters = { "p1" => "the first parameter ...",
7
+ "p2" => "'and the second one!'" }
8
+ #xslt.save("test.html")
9
+ puts xslt.serve
10
+ xslt.parameters = { "p1" => "Ruby...",
11
+ "p2" => "'...is cool !'" }
12
+ #xslt.save("test.html")
13
+ puts xslt.serve
@@ -0,0 +1,114 @@
1
+ #!/usr/bin/ruby -w
2
+ # See the LICENSE file for copyright and distribution information
3
+
4
+ require "mkmf"
5
+
6
+ def help
7
+ print <<HELP
8
+ "extconf.rb" configures this package to adapt to many kinds of systems.
9
+
10
+ Usage: ruby extconf.rb [OPTION]...
11
+
12
+ Configuration:
13
+ --help display this help and exit
14
+
15
+ --with-xslt-lib=PATH
16
+ --with-xslt-include=PATH
17
+ --with-xslt-dir=PATH specify the directory name for the libxslt include
18
+ files and/or library
19
+
20
+ --enable-error-handler enables a VERY crude error handler. Error messages
21
+ are appended to the class variable XML::XSLT and can
22
+ be accessed with the class method XML::XSLT.errors
23
+ (will change in a future version)
24
+ --disable-exslt disables libexslt support <http://exslt.org/>
25
+
26
+ --enable-debug compile with memwatch
27
+ <http://www.linkdata.se/sourcecode.html>
28
+
29
+ HELP
30
+ end
31
+
32
+ if ARGV.include?( "--help" )
33
+ help()
34
+ exit 0
35
+ end
36
+
37
+ if enable_config("debug", false)
38
+ File.symlink( "debug/memwatch.h", "memwatch.h" ) if( ! File.exist?("memwatch.h") )
39
+ File.symlink( "debug/memwatch.c", "memwatch.c" ) if( ! File.exist?("memwatch.c") )
40
+ $CFLAGS += " -DMEMWATCH -D__DEBUG__"
41
+ end
42
+
43
+ if enable_config("error-handler", false)
44
+ $CFLAGS += " -DUSE_ERROR_HANDLER"
45
+ end
46
+
47
+ $LIBPATH.push(Config::CONFIG['libdir'])
48
+
49
+ def crash(str)
50
+ printf(" extconf failure: %s\n", str)
51
+ exit 1
52
+ end
53
+
54
+ #unless have_library("z", "inflate")
55
+ # crash("need zlib")
56
+ #else
57
+ # $defs.push('-DHAVE_ZLIB_H')
58
+ #end
59
+
60
+ if dir_config( "xslt" ) != [nil, nil]
61
+ inc, lib = dir_config( 'xslt' )
62
+ $LDFLAGS << " -L#{lib} -lxslt -lxml2 -lz -lpthread -liconv -lm"
63
+ $CFLAGS << " -I#{inc}"
64
+ elsif ex = find_executable( "xslt-config" )
65
+ $LDFLAGS << ' ' + `#{ex} --libs`.chomp
66
+ $CFLAGS << ' ' + `#{ex} --cflags`.chomp
67
+ else
68
+ crash(<<EOL)
69
+ need libxslt.
70
+
71
+ Install the library or try one of the following options to extconf.rb:
72
+
73
+ --with-xslt-lib=/path/to/libxslt/lib
74
+ --with-xslt-include=/path/to/libxslt/include
75
+ EOL
76
+ end
77
+
78
+ if enable_config("exslt", true)
79
+ $LDFLAGS << " -lexslt"
80
+ $CFLAGS += " -DUSE_EXSLT"
81
+ end
82
+
83
+ $CFLAGS = '-g -Wall ' + $CFLAGS
84
+
85
+ puts "compile with : "
86
+ puts " CFLAGS = #{$CFLAGS}"
87
+ puts " LDFLAGS = #{$LDFLAGS}"
88
+ puts
89
+
90
+ create_header()
91
+ create_makefile("xml/xslt")
92
+
93
+ ###### Modify Makefile: #######
94
+ File.rename( "Makefile", "Makefile.orig" )
95
+ oldmkfl = File.open( "Makefile.orig" )
96
+ newmkfl = File.open( "Makefile", "w" )
97
+ oldmkfl.each_line{ |line|
98
+ case(line)
99
+ when /^all:/
100
+ newmkfl.puts(line)
101
+ newmkfl.puts("")
102
+ newmkfl.puts("test: all") # insert the "test" target
103
+ newmkfl.puts("\t\t@cd tests && ruby test.rb && cd ..")
104
+ newmkfl.puts("doc: all") # insert the "doc" target
105
+ newmkfl.puts("\t\t@rdoc -S -t \"Ruby/XSLT Documentation\" README AUTHORS ChangeLog xslt.c")
106
+ when /^distclean:/
107
+ newmkfl.puts(line)
108
+ newmkfl.puts("\t\t@-$(RM) memwatch.h memwatch.c Makefile.orig")
109
+ newmkfl.puts("\t\t@-$(RM)r doc")
110
+ else
111
+ newmkfl.puts(line)
112
+ end
113
+ }
114
+ newmkfl.close
@@ -0,0 +1,216 @@
1
+ /**
2
+ * Copyright (C) 2005 Gregoire Lejeune <gregoire.lejeune@free.fr>
3
+ *
4
+ * This program is free software; you can redistribute it and/or modify
5
+ * it under the terms of the GNU General Public License as published by
6
+ * the Free Software Foundation; either version 2 of the License, or
7
+ * (at your option) any later version.
8
+ *
9
+ * This program is distributed in the hope that it will be useful,
10
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ * GNU General Public License for more details.
13
+ *
14
+ * You should have received a copy of the GNU General Public License
15
+ * along with this program; if not, write to the Free Software
16
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
+ */
18
+
19
+ #include "xslt.h"
20
+
21
+ extern VALUE mXML;
22
+ extern VALUE cXSLT;
23
+
24
+ /**
25
+ * external function support, patch from :
26
+ *
27
+ * Brendan Taylor
28
+ * whateley@gmail.com
29
+ *
30
+ */
31
+
32
+
33
+ /* converts an xmlXPathObjectPtr to a Ruby VALUE
34
+ * number -> float
35
+ * boolean -> boolean
36
+ * string -> string
37
+ * nodeset -> an array of REXML::Elements
38
+ */
39
+ VALUE xpathObj2value(xmlXPathObjectPtr obj, xmlDocPtr doc)
40
+ {
41
+ VALUE ret = Qnil;
42
+
43
+ if (obj == NULL) {
44
+ return ret;
45
+ }
46
+
47
+ switch (obj->type) {
48
+ case XPATH_NODESET:
49
+ rb_require("rexml/document");
50
+ ret = rb_ary_new();
51
+
52
+ if ((obj->nodesetval != NULL) && (obj->nodesetval->nodeNr != 0)) {
53
+ xmlBufferPtr buff = xmlBufferCreate();
54
+ xmlNodePtr node;
55
+ int i;
56
+
57
+ // this assumes all the nodes are elements, which is a bad idea
58
+ for (i = 0; i < obj->nodesetval->nodeNr; i++) {
59
+ node = obj->nodesetval->nodeTab[i];
60
+
61
+ if( node->type == XML_ELEMENT_NODE ) {
62
+ xmlNodeDump(buff, doc, node, 0, 0);
63
+
64
+ VALUE cREXML = rb_const_get(rb_cObject, rb_intern("REXML"));
65
+ VALUE cDocument = rb_const_get(cREXML, rb_intern("Document"));
66
+ VALUE rDocument = rb_funcall(cDocument, rb_intern("new"), 1,rb_str_new2((char *)buff->content));
67
+ VALUE rElement = rb_funcall(rDocument, rb_intern("root"), 0);
68
+
69
+ rb_ary_push(ret, rElement);
70
+
71
+ // empty the buffer (xmlNodeDump appends rather than replaces)
72
+ xmlBufferEmpty(buff);
73
+ } else if ( node->type == XML_TEXT_NODE ) {
74
+ rb_ary_push(ret, rb_str_new2((char *)node->content));
75
+ }
76
+ }
77
+ xmlBufferFree(buff);
78
+ }
79
+ break;
80
+ case XPATH_BOOLEAN:
81
+ ret = obj->boolval ? Qtrue : Qfalse;
82
+ break;
83
+ case XPATH_NUMBER:
84
+ ret = rb_float_new(obj->floatval);
85
+ break;
86
+ case XPATH_STRING:
87
+ ret = rb_str_new2((char *) obj->stringval);
88
+ break;
89
+ /* these cases were in libxslt's python bindings, but i don't know what they are, so i'll leave them alone */
90
+ case XPATH_XSLT_TREE:
91
+ case XPATH_POINT:
92
+ case XPATH_RANGE:
93
+ case XPATH_LOCATIONSET:
94
+ default:
95
+ rb_warning("xpathObj2value: can't convert XPath object type %d to Ruby object\n", obj->type );
96
+ }
97
+ xmlXPathFreeObject(obj);
98
+ return ret;
99
+ }
100
+
101
+ /*
102
+ * converts a Ruby VALUE to an xmlXPathObjectPtr
103
+ * boolean -> boolean
104
+ * number -> number
105
+ * string -> escaped string
106
+ * array -> array of parsed nodes
107
+ */
108
+ xmlXPathObjectPtr value2xpathObj (VALUE val) {
109
+ xmlXPathObjectPtr ret = NULL;
110
+
111
+ switch (TYPE(val)) {
112
+ case T_TRUE:
113
+ case T_FALSE:
114
+ ret = xmlXPathNewBoolean(RTEST(val));
115
+ break;
116
+ case T_FIXNUM:
117
+ case T_FLOAT:
118
+ ret = xmlXPathNewFloat(NUM2DBL(val));
119
+ break;
120
+ case T_STRING:
121
+ {
122
+ xmlChar *str;
123
+
124
+ // we need the Strdup (this is the major bugfix for 0.8.1)
125
+ str = xmlStrdup((const xmlChar *) STR2CSTR(val));
126
+ ret = xmlXPathWrapString(str);
127
+ }
128
+ break;
129
+ case T_NIL:
130
+ ret = xmlXPathNewNodeSet(NULL);
131
+ break;
132
+ case T_ARRAY: {
133
+ int i,j;
134
+ ret = xmlXPathNewNodeSet(NULL);
135
+
136
+ for(i = RARRAY(val)->len; i > 0; i--) {
137
+ xmlXPathObjectPtr obj = value2xpathObj( rb_ary_shift( val ) );
138
+ if ((obj->nodesetval != NULL) && (obj->nodesetval->nodeNr != 0)) {
139
+ for(j = 0; j < obj->nodesetval->nodeNr; j++) {
140
+ xmlXPathNodeSetAdd( ret->nodesetval, obj->nodesetval->nodeTab[j] );
141
+ }
142
+ }
143
+ }
144
+ break; }
145
+ case T_DATA:
146
+ case T_OBJECT: {
147
+ if( strcmp( getRubyObjectName( val ), "REXML::Document" ) == 0 || strcmp(getRubyObjectName( val ), "REXML::Element") == 0 ) {
148
+
149
+ VALUE to_s = rb_funcall( val, rb_intern( "to_s" ), 0 );
150
+ xmlDocPtr doc = xmlParseDoc((xmlChar *) STR2CSTR(to_s));
151
+
152
+ ret = xmlXPathNewNodeSet((xmlNode *)doc->children);
153
+ break;
154
+ } else if( strcmp( getRubyObjectName( val ), "REXML::Text" ) == 0 ) {
155
+ VALUE to_s = rb_funcall( val, rb_intern( "to_s" ), 0 );
156
+
157
+ xmlChar *str;
158
+
159
+ str = xmlStrdup((const xmlChar *) STR2CSTR(to_s));
160
+ ret = xmlXPathWrapString(str);
161
+ break;
162
+ }
163
+ // this drops through so i can reuse the error message
164
+ }
165
+ default:
166
+ rb_warning( "value2xpathObj: can't convert class %s to XPath object\n", getRubyObjectName(val));
167
+ return NULL;
168
+ }
169
+
170
+ return ret;
171
+ }
172
+
173
+ /*
174
+ * chooses what registered function to call and calls it
175
+ */
176
+ void xmlXPathFuncCallback( xmlXPathParserContextPtr ctxt, int nargs) {
177
+ VALUE result, arguments[nargs];
178
+ VALUE ns_hash, func_hash, object;
179
+ const xmlChar *namespace;
180
+ char *rb_func, *chr;
181
+ xmlXPathObjectPtr obj;
182
+ int i;
183
+
184
+ if (ctxt == NULL || ctxt->context == NULL)
185
+ return;
186
+
187
+ rb_func = strdup((char *)ctxt->context->function);
188
+ namespace = ctxt->context->functionURI;
189
+
190
+ ns_hash = rb_cvar_get(cXSLT, rb_intern("@@extFunctions"));
191
+
192
+ func_hash = rb_hash_aref(ns_hash, rb_str_new2((char *)namespace));
193
+
194
+ if(func_hash == Qnil) {
195
+ rb_warning( "xmlXPathFuncCallback: namespace %s not found!\n", namespace );
196
+ }
197
+
198
+ object = rb_hash_aref(func_hash, rb_str_new2((char *)rb_func));
199
+
200
+ for (i = nargs - 1; i >= 0; i--) {
201
+ obj = valuePop(ctxt);
202
+ arguments[i] = xpathObj2value(obj, ctxt->context->doc);
203
+ }
204
+
205
+ /* -s are common in XSLT function names, but illegal for Ruby method names */
206
+ while( (chr = strchr(rb_func, '-')) != NULL ) {
207
+ chr[0] = '_'; /* so we pretend the - was a _ all along */
208
+ }
209
+
210
+ result = rb_funcall2( object, rb_intern(rb_func), nargs, arguments);
211
+
212
+ free( rb_func );
213
+
214
+ obj = value2xpathObj(result);
215
+ valuePush(ctxt, obj);
216
+ }
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Copyright (C) 2005 Gregoire Lejeune <gregoire.lejeune@free.fr>
3
+ *
4
+ * This program is free software; you can redistribute it and/or modify
5
+ * it under the terms of the GNU General Public License as published by
6
+ * the Free Software Foundation; either version 2 of the License, or
7
+ * (at your option) any later version.
8
+ *
9
+ * This program is distributed in the hope that it will be useful,
10
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ * GNU General Public License for more details.
13
+ *
14
+ * You should have received a copy of the GNU General Public License
15
+ * along with this program; if not, write to the Free Software
16
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
+ */
18
+
19
+ #include "xslt.h"
20
+
21
+ #include <libxml/xpathInternals.h>
22
+ #include <libxslt/extensions.h>
23
+
24
+ VALUE xpathObj2value( xmlXPathObjectPtr, xmlDocPtr );
25
+ xmlXPathObjectPtr value2xpathObj( VALUE );
26
+ void xmlXPathFuncCallback( xmlXPathParserContextPtr, int );
@@ -0,0 +1,59 @@
1
+ /**
2
+ * Copyright (C) 2005 Gregoire Lejeune <gregoire.lejeune@free.fr>
3
+ *
4
+ * This program is free software; you can redistribute it and/or modify
5
+ * it under the terms of the GNU General Public License as published by
6
+ * the Free Software Foundation; either version 2 of the License, or
7
+ * (at your option) any later version.
8
+ *
9
+ * This program is distributed in the hope that it will be useful,
10
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ * GNU General Public License for more details.
13
+ *
14
+ * You should have received a copy of the GNU General Public License
15
+ * along with this program; if not, write to the Free Software
16
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
+ */
18
+
19
+ #include "xslt.h"
20
+
21
+ /**
22
+ * parameters support, patch from :
23
+ *
24
+ * Eust�quio "TaQ" Rangel
25
+ * eustaquiorangel@yahoo.com
26
+ * http://beam.to/taq
27
+ *
28
+ */
29
+ VALUE each_pair( VALUE obj ) {
30
+ return rb_funcall( obj, rb_intern("each"), 0, 0 );
31
+ }
32
+
33
+ VALUE process_pair( VALUE pair, VALUE rbparams ) {
34
+ VALUE key, value;
35
+ // Thx to alex__
36
+ int count = FIX2INT( rb_funcall( rbparams, rb_intern("size"), 0, 0 ) );
37
+ // static int count = 0;
38
+ char *xValue = NULL;
39
+
40
+ Check_Type( pair, T_ARRAY );
41
+
42
+ key = RARRAY(pair)->ptr[0];
43
+ value = RARRAY(pair)->ptr[1];
44
+
45
+ Check_Type( key, T_STRING );
46
+ Check_Type( value, T_STRING );
47
+
48
+ xValue = STR2CSTR( value );
49
+ if( xValue[0] != '\'' && xValue[strlen( xValue ) - 1] != '\'' ) {
50
+ value = rb_str_concat( value, rb_str_new2( "'" ) );
51
+ value = rb_str_concat( rb_str_new2( "'" ), value );
52
+ }
53
+
54
+ rb_ary_store( rbparams, count, key );
55
+ rb_ary_store( rbparams, count + 1, value );
56
+
57
+ count += 2;
58
+ return Qnil;
59
+ }