ruby-xml-smart 0.1.11-i486-linux
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/AUTHORS +4 -0
- data/COPYING +504 -0
- data/Changelog +192 -0
- data/README +52 -0
- data/Rakefile +112 -0
- data/TODO +6 -0
- data/examples/EXAMPLE.xml +17 -0
- data/examples/EXAMPLE.xml.sic +17 -0
- data/examples/Visualise/EXAMPLE.xml +18 -0
- data/examples/Visualise/term-ansicolor-0.0.4/CHANGES +11 -0
- data/examples/Visualise/term-ansicolor-0.0.4/GPL +340 -0
- data/examples/Visualise/term-ansicolor-0.0.4/README.en +23 -0
- data/examples/Visualise/term-ansicolor-0.0.4/Rakefile +72 -0
- data/examples/Visualise/term-ansicolor-0.0.4/VERSION +1 -0
- data/examples/Visualise/term-ansicolor-0.0.4/examples/cdiff.rb +20 -0
- data/examples/Visualise/term-ansicolor-0.0.4/examples/example.rb +82 -0
- data/examples/Visualise/term-ansicolor-0.0.4/install.rb +12 -0
- data/examples/Visualise/term-ansicolor-0.0.4/lib/term/ansicolor.rb +78 -0
- data/examples/Visualise/xpath_visual.rb +45 -0
- data/examples/add_children.rb +14 -0
- data/examples/add_elements.rb +13 -0
- data/examples/attrs.rb +15 -0
- data/examples/children.rb +14 -0
- data/examples/concurrent.rb +30 -0
- data/examples/copy.rb +23 -0
- data/examples/create.rb +18 -0
- data/examples/delete.rb +30 -0
- data/examples/move_elements.rb +12 -0
- data/examples/namespace.rb +14 -0
- data/examples/namespace_detailed.rb +36 -0
- data/examples/namespace_find.rb +20 -0
- data/examples/pull.rb +18 -0
- data/examples/qname.rb +16 -0
- data/examples/replace.rb +14 -0
- data/examples/set_OR_replace.rb +32 -0
- data/examples/signals.rb +28 -0
- data/examples/string.rb +27 -0
- data/examples/write.rb +11 -0
- data/examples/xpath_attrs.rb +19 -0
- data/examples/xpath_functions.rb +7 -0
- data/examples/xpath_root.rb +6 -0
- data/extconf.rb +29 -0
- data/rbxs.c +136 -0
- data/rbxs.h +53 -0
- data/rbxs_dom.c +483 -0
- data/rbxs_dom.h +32 -0
- data/rbxs_domattribute.c +189 -0
- data/rbxs_domattribute.h +18 -0
- data/rbxs_domattributeset.c +182 -0
- data/rbxs_domattributeset.h +17 -0
- data/rbxs_domelement.c +656 -0
- data/rbxs_domelement.h +18 -0
- data/rbxs_domnamespace.c +127 -0
- data/rbxs_domnamespace.h +18 -0
- data/rbxs_domnamespaceset.c +276 -0
- data/rbxs_domnamespaceset.h +17 -0
- data/rbxs_domnodeset.c +284 -0
- data/rbxs_domnodeset.h +19 -0
- data/rbxs_domother.c +121 -0
- data/rbxs_domother.h +18 -0
- data/rbxs_domtext.c +165 -0
- data/rbxs_domtext.h +18 -0
- data/rbxs_pull.c +244 -0
- data/rbxs_pull.h +17 -0
- data/rbxs_pullattribute.c +124 -0
- data/rbxs_pullattribute.h +18 -0
- data/rbxs_pullattributeset.c +156 -0
- data/rbxs_pullattributeset.h +17 -0
- data/rbxs_qname.c +267 -0
- data/rbxs_qname.h +18 -0
- data/rbxs_utils.h +39 -0
- data/test/namespace_test.rb +83 -0
- metadata +125 -0
data/rbxs_dom.c
ADDED
@@ -0,0 +1,483 @@
|
|
1
|
+
#include "rbxs_dom.h"
|
2
|
+
#include "rbxs_domelement.h"
|
3
|
+
#include "rbxs_domnodeset.h"
|
4
|
+
|
5
|
+
#include <sys/types.h>
|
6
|
+
#include <sys/stat.h>
|
7
|
+
#include <time.h>
|
8
|
+
#include <fcntl.h>
|
9
|
+
#include <unistd.h>
|
10
|
+
|
11
|
+
/* -- */
|
12
|
+
// ***********************************************************************************
|
13
|
+
// GC
|
14
|
+
// ***********************************************************************************
|
15
|
+
void rbxs_dom_free(rbxs_dom *prbxs_dom) {
|
16
|
+
if (prbxs_dom != NULL) {
|
17
|
+
xmlFreeDoc(prbxs_dom->doc);
|
18
|
+
xmlCleanupParser();
|
19
|
+
free(prbxs_dom);
|
20
|
+
}
|
21
|
+
}
|
22
|
+
|
23
|
+
void rbxs_dom_mark(rbxs_dom *prbxs_dom) {
|
24
|
+
if (prbxs_dom == NULL) return;
|
25
|
+
if (!NIL_P(prbxs_dom->changeHandlers)) rb_gc_mark(prbxs_dom->changeHandlers);
|
26
|
+
if (!NIL_P(prbxs_dom->namespaces)) rb_gc_mark(prbxs_dom->namespaces);
|
27
|
+
}
|
28
|
+
|
29
|
+
//***********************************************************************************
|
30
|
+
// Methods
|
31
|
+
//***********************************************************************************
|
32
|
+
/* ++ */
|
33
|
+
static int nslist_each(VALUE key, VALUE value, xmlXPathContextPtr arg) {
|
34
|
+
if (xmlXPathRegisterNs(arg,(unsigned char *)StringValuePtr(key),(unsigned char *)StringValuePtr(value)) != 0) {
|
35
|
+
xmlXPathFreeContext(arg);
|
36
|
+
rb_raise(rb_eRuntimeError, "Couldn't add namespace");
|
37
|
+
}
|
38
|
+
return ST_CONTINUE;
|
39
|
+
}
|
40
|
+
|
41
|
+
static int nslistset_each(VALUE key, VALUE value) {
|
42
|
+
Check_Type(key, T_STRING);
|
43
|
+
Check_Type(value, T_STRING);
|
44
|
+
return ST_CONTINUE;
|
45
|
+
}
|
46
|
+
|
47
|
+
/*
|
48
|
+
* Documentation
|
49
|
+
*/
|
50
|
+
VALUE rbxs_dom_inspect(VALUE self)
|
51
|
+
{
|
52
|
+
VALUE *argv;
|
53
|
+
|
54
|
+
argv = ALLOCA_N(VALUE, 3);
|
55
|
+
argv[0] = rb_str_new2("#<%s:0x%x>");
|
56
|
+
argv[1] = CLASS_OF(self);
|
57
|
+
argv[2] = rb_obj_id(self);
|
58
|
+
return(rb_f_sprintf(3, argv));
|
59
|
+
}
|
60
|
+
|
61
|
+
/*
|
62
|
+
* Documentation
|
63
|
+
*/
|
64
|
+
VALUE rbxs_dom_to_s(VALUE self)
|
65
|
+
{
|
66
|
+
rbxs_dom *prbxs_dom;
|
67
|
+
xmlChar *result;
|
68
|
+
VALUE ret;
|
69
|
+
int len;
|
70
|
+
|
71
|
+
Data_Get_Struct(self, rbxs_dom, prbxs_dom);
|
72
|
+
if (prbxs_dom->doc == NULL) {
|
73
|
+
return(Qnil);
|
74
|
+
} else if (prbxs_dom->doc->encoding != NULL) {
|
75
|
+
xmlDocDumpFormatMemoryEnc(prbxs_dom->doc, &result, &len, (char *)prbxs_dom->doc->encoding, 1);
|
76
|
+
} else {
|
77
|
+
xmlDocDumpFormatMemory(prbxs_dom->doc, &result, &len, 1);
|
78
|
+
}
|
79
|
+
|
80
|
+
ret = rb_str_new2((char *)result);
|
81
|
+
xmlFree(result);
|
82
|
+
return(ret);
|
83
|
+
}
|
84
|
+
|
85
|
+
/*
|
86
|
+
* Documentation
|
87
|
+
*/
|
88
|
+
VALUE rbxs_dom_root_set(VALUE self, VALUE element)
|
89
|
+
{
|
90
|
+
rbxs_dom *prbxs_dom;
|
91
|
+
rbxs_domelement *prbxs_domelement;
|
92
|
+
xmlNodePtr root,newnode;
|
93
|
+
|
94
|
+
if (rb_obj_is_kind_of(element, cSmartDomElement)) {
|
95
|
+
Data_Get_Struct(self, rbxs_dom, prbxs_dom);
|
96
|
+
Data_Get_Struct(element, rbxs_domelement, prbxs_domelement);
|
97
|
+
newnode = xmlCopyNode(prbxs_domelement->node,1); // 1 == deep
|
98
|
+
root = xmlDocGetRootElement(prbxs_dom->doc);
|
99
|
+
xmlUnlinkNode(root);
|
100
|
+
xmlFreeNode (root);
|
101
|
+
root = xmlDocSetRootElement(prbxs_dom->doc,newnode);
|
102
|
+
if (root) {
|
103
|
+
VALUE ret = rbxs_domelement_new(cSmartDomElement, self, root);
|
104
|
+
rbxs_dom_change_handlers_execute(prbxs_dom,RBXS_DOM_SIGNAL_CHANGE,ret);
|
105
|
+
return(ret);
|
106
|
+
}
|
107
|
+
} else
|
108
|
+
rb_raise(rb_eArgError, "takes an element as argument");
|
109
|
+
return(Qnil);
|
110
|
+
}
|
111
|
+
|
112
|
+
/*
|
113
|
+
* Documentation
|
114
|
+
*/
|
115
|
+
VALUE rbxs_dom_encode_entities_set(VALUE self, VALUE value)
|
116
|
+
{
|
117
|
+
rbxs_dom *prbxs_dom;
|
118
|
+
Data_Get_Struct(self, rbxs_dom, prbxs_dom);
|
119
|
+
switch (TYPE(value)) {
|
120
|
+
case T_FALSE:
|
121
|
+
prbxs_dom->encodeEntities = 0;
|
122
|
+
return Qfalse;
|
123
|
+
case T_TRUE:
|
124
|
+
prbxs_dom->encodeEntities = 1;
|
125
|
+
return Qtrue;
|
126
|
+
default:
|
127
|
+
rb_raise(rb_eArgError, "can be set to TRUE or FALSE");
|
128
|
+
}
|
129
|
+
}
|
130
|
+
|
131
|
+
/*
|
132
|
+
* Documentation
|
133
|
+
*/
|
134
|
+
VALUE rbxs_dom_encode_entities_q(VALUE self)
|
135
|
+
{
|
136
|
+
rbxs_dom *prbxs_dom;
|
137
|
+
Data_Get_Struct(self, rbxs_dom, prbxs_dom);
|
138
|
+
if (prbxs_dom->encodeEntities == 0)
|
139
|
+
return(Qfalse);
|
140
|
+
else
|
141
|
+
return(Qtrue);
|
142
|
+
}
|
143
|
+
|
144
|
+
/*
|
145
|
+
* Documentation
|
146
|
+
*/
|
147
|
+
VALUE rbxs_dom_root(VALUE self)
|
148
|
+
{
|
149
|
+
rbxs_dom *prbxs_dom;
|
150
|
+
xmlNodePtr root;
|
151
|
+
|
152
|
+
Data_Get_Struct(self, rbxs_dom, prbxs_dom);
|
153
|
+
root = xmlDocGetRootElement(prbxs_dom->doc);
|
154
|
+
if (root)
|
155
|
+
return(rbxs_domelement_new(cSmartDomElement, self, root));
|
156
|
+
else
|
157
|
+
return(Qnil);
|
158
|
+
}
|
159
|
+
|
160
|
+
/*
|
161
|
+
* Documentation
|
162
|
+
*/
|
163
|
+
VALUE rbxs_dom_save_as(VALUE self, VALUE file)
|
164
|
+
{
|
165
|
+
Check_Type(file, T_FILE);
|
166
|
+
rb_io_write(file,rbxs_dom_to_s(self));
|
167
|
+
return(Qtrue);
|
168
|
+
}
|
169
|
+
|
170
|
+
/*
|
171
|
+
* Documentation
|
172
|
+
*/
|
173
|
+
VALUE rbxs_dom_find(int argc, VALUE *argv, VALUE self)
|
174
|
+
{
|
175
|
+
rbxs_dom *prbxs_dom;
|
176
|
+
xmlXPathContextPtr ctxt;
|
177
|
+
xmlXPathObjectPtr obj;
|
178
|
+
xmlNodePtr root;
|
179
|
+
VALUE set;
|
180
|
+
|
181
|
+
if (argc > 2 || argc < 1)
|
182
|
+
rb_raise(rb_eArgError, "wrong number of arguments (need 1 or 2)");
|
183
|
+
Check_Type(argv[0], T_STRING);
|
184
|
+
|
185
|
+
Data_Get_Struct(self, rbxs_dom, prbxs_dom);
|
186
|
+
|
187
|
+
ctxt = xmlXPathNewContext(prbxs_dom->doc);
|
188
|
+
if(ctxt == NULL)
|
189
|
+
rb_raise(rb_eRuntimeError, "Couldn't create XPath context");
|
190
|
+
root = xmlDocGetRootElement(prbxs_dom->doc);
|
191
|
+
ctxt->node = root->parent;
|
192
|
+
|
193
|
+
if (argc == 2) {
|
194
|
+
Check_Type(argv[1], T_HASH);
|
195
|
+
if (!RHASH_EMPTY_P(argv[1]))
|
196
|
+
rb_hash_foreach(argv[1], nslist_each, (st_data_t)ctxt);
|
197
|
+
}
|
198
|
+
if (!RHASH_EMPTY_P(prbxs_dom->namespaces))
|
199
|
+
rb_hash_foreach(prbxs_dom->namespaces, nslist_each, (st_data_t)ctxt);
|
200
|
+
|
201
|
+
obj = xmlXPathEvalExpression((unsigned char *)StringValuePtr(argv[0]), ctxt);
|
202
|
+
ctxt->node = NULL;
|
203
|
+
if(obj == NULL) {
|
204
|
+
xmlXPathFreeContext(ctxt);
|
205
|
+
rb_raise(rb_eRuntimeError, "Error in xpath");
|
206
|
+
}
|
207
|
+
switch (obj->type) {
|
208
|
+
case XPATH_NODESET:
|
209
|
+
set = rbxs_domnodeset_new(cSmartDomNodeSet,self,obj);
|
210
|
+
break;
|
211
|
+
case XPATH_BOOLEAN:
|
212
|
+
set = obj->boolval > 0 ? Qtrue : Qfalse;
|
213
|
+
xmlXPathFreeObject(obj);
|
214
|
+
break;
|
215
|
+
case XPATH_NUMBER:
|
216
|
+
set = rb_float_new(obj->floatval);
|
217
|
+
xmlXPathFreeObject(obj);
|
218
|
+
break;
|
219
|
+
case XPATH_STRING:
|
220
|
+
set = rb_str_new2((char *)obj->stringval);
|
221
|
+
xmlXPathFreeObject(obj);
|
222
|
+
break;
|
223
|
+
default:
|
224
|
+
set = Qnil;
|
225
|
+
}
|
226
|
+
xmlXPathFreeContext(ctxt);
|
227
|
+
|
228
|
+
return set;
|
229
|
+
}
|
230
|
+
|
231
|
+
/*
|
232
|
+
* Documentation
|
233
|
+
*/
|
234
|
+
VALUE rbxs_dom_change_handler_set(VALUE self)
|
235
|
+
{
|
236
|
+
rbxs_dom *prbxs_dom;
|
237
|
+
|
238
|
+
Data_Get_Struct(self, rbxs_dom, prbxs_dom);
|
239
|
+
if (!rb_block_given_p())
|
240
|
+
rb_raise(rb_eArgError, "you need to supply a block with #on_change");
|
241
|
+
|
242
|
+
rb_ary_push(prbxs_dom->changeHandlers,rb_block_proc());
|
243
|
+
return(Qtrue);
|
244
|
+
}
|
245
|
+
|
246
|
+
|
247
|
+
/*
|
248
|
+
* Documentation
|
249
|
+
*/
|
250
|
+
VALUE rbxs_dom_change_handlers(VALUE self)
|
251
|
+
{
|
252
|
+
rbxs_dom *prbxs_dom;
|
253
|
+
Data_Get_Struct(self, rbxs_dom, prbxs_dom);
|
254
|
+
return(prbxs_dom->changeHandlers);
|
255
|
+
}
|
256
|
+
|
257
|
+
/*
|
258
|
+
* Documentation
|
259
|
+
*/
|
260
|
+
VALUE rbxs_dom_namespaces_get(VALUE self)
|
261
|
+
{
|
262
|
+
rbxs_dom *prbxs_dom;
|
263
|
+
Data_Get_Struct(self, rbxs_dom, prbxs_dom);
|
264
|
+
rb_ary_push(prbxs_dom->changeHandlers,rb_block_proc());
|
265
|
+
return(prbxs_dom->namespaces);
|
266
|
+
}
|
267
|
+
/*
|
268
|
+
* Documentation
|
269
|
+
*/
|
270
|
+
VALUE rbxs_dom_namespaces_set(VALUE self, VALUE ns)
|
271
|
+
{
|
272
|
+
rbxs_dom *prbxs_dom;
|
273
|
+
Data_Get_Struct(self, rbxs_dom, prbxs_dom);
|
274
|
+
Check_Type(ns, T_HASH);
|
275
|
+
if (!RHASH_EMPTY_P(ns))
|
276
|
+
rb_hash_foreach(ns, nslistset_each, Qnil);
|
277
|
+
prbxs_dom->namespaces = ns;
|
278
|
+
return(Qnil);
|
279
|
+
}
|
280
|
+
|
281
|
+
void rbxs_dom_change_handlers_execute(rbxs_dom *prbxs_dom, unsigned short int type, VALUE node) {
|
282
|
+
long i;
|
283
|
+
for (i = 0; i < RARRAY_LEN(prbxs_dom->changeHandlers); i++) {
|
284
|
+
VALUE args = rb_ary_new2(2);
|
285
|
+
|
286
|
+
VALUE e = RARRAY_PTR(prbxs_dom->changeHandlers)[i];
|
287
|
+
rb_ary_push(args,INT2FIX(type));
|
288
|
+
rb_ary_push(args,node);
|
289
|
+
rb_eval_cmd(e,args,1);
|
290
|
+
}
|
291
|
+
}
|
292
|
+
|
293
|
+
//***********************************************************************************
|
294
|
+
// Constructors
|
295
|
+
//***********************************************************************************
|
296
|
+
VALUE rbxs_dom_string(VALUE string) {
|
297
|
+
rbxs_dom *prbxs_dom;
|
298
|
+
xmlParserCtxtPtr ctxt;
|
299
|
+
|
300
|
+
Check_Type(string, T_STRING);
|
301
|
+
|
302
|
+
prbxs_dom = (rbxs_dom *)malloc(sizeof(rbxs_dom));
|
303
|
+
if (prbxs_dom == NULL)
|
304
|
+
rb_raise(rb_eNoMemError, "No memory left for XML::Smart::Dom struct");
|
305
|
+
|
306
|
+
xmlInitParser();
|
307
|
+
|
308
|
+
ctxt = xmlCreateMemoryParserCtxt(StringValuePtr(string),strlen(StringValuePtr(string)));
|
309
|
+
if (ctxt == NULL)
|
310
|
+
rb_sys_fail(StringValuePtr(string));
|
311
|
+
|
312
|
+
if (xmlParseDocument(ctxt) == -1) {
|
313
|
+
xmlFreeDoc(ctxt->myDoc);
|
314
|
+
xmlFreeParserCtxt(ctxt);
|
315
|
+
rb_raise(rb_eRuntimeError, "Document didn't parse");
|
316
|
+
}
|
317
|
+
|
318
|
+
if (!ctxt->wellFormed) {
|
319
|
+
xmlFreeDoc(ctxt->myDoc);
|
320
|
+
xmlFreeParserCtxt(ctxt);
|
321
|
+
ctxt = NULL;
|
322
|
+
rb_raise(rb_eRuntimeError, "Document is not wellformed");
|
323
|
+
}
|
324
|
+
|
325
|
+
prbxs_dom->type = RBXS_DOM_TYPE_STRING;
|
326
|
+
prbxs_dom->lock = 0;
|
327
|
+
prbxs_dom->changeHandlers = rb_ary_new2(0);
|
328
|
+
prbxs_dom->namespaces = rb_hash_new();
|
329
|
+
prbxs_dom->encodeEntities = 1;
|
330
|
+
prbxs_dom->doc = ctxt->myDoc;
|
331
|
+
|
332
|
+
xmlFreeParserCtxt(ctxt);
|
333
|
+
|
334
|
+
return(Data_Wrap_Struct(cSmartDom, rbxs_dom_mark, rbxs_dom_free, prbxs_dom));
|
335
|
+
}
|
336
|
+
|
337
|
+
VALUE rbxs_dom_open(VALUE name, char *root, unsigned short int lock, unsigned short int save) {
|
338
|
+
rbxs_dom *prbxs_dom;
|
339
|
+
xmlParserCtxtPtr ctxt;
|
340
|
+
char *lockfile;
|
341
|
+
|
342
|
+
ctxt = NULL;
|
343
|
+
lockfile = NULL;
|
344
|
+
|
345
|
+
if ((!rb_block_given_p()) && save>0)
|
346
|
+
rb_raise(rb_eArgError, "you need to supply a block with #modify");
|
347
|
+
|
348
|
+
prbxs_dom = (rbxs_dom *)malloc(sizeof(rbxs_dom));
|
349
|
+
if (prbxs_dom == NULL)
|
350
|
+
rb_raise(rb_eNoMemError, "No memory left for XML::Smart::Dom struct");
|
351
|
+
|
352
|
+
if (root != NULL) {
|
353
|
+
int fd;
|
354
|
+
fd = open(StringValuePtr(name), O_CREAT|O_EXCL|O_WRONLY, S_IRUSR|S_IWUSR);
|
355
|
+
if (fd < 0) {
|
356
|
+
if (errno != EEXIST)
|
357
|
+
rb_raise(rb_eRuntimeError, "Failed to create new file");
|
358
|
+
} else {
|
359
|
+
char *wr;
|
360
|
+
wr = (char *)calloc(strlen("<?xml version='1.0'?>\n") + strlen(root) + 1,sizeof(char));
|
361
|
+
strncat(wr,"<?xml version='1.0'?>\n",strlen("<?xml version='1.0'?>\n"));
|
362
|
+
strncat(wr,root,strlen(root));
|
363
|
+
if (!(write(fd,wr,strlen(wr)) > 0))
|
364
|
+
rb_raise(rb_eRuntimeError, "Failed to write new file");
|
365
|
+
free(wr);
|
366
|
+
}
|
367
|
+
close(fd);
|
368
|
+
}
|
369
|
+
|
370
|
+
if (save > 0 && lock > 0) {
|
371
|
+
struct stat buffer;
|
372
|
+
lockfile = (char *)calloc(strlen(StringValuePtr(name)) + 6,sizeof(char));
|
373
|
+
strncat(lockfile,StringValuePtr(name),strlen(StringValuePtr(name)));
|
374
|
+
strncat(lockfile,".lock",5);
|
375
|
+
int fd;
|
376
|
+
do {
|
377
|
+
fd = open(lockfile, O_CREAT|O_EXCL, S_IRUSR|S_IWUSR);
|
378
|
+
if (fd < 0) {
|
379
|
+
if (errno != EEXIST) {
|
380
|
+
xmlFreeDoc(ctxt->myDoc);
|
381
|
+
ctxt = NULL;
|
382
|
+
free(lockfile);
|
383
|
+
rb_raise(rb_eRuntimeError, "Failed to create lockfile");
|
384
|
+
} else {
|
385
|
+
stat(lockfile, &buffer);
|
386
|
+
if (buffer.st_mtime < time(NULL) - lock)
|
387
|
+
unlink(lockfile);
|
388
|
+
}
|
389
|
+
}
|
390
|
+
rb_thread_polling();
|
391
|
+
} while (fd < 0);
|
392
|
+
close(fd);
|
393
|
+
}
|
394
|
+
|
395
|
+
xmlInitParser();
|
396
|
+
ctxt = xmlCreateFileParserCtxt(StringValuePtr(name));
|
397
|
+
|
398
|
+
prbxs_dom->type = RBXS_DOM_TYPE_FILE;
|
399
|
+
prbxs_dom->encodeEntities = 1;
|
400
|
+
prbxs_dom->changeHandlers = rb_ary_new2(0);
|
401
|
+
prbxs_dom->namespaces = rb_hash_new();
|
402
|
+
prbxs_dom->lock = lock;
|
403
|
+
|
404
|
+
if (ctxt == NULL) {
|
405
|
+
if (save>0 && prbxs_dom->lock>0) {
|
406
|
+
unlink(lockfile);
|
407
|
+
free(lockfile);
|
408
|
+
}
|
409
|
+
rb_sys_fail(StringValuePtr(name));
|
410
|
+
}
|
411
|
+
|
412
|
+
if (xmlParseDocument(ctxt) == -1) {
|
413
|
+
if (save>0 && prbxs_dom->lock>0) {
|
414
|
+
unlink(lockfile);
|
415
|
+
free(lockfile);
|
416
|
+
}
|
417
|
+
xmlFreeDoc(ctxt->myDoc);
|
418
|
+
xmlFreeParserCtxt(ctxt);
|
419
|
+
rb_raise(rb_eRuntimeError, "Document didn't parse");
|
420
|
+
}
|
421
|
+
|
422
|
+
if (!ctxt->wellFormed) {
|
423
|
+
if (save>0 && prbxs_dom->lock>0) {
|
424
|
+
unlink(lockfile);
|
425
|
+
free(lockfile);
|
426
|
+
}
|
427
|
+
xmlFreeDoc(ctxt->myDoc);
|
428
|
+
xmlFreeParserCtxt(ctxt);
|
429
|
+
ctxt = NULL;
|
430
|
+
rb_raise(rb_eRuntimeError, "Document is not wellformed");
|
431
|
+
}
|
432
|
+
|
433
|
+
prbxs_dom->doc = ctxt->myDoc;
|
434
|
+
xmlFreeParserCtxt(ctxt);
|
435
|
+
xmlCleanupParser(); // Hmmm, no problem to call it as this point
|
436
|
+
|
437
|
+
if (rb_block_given_p()) {
|
438
|
+
rb_yield(Data_Wrap_Struct(cSmartDom, rbxs_dom_mark, rbxs_dom_free, prbxs_dom));
|
439
|
+
if (save > 0) {
|
440
|
+
int status = -1;
|
441
|
+
status = xmlSaveFormatFile(StringValuePtr(name), prbxs_dom->doc, 1);
|
442
|
+
if (prbxs_dom->lock > 0) {
|
443
|
+
unlink(lockfile);
|
444
|
+
free(lockfile);
|
445
|
+
}
|
446
|
+
if (status == -1)
|
447
|
+
rb_raise(rb_eRuntimeError, "Unable to write file back to disk");
|
448
|
+
}
|
449
|
+
return(Qnil);
|
450
|
+
}
|
451
|
+
|
452
|
+
return(Data_Wrap_Struct(cSmartDom, rbxs_dom_mark, rbxs_dom_free, prbxs_dom));
|
453
|
+
}
|
454
|
+
|
455
|
+
//***********************************************************************************
|
456
|
+
// Initialize module and class
|
457
|
+
//***********************************************************************************
|
458
|
+
#ifdef RDOC__
|
459
|
+
mXML = rb_define_module( "XML" );
|
460
|
+
cSmart = rb_define_class_under( mXML, "Smart", rb_cObject );
|
461
|
+
#endif
|
462
|
+
VALUE cSmartDom;
|
463
|
+
|
464
|
+
void init_rbxs_dom( void ) {
|
465
|
+
cSmartDom = rb_define_class_under( cSmart, "Dom", rb_cObject );
|
466
|
+
|
467
|
+
rb_define_const(cSmartDom, "SIGNAL_ADD", INT2NUM(RBXS_DOM_SIGNAL_ADD ));
|
468
|
+
rb_define_const(cSmartDom, "SIGNAL_CHANGE", INT2NUM(RBXS_DOM_SIGNAL_CHANGE));
|
469
|
+
rb_define_const(cSmartDom, "SIGNAL_DELETE", INT2NUM(RBXS_DOM_SIGNAL_DELETE));
|
470
|
+
|
471
|
+
rb_define_method(cSmartDom, "inspect", rbxs_dom_inspect, 0);
|
472
|
+
rb_define_method(cSmartDom, "to_s", rbxs_dom_to_s, 0);
|
473
|
+
rb_define_method(cSmartDom, "root", rbxs_dom_root, 0);
|
474
|
+
rb_define_method(cSmartDom, "root=", rbxs_dom_root_set, 1);
|
475
|
+
rb_define_method(cSmartDom, "find", rbxs_dom_find, -1);
|
476
|
+
rb_define_method(cSmartDom, "on_change", rbxs_dom_change_handler_set, 0);
|
477
|
+
rb_define_method(cSmartDom, "change_handlers", rbxs_dom_change_handlers, 0);
|
478
|
+
rb_define_method(cSmartDom, "save_as", rbxs_dom_save_as, 1);
|
479
|
+
rb_define_method(cSmartDom, "namespaces=", rbxs_dom_namespaces_set, 1);
|
480
|
+
rb_define_method(cSmartDom, "namespaces", rbxs_dom_namespaces_get, 0);
|
481
|
+
rb_define_method(cSmartDom, "encode_entities=", rbxs_dom_encode_entities_set, 1);
|
482
|
+
rb_define_method(cSmartDom, "encode_entities?", rbxs_dom_encode_entities_q, 0);
|
483
|
+
}
|
data/rbxs_dom.h
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
/* Please see the COPYING file for copyright and distribution information */
|
2
|
+
|
3
|
+
#ifndef __RBXS_DOM_H__
|
4
|
+
#define __RBXS_DOM_H__
|
5
|
+
|
6
|
+
#include "rbxs.h"
|
7
|
+
|
8
|
+
#define RBXS_DOM_TYPE_STRING 0
|
9
|
+
#define RBXS_DOM_TYPE_FILE 1
|
10
|
+
|
11
|
+
#define RBXS_DOM_SIGNAL_ADD 0
|
12
|
+
#define RBXS_DOM_SIGNAL_CHANGE 1
|
13
|
+
#define RBXS_DOM_SIGNAL_DELETE 2
|
14
|
+
|
15
|
+
RUBY_EXTERN VALUE cSmartDom;
|
16
|
+
|
17
|
+
typedef struct rbxs_dom {
|
18
|
+
unsigned short int encodeEntities;
|
19
|
+
int type;
|
20
|
+
unsigned short int lock;
|
21
|
+
xmlDocPtr doc;
|
22
|
+
VALUE changeHandlers;
|
23
|
+
VALUE namespaces;
|
24
|
+
} rbxs_dom;
|
25
|
+
|
26
|
+
void rbxs_dom_change_handlers_execute(rbxs_dom *prbxs_dom, unsigned short int type, VALUE node);
|
27
|
+
|
28
|
+
RUBY_EXTERN VALUE rbxs_dom_open(VALUE name, char *root, unsigned short int lock, unsigned short int save);
|
29
|
+
RUBY_EXTERN VALUE rbxs_dom_string(VALUE string);
|
30
|
+
RUBY_EXTERN void init_rbxs_dom(void);
|
31
|
+
|
32
|
+
#endif
|
data/rbxs_domattribute.c
ADDED
@@ -0,0 +1,189 @@
|
|
1
|
+
#include "rbxs_domattribute.h"
|
2
|
+
#include "rbxs_domelement.h"
|
3
|
+
#include "rbxs_dom.h"
|
4
|
+
|
5
|
+
/* -- */
|
6
|
+
//***********************************************************************************
|
7
|
+
// GC
|
8
|
+
//***********************************************************************************
|
9
|
+
void rbxs_domattribute_free(rbxs_domattribute *prbxs_domattribute) {
|
10
|
+
if (prbxs_domattribute != NULL) {
|
11
|
+
free(prbxs_domattribute);
|
12
|
+
}
|
13
|
+
}
|
14
|
+
|
15
|
+
void rbxs_domattribute_mark(rbxs_domattribute *prbxs_domattribute) {
|
16
|
+
if (prbxs_domattribute == NULL) return;
|
17
|
+
if (!NIL_P(prbxs_domattribute->doc)) rb_gc_mark(prbxs_domattribute->doc);
|
18
|
+
}
|
19
|
+
|
20
|
+
//***********************************************************************************
|
21
|
+
// Methods
|
22
|
+
//***********************************************************************************
|
23
|
+
/* ++ */
|
24
|
+
|
25
|
+
/*
|
26
|
+
* Documentation
|
27
|
+
*/
|
28
|
+
VALUE rbxs_domattribute_inspect(VALUE self)
|
29
|
+
{
|
30
|
+
rbxs_domattribute *prbxs_domattribute;
|
31
|
+
xmlBufferPtr ret;
|
32
|
+
VALUE *argv;
|
33
|
+
|
34
|
+
argv = ALLOCA_N(VALUE, 4);
|
35
|
+
argv[0] = rb_str_new2("#<%s:0x%x @%s>");
|
36
|
+
argv[1] = CLASS_OF(self);
|
37
|
+
argv[2] = rb_obj_id(self);
|
38
|
+
|
39
|
+
Data_Get_Struct(self, rbxs_domattribute, prbxs_domattribute);
|
40
|
+
ret = xmlBufferCreate();
|
41
|
+
xmlNodeDump(ret, prbxs_domattribute->attribute->doc, (xmlNodePtr)prbxs_domattribute->attribute, 0, 1);
|
42
|
+
argv[3] = rb_str_new2((char *)ret->content);
|
43
|
+
argv[3] = rb_str_substr(argv[3],1,RSTRING_LEN(argv[3]));
|
44
|
+
|
45
|
+
xmlBufferFree(ret);
|
46
|
+
return(rb_f_sprintf(4, argv));
|
47
|
+
}
|
48
|
+
|
49
|
+
/*
|
50
|
+
* Documentation
|
51
|
+
*/
|
52
|
+
VALUE rbxs_domattribute_value_get(VALUE self)
|
53
|
+
{
|
54
|
+
rbxs_domattribute *prbxs_domattribute;
|
55
|
+
xmlChar *ret;
|
56
|
+
VALUE val;
|
57
|
+
|
58
|
+
Data_Get_Struct(self, rbxs_domattribute, prbxs_domattribute);
|
59
|
+
ret = xmlGetProp(prbxs_domattribute->attribute->parent,prbxs_domattribute->attribute->name);
|
60
|
+
val = rb_str_new2((char *)ret);
|
61
|
+
xmlFree(ret);
|
62
|
+
return(val);
|
63
|
+
}
|
64
|
+
|
65
|
+
/*
|
66
|
+
* Documentation
|
67
|
+
*/
|
68
|
+
VALUE rbxs_domattribute_path(VALUE self)
|
69
|
+
{
|
70
|
+
rbxs_domattribute *prbxs_domattribute;
|
71
|
+
xmlChar *ret;
|
72
|
+
VALUE val;
|
73
|
+
|
74
|
+
Data_Get_Struct(self, rbxs_domattribute, prbxs_domattribute);
|
75
|
+
ret = xmlGetNodePath((xmlNodePtr)prbxs_domattribute->attribute);
|
76
|
+
val = rb_str_new2((char *)ret);
|
77
|
+
xmlFree(ret);
|
78
|
+
return(val);
|
79
|
+
}
|
80
|
+
|
81
|
+
/*
|
82
|
+
* Documentation
|
83
|
+
*/
|
84
|
+
VALUE rbxs_domattribute_to_i(int argc, VALUE *argv, VALUE self)
|
85
|
+
{
|
86
|
+
VALUE b;
|
87
|
+
int base;
|
88
|
+
|
89
|
+
rb_scan_args(argc, argv, "01", &b);
|
90
|
+
if (argc == 0) base = 10;
|
91
|
+
else base = NUM2INT(b);
|
92
|
+
|
93
|
+
if (base < 0)
|
94
|
+
rb_raise(rb_eArgError, "illegal radix %d", base);
|
95
|
+
return(rb_str_to_inum(rbxs_domattribute_value_get(self),base,Qfalse));
|
96
|
+
}
|
97
|
+
|
98
|
+
/*
|
99
|
+
* Documentation
|
100
|
+
*/
|
101
|
+
VALUE rbxs_domattribute_to_f(VALUE self)
|
102
|
+
{
|
103
|
+
return rb_float_new(rb_str_to_dbl(rbxs_domattribute_value_get(self), Qfalse));
|
104
|
+
}
|
105
|
+
|
106
|
+
/*
|
107
|
+
* Documentation
|
108
|
+
*/
|
109
|
+
VALUE rbxs_domattribute_name_get(VALUE self)
|
110
|
+
{
|
111
|
+
rbxs_domattribute *prbxs_domattribute;
|
112
|
+
Data_Get_Struct(self, rbxs_domattribute, prbxs_domattribute);
|
113
|
+
return(rb_str_new2((char *)prbxs_domattribute->attribute->name));
|
114
|
+
}
|
115
|
+
|
116
|
+
/*
|
117
|
+
* Documentation
|
118
|
+
*/
|
119
|
+
VALUE rbxs_domattribute_value_set(VALUE self, VALUE value)
|
120
|
+
{
|
121
|
+
rbxs_domattribute *prbxs_domattribute;
|
122
|
+
rbxs_dom *prbxs_dom;
|
123
|
+
unsigned char *tc;
|
124
|
+
VALUE str;
|
125
|
+
|
126
|
+
Data_Get_Struct(self, rbxs_domattribute, prbxs_domattribute);
|
127
|
+
Data_Get_Struct(prbxs_domattribute->doc, rbxs_dom, prbxs_dom);
|
128
|
+
|
129
|
+
str = rb_obj_as_string(value);
|
130
|
+
if (NIL_P(str) || TYPE(str) != T_STRING)
|
131
|
+
rb_raise(rb_eTypeError, "cannot convert obj to string");
|
132
|
+
tc = (unsigned char *)StringValuePtr(str);
|
133
|
+
if (!xmlCheckUTF8(tc))
|
134
|
+
rb_raise(rb_eArgError, "text must be utf8 encoded");
|
135
|
+
xmlNodeSetContent((xmlNodePtr)prbxs_domattribute->attribute,tc);
|
136
|
+
|
137
|
+
rbxs_dom_change_handlers_execute(prbxs_dom,RBXS_DOM_SIGNAL_CHANGE,self);
|
138
|
+
return(value);
|
139
|
+
}
|
140
|
+
|
141
|
+
/*
|
142
|
+
* Documentation
|
143
|
+
*/
|
144
|
+
VALUE rbxs_domattribute_element(VALUE self)
|
145
|
+
{
|
146
|
+
rbxs_domattribute *prbxs_domattribute;
|
147
|
+
Data_Get_Struct(self, rbxs_domattribute, prbxs_domattribute);
|
148
|
+
return(rbxs_domelement_new(cSmartDomElement,prbxs_domattribute->doc,prbxs_domattribute->attribute->parent));
|
149
|
+
}
|
150
|
+
|
151
|
+
//***********************************************************************************
|
152
|
+
// Constructors
|
153
|
+
//***********************************************************************************
|
154
|
+
VALUE rbxs_domattribute_new(VALUE class, VALUE doc, xmlAttrPtr attribute) {
|
155
|
+
rbxs_domattribute *prbxs_domattribute;
|
156
|
+
|
157
|
+
prbxs_domattribute = (rbxs_domattribute *)malloc(sizeof(rbxs_domattribute));
|
158
|
+
if (prbxs_domattribute == NULL )
|
159
|
+
rb_raise(rb_eNoMemError, "No memory left for XML::Smart::Dom::Attribute struct");
|
160
|
+
|
161
|
+
prbxs_domattribute->doc = doc;
|
162
|
+
prbxs_domattribute->attribute = attribute;
|
163
|
+
|
164
|
+
return(Data_Wrap_Struct(class, rbxs_domattribute_mark, rbxs_domattribute_free, prbxs_domattribute));
|
165
|
+
}
|
166
|
+
|
167
|
+
//***********************************************************************************
|
168
|
+
// Initialize class Node
|
169
|
+
//***********************************************************************************
|
170
|
+
#ifdef RDOC__
|
171
|
+
mXML = rb_define_module( "XML" );
|
172
|
+
cSmart = rb_define_class_under( mXML, "Smart", rb_cObject );
|
173
|
+
cSmartDom = rb_define_class_under( cSmart, "Dom", rb_cObject );
|
174
|
+
#endif
|
175
|
+
VALUE cSmartDomAttribute;
|
176
|
+
|
177
|
+
void init_rbxs_domattribute(void) {
|
178
|
+
cSmartDomAttribute = rb_define_class_under( cSmartDom, "Attribute", rb_cObject );
|
179
|
+
|
180
|
+
rb_define_method(cSmartDomAttribute, "inspect", rbxs_domattribute_inspect, 0);
|
181
|
+
rb_define_method(cSmartDomAttribute, "to_s", rbxs_domattribute_value_get, 0);
|
182
|
+
rb_define_method(cSmartDomAttribute, "to_i", rbxs_domattribute_to_i, -1);
|
183
|
+
rb_define_method(cSmartDomAttribute, "to_f", rbxs_domattribute_to_f, 0);
|
184
|
+
rb_define_method(cSmartDomAttribute, "name", rbxs_domattribute_name_get, 0);
|
185
|
+
rb_define_method(cSmartDomAttribute, "path", rbxs_domattribute_path, 0);
|
186
|
+
rb_define_method(cSmartDomAttribute, "value", rbxs_domattribute_value_get, 0);
|
187
|
+
rb_define_method(cSmartDomAttribute, "value=", rbxs_domattribute_value_set, 1);
|
188
|
+
rb_define_method(cSmartDomAttribute, "element", rbxs_domattribute_element, 0);
|
189
|
+
}
|