xml-smart 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (64) hide show
  1. data/AUTHORS +4 -0
  2. data/COPYING +504 -0
  3. data/README.rdoc +55 -0
  4. data/Rakefile +15 -0
  5. data/example/EXAMPLE.xml +18 -0
  6. data/example/xpath_visual.rb +54 -0
  7. data/lib/xml/XSDtoRNG.xsl +448 -0
  8. data/lib/xml/smart.rb +177 -0
  9. data/lib/xml/smart_dom.rb +118 -0
  10. data/lib/xml/smart_domattribute.rb +34 -0
  11. data/lib/xml/smart_domattributeset.rb +62 -0
  12. data/lib/xml/smart_domelement.rb +213 -0
  13. data/lib/xml/smart_domnamespace.rb +32 -0
  14. data/lib/xml/smart_domnamespaceset.rb +125 -0
  15. data/lib/xml/smart_domnodeset.rb +59 -0
  16. data/lib/xml/smart_domother.rb +16 -0
  17. data/lib/xml/smart_domtext.rb +25 -0
  18. data/lib/xml/smart_qname.rb +34 -0
  19. data/test/1.xml +1 -0
  20. data/test/2.xml +1 -0
  21. data/test/3.xml +1 -0
  22. data/test/EXAMPLE-NS.xml +18 -0
  23. data/test/EXAMPLE-NSE.xml +18 -0
  24. data/test/EXAMPLE.str.xml +6 -0
  25. data/test/EXAMPLE.str.xml.test +6 -0
  26. data/test/EXAMPLE.tmp.xml +4 -0
  27. data/test/EXAMPLE.tmp.xml.test +4 -0
  28. data/test/EXAMPLE.xml +17 -0
  29. data/test/HELLO-MORE.xml +1 -0
  30. data/test/HELLO.rng +9 -0
  31. data/test/HELLO.xml +8 -0
  32. data/test/HELLO.xsd +16 -0
  33. data/test/XSL_BASE.xml +17 -0
  34. data/test/XSL_BASE.xml.test +16 -0
  35. data/test/XSL_DOCUMENT.xml +48 -0
  36. data/test/concurrent.xml +1 -0
  37. data/test/smartrunner.rb +25 -0
  38. data/test/tc_add.rb +21 -0
  39. data/test/tc_basic.rb +108 -0
  40. data/test/tc_concurrent.rb +73 -0
  41. data/test/tc_copy.rb +41 -0
  42. data/test/tc_create.rb +32 -0
  43. data/test/tc_delete.rb +52 -0
  44. data/test/tc_move_elements.rb +24 -0
  45. data/test/tc_namespace_default.rb +70 -0
  46. data/test/tc_namespace_detailed.rb +44 -0
  47. data/test/tc_namespace_find.rb +22 -0
  48. data/test/tc_nested.rb +26 -0
  49. data/test/tc_qname.rb +30 -0
  50. data/test/tc_relaxng.rb +30 -0
  51. data/test/tc_set_or_replace.rb +57 -0
  52. data/test/tc_sort.rb +18 -0
  53. data/test/tc_string.rb +41 -0
  54. data/test/tc_todoc.rb +27 -0
  55. data/test/tc_write.rb +19 -0
  56. data/test/tc_xinclude.rb +26 -0
  57. data/test/tc_xmlschema.rb +30 -0
  58. data/test/tc_xpath.rb +16 -0
  59. data/test/tc_xpath_attrs.rb +24 -0
  60. data/test/tc_xpath_functions.rb +12 -0
  61. data/test/tc_xpath_root.rb +23 -0
  62. data/test/tc_xsl.rb +22 -0
  63. data/xml-smart.gemspec +26 -0
  64. metadata +201 -0
@@ -0,0 +1,448 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <!--
3
+ Copyright or © or Copr. Nicolas Debeissat
4
+
5
+ nicolas.debeissat@gmail.com (http://debeissat.nicolas.free.fr/)
6
+
7
+ This software is a computer program whose purpose is to convert a
8
+ XSD schema into a RelaxNG schema.
9
+
10
+ This software is governed by the CeCILL license under French law and
11
+ abiding by the rules of distribution of free software. You can use,
12
+ modify and/ or redistribute the software under the terms of the CeCILL
13
+ license as circulated by CEA, CNRS and INRIA at the following URL
14
+ "http://www.cecill.info".
15
+
16
+ As a counterpart to the access to the source code and rights to copy,
17
+ modify and redistribute granted by the license, users are provided only
18
+ with a limited warranty and the software's author, the holder of the
19
+ economic rights, and the successive licensors have only limited
20
+ liability.
21
+
22
+ In this respect, the user's attention is drawn to the risks associated
23
+ with loading, using, modifying and/or developing or reproducing the
24
+ software by the user in light of its specific status of free software,
25
+ that may mean that it is complicated to manipulate, and that also
26
+ therefore means that it is reserved for developers and experienced
27
+ professionals having in-depth computer knowledge. Users are therefore
28
+ encouraged to load and test the software's suitability as regards their
29
+ requirements in conditions enabling the security of their systems and/or
30
+ data to be ensured and, more generally, to use and operate it in the
31
+ same conditions as regards security.
32
+
33
+ The fact that you are presently reading this means that you have had
34
+ knowledge of the CeCILL license and that you accept its terms.
35
+
36
+ -->
37
+ <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:rng="http://relaxng.org/ns/structure/1.0" xmlns:a="http://relaxng.org/ns/compatibility/annotations/1.0" exclude-result-prefixes="xs" version="1.0">
38
+
39
+ <xsl:output indent="yes" method="xml"/>
40
+
41
+ <xsl:preserve-space elements="*"/>
42
+
43
+ <xsl:template match="/xs:schema">
44
+ <rng:grammar>
45
+ <xsl:for-each select="namespace::*">
46
+ <xsl:if test="local-name() != 'xs'">
47
+ <xsl:copy/>
48
+ </xsl:if>
49
+ </xsl:for-each>
50
+ <xsl:attribute name="ns"><xsl:value-of select="@targetNamespace"/></xsl:attribute>
51
+ <xsl:attribute name="datatypeLibrary">http://www.w3.org/2001/XMLSchema-datatypes</xsl:attribute>
52
+ <xsl:apply-templates/>
53
+ </rng:grammar>
54
+ </xsl:template>
55
+
56
+ <!-- in order to manage occurrences (and defaut) attributes goes there
57
+ before going to mode="content" templates -->
58
+ <xsl:template match="xs:*">
59
+ <xsl:call-template name="occurrences"/>
60
+ </xsl:template>
61
+
62
+ <xsl:template match="comment()">
63
+ <xsl:copy/>
64
+ </xsl:template>
65
+
66
+ <!-- unique and key are not supported in RelaxNG, must be done in schematron -->
67
+ <xsl:template match="xs:unique|xs:key"/>
68
+
69
+ <xsl:template match="xs:annotation">
70
+ <a:documentation>
71
+ <xsl:apply-templates/>
72
+ </a:documentation>
73
+ </xsl:template>
74
+
75
+ <xsl:template match="xs:documentation">
76
+ <xsl:copy-of select="child::node()"/>
77
+ </xsl:template>
78
+
79
+ <xsl:template match="xs:appinfo">
80
+ <xsl:copy-of select="child::node()"/>
81
+ </xsl:template>
82
+
83
+ <xsl:template match="xs:union">
84
+ <rng:choice>
85
+ <xsl:apply-templates select="@memberTypes"/>
86
+ <xsl:apply-templates/>
87
+ </rng:choice>
88
+ </xsl:template>
89
+
90
+ <xsl:template match="@memberTypes">
91
+ <xsl:call-template name="declareMemberTypes">
92
+ <xsl:with-param name="memberTypes" select="."/>
93
+ </xsl:call-template>
94
+ </xsl:template>
95
+
96
+ <xsl:template match="xs:list">
97
+ <rng:list>
98
+ <xsl:apply-templates select="@itemType"/>
99
+ <xsl:apply-templates/>
100
+ </rng:list>
101
+ </xsl:template>
102
+
103
+ <xsl:template match="@itemType">
104
+ <xsl:call-template name="type">
105
+ <xsl:with-param name="type" select="."/>
106
+ </xsl:call-template>
107
+ </xsl:template>
108
+
109
+ <xsl:template match="xs:complexType[@name]|xs:simpleType[@name]|xs:group[@name]|xs:attributeGroup[@name]">
110
+ <!-- the schemas may be included several times, so it needs a combine attribute
111
+ (the attributes are inversed :-) at the transformation) -->
112
+ <rng:define name="{@name}">
113
+ <!-- work-around for empty issue -->
114
+ <xsl:choose>
115
+ <xsl:when test="not(*[local-name() != 'annotation'])">
116
+ <rng:empty/>
117
+ <xsl:apply-templates/>
118
+ </xsl:when>
119
+ <xsl:otherwise>
120
+ <xsl:apply-templates/>
121
+ </xsl:otherwise>
122
+ </xsl:choose>
123
+ </rng:define>
124
+ </xsl:template>
125
+
126
+ <!-- when finds a ref attribute replace it by its type call (ref name="" or type) -->
127
+ <xsl:template match="xs:*[@ref]" mode="content">
128
+ <!-- when finds a attribute declaraction with a ref attribute replace it by
129
+ its type call prefixed by attr_ -->
130
+ <xsl:choose>
131
+ <xsl:when test="local-name() = 'attribute'">
132
+ <xsl:variable name="type">
133
+ <xsl:choose>
134
+ <xsl:when test="contains(@ref, ':')">
135
+ <xsl:value-of select="concat('attr_', substring-after(@ref, ':'))"/>
136
+ </xsl:when>
137
+ <xsl:otherwise>
138
+ <xsl:value-of select="concat('attr_', @ref)"/>
139
+ </xsl:otherwise>
140
+ </xsl:choose>
141
+ </xsl:variable>
142
+ <xsl:call-template name="type">
143
+ <xsl:with-param name="type" select="$type"/>
144
+ </xsl:call-template>
145
+ </xsl:when>
146
+ <xsl:otherwise>
147
+ <xsl:call-template name="type">
148
+ <xsl:with-param name="type" select="@ref"/>
149
+ </xsl:call-template>
150
+ </xsl:otherwise>
151
+ </xsl:choose>
152
+ </xsl:template>
153
+
154
+ <!-- the <xs:simpleType> and <xs:complexType without name attribute are ignored -->
155
+ <xsl:template match="xs:sequence|xs:simpleContent|xs:complexContent|xs:simpleType|xs:complexType">
156
+ <xsl:apply-templates/>
157
+ </xsl:template>
158
+
159
+ <xsl:template match="xs:extension[@base]">
160
+ <xsl:call-template name="type">
161
+ <xsl:with-param name="type" select="@base"/>
162
+ </xsl:call-template>
163
+ </xsl:template>
164
+
165
+ <xsl:template match="xs:element[@name]">
166
+ <!-- case of root element -->
167
+ <xsl:choose>
168
+ <xsl:when test="parent::xs:schema">
169
+ <rng:start combine="choice">
170
+ <!-- must introduce prefix in order not to override a complextype of the same name -->
171
+ <rng:ref name="starting_{@name}"/>
172
+ </rng:start>
173
+ <rng:define name="starting_{@name}">
174
+ <xsl:apply-templates select="current()" mode="content"/>
175
+ </rng:define>
176
+ </xsl:when>
177
+ <xsl:otherwise>
178
+ <xsl:call-template name="occurrences"/>
179
+ </xsl:otherwise>
180
+ </xsl:choose>
181
+ </xsl:template>
182
+
183
+ <xsl:template match="xs:restriction[@base]">
184
+ <xsl:choose>
185
+ <xsl:when test="xs:enumeration[@value]">
186
+ <rng:choice>
187
+ <xsl:apply-templates/>
188
+ </rng:choice>
189
+ </xsl:when>
190
+ <xsl:otherwise>
191
+ <xsl:call-template name="type">
192
+ <xsl:with-param name="type" select="@base"/>
193
+ </xsl:call-template>
194
+ </xsl:otherwise>
195
+ </xsl:choose>
196
+ </xsl:template>
197
+
198
+ <xsl:template match="xs:enumeration[@value]">
199
+ <rng:value>
200
+ <xsl:value-of select="@value"/>
201
+ </rng:value>
202
+ <xsl:apply-templates/>
203
+ </xsl:template>
204
+
205
+ <!--
206
+ support for fractionDigits, length, maxExclusive, maxInclusive, maxLength, minExclusive, minInclusive, minLength, pattern, totalDigits, whiteSpace
207
+ explicit removal of enumeration as not all the XSLT processor respect templates priority
208
+ -->
209
+ <xsl:template match="xs:*[not(self::xs:enumeration)][@value]">
210
+ <rng:param name="{local-name()}">
211
+ <xsl:value-of select="@value"/>
212
+ </rng:param>
213
+ </xsl:template>
214
+
215
+ <xsl:template match="xs:all">
216
+ <rng:interleave>
217
+ <xsl:for-each select="child::text()[normalize-space(.) != ''] | child::*">
218
+ <rng:optional>
219
+ <xsl:apply-templates select="current()"/>
220
+ </rng:optional>
221
+ </xsl:for-each>
222
+ </rng:interleave>
223
+ </xsl:template>
224
+
225
+ <xsl:template match="xs:import|xs:include|xs:redefine">
226
+ <rng:include>
227
+ <xsl:if test="@schemaLocation">
228
+ <xsl:attribute name="href"><xsl:value-of select="concat(substring-before(@schemaLocation, '.xsd'),'.rng')"/></xsl:attribute>
229
+ </xsl:if>
230
+ <xsl:if test="@namespace">
231
+ <xsl:attribute name="ns"><xsl:value-of select="@namespace"/></xsl:attribute>
232
+ </xsl:if>
233
+ <xsl:apply-templates/>
234
+ </rng:include>
235
+ </xsl:template>
236
+
237
+ <xsl:template match="@default">
238
+ <a:documentation>
239
+ default value is : <xsl:value-of select="."/>
240
+ </a:documentation>
241
+ </xsl:template>
242
+
243
+ <xsl:template match="xs:attribute[@name]">
244
+ <xsl:choose>
245
+ <!-- attributes specified at schema level -->
246
+ <xsl:when test="parent::xs:schema">
247
+ <rng:define name="attr_{@name}">
248
+ <xsl:apply-templates select="current()" mode="occurrences"/>
249
+ </rng:define>
250
+ </xsl:when>
251
+ <xsl:otherwise>
252
+ <xsl:apply-templates select="current()" mode="occurrences"/>
253
+ </xsl:otherwise>
254
+ </xsl:choose>
255
+ </xsl:template>
256
+
257
+ <xsl:template match="xs:attribute[@name]" mode="occurrences">
258
+ <xsl:choose>
259
+ <xsl:when test="@use and @use='prohibited'"/>
260
+ <xsl:when test="@use and @use='required'">
261
+ <xsl:apply-templates select="current()" mode="content"/>
262
+ </xsl:when>
263
+ <!-- by default, attributes are optional -->
264
+ <xsl:otherwise>
265
+ <rng:optional>
266
+ <xsl:apply-templates select="current()" mode="content"/>
267
+ </rng:optional>
268
+ </xsl:otherwise>
269
+ </xsl:choose>
270
+ </xsl:template>
271
+
272
+ <xsl:template match="xs:attribute[@name]" mode="content">
273
+ <rng:attribute name="{@name}">
274
+ <xsl:apply-templates select="@default" mode="attributeDefaultValue"/>
275
+ <!-- there can be no type attribute to <xs:attribute>, in this case, the type is defined in
276
+ a <xs:simpleType> or a <xs:complexType> inside -->
277
+ <xsl:choose>
278
+ <xsl:when test="@type">
279
+ <xsl:call-template name="type">
280
+ <xsl:with-param name="type" select="@type"/>
281
+ </xsl:call-template>
282
+ </xsl:when>
283
+ <xsl:otherwise>
284
+ <xsl:apply-templates/>
285
+ </xsl:otherwise>
286
+ </xsl:choose>
287
+ </rng:attribute>
288
+ </xsl:template>
289
+
290
+ <xsl:template match="@default" mode="attributeDefaultValue">
291
+ <xsl:attribute name="defaultValue" namespace="http://relaxng.org/ns/compatibility/annotations/1.0">
292
+ <xsl:value-of select="."/>
293
+ </xsl:attribute>
294
+ </xsl:template>
295
+
296
+ <xsl:template match="xs:any" mode="content">
297
+ <rng:element>
298
+ <rng:anyName/>
299
+ <rng:text/>
300
+ </rng:element>
301
+ </xsl:template>
302
+
303
+ <xsl:template match="xs:anyAttribute" mode="content">
304
+ <rng:attribute>
305
+ <rng:anyName/>
306
+ <rng:text/>
307
+ </rng:attribute>
308
+ </xsl:template>
309
+
310
+ <xsl:template match="xs:choice" mode="content">
311
+ <rng:choice>
312
+ <xsl:apply-templates/>
313
+ </rng:choice>
314
+ </xsl:template>
315
+
316
+ <xsl:template match="xs:element" mode="content">
317
+ <rng:element name="{@name}">
318
+ <xsl:choose>
319
+ <xsl:when test="@type">
320
+ <xsl:call-template name="type">
321
+ <xsl:with-param name="type" select="@type"/>
322
+ </xsl:call-template>
323
+ </xsl:when>
324
+ <!-- work-around for empty issue -->
325
+ <xsl:when test="not(*[local-name() != 'annotation']) and not(@type)">
326
+ <rng:empty/>
327
+ <xsl:apply-templates/>
328
+ </xsl:when>
329
+ <xsl:otherwise>
330
+ <xsl:apply-templates/>
331
+ </xsl:otherwise>
332
+ </xsl:choose>
333
+ </rng:element>
334
+ </xsl:template>
335
+
336
+ <xsl:template name="occurrences">
337
+ <xsl:apply-templates select="@default"/>
338
+ <xsl:choose>
339
+ <xsl:when test="@maxOccurs and @maxOccurs='unbounded'">
340
+ <xsl:choose>
341
+ <xsl:when test="@minOccurs and @minOccurs='0'">
342
+ <rng:zeroOrMore>
343
+ <xsl:apply-templates select="current()" mode="content"/>
344
+ </rng:zeroOrMore>
345
+ </xsl:when>
346
+ <xsl:otherwise>
347
+ <rng:oneOrMore>
348
+ <xsl:apply-templates select="current()" mode="content"/>
349
+ </rng:oneOrMore>
350
+ </xsl:otherwise>
351
+ </xsl:choose>
352
+ </xsl:when>
353
+ <xsl:when test="@minOccurs and @minOccurs='0'">
354
+ <rng:optional>
355
+ <xsl:apply-templates select="current()" mode="content"/>
356
+ </rng:optional>
357
+ </xsl:when>
358
+ <!-- here minOccurs is present but not = 0 -->
359
+ <xsl:when test="@minOccurs">
360
+ <xsl:call-template name="loopUntilZero">
361
+ <xsl:with-param name="nbLoops" select="@minOccurs"/>
362
+ </xsl:call-template>
363
+ </xsl:when>
364
+ <xsl:otherwise>
365
+ <xsl:apply-templates select="current()" mode="content"/>
366
+ </xsl:otherwise>
367
+ </xsl:choose>
368
+ </xsl:template>
369
+
370
+ <xsl:template name="loopUntilZero">
371
+ <xsl:param name="nbLoops"/>
372
+ <xsl:if test="$nbLoops > 0">
373
+ <xsl:apply-templates select="current()" mode="content"/>
374
+ <xsl:call-template name="loopUntilZero">
375
+ <xsl:with-param name="nbLoops" select="$nbLoops - 1"/>
376
+ </xsl:call-template>
377
+ </xsl:if>
378
+ </xsl:template>
379
+
380
+ <xsl:template name="type">
381
+ <xsl:param name="type"/>
382
+ <xsl:choose>
383
+ <xsl:when test="contains($type, 'anyType')">
384
+ <rng:data type="string">
385
+ <xsl:apply-templates/>
386
+ </rng:data>
387
+ </xsl:when>
388
+ <!-- have to improve the prefix detection -->
389
+ <xsl:when test="starts-with($type, 'xs:') or starts-with($type, 'xsd:')">
390
+ <rng:data type="{substring-after($type, ':')}">
391
+ <!-- xsltproc tries to apply templates on current attributes -->
392
+ <xsl:apply-templates select="*"/>
393
+ </rng:data>
394
+ </xsl:when>
395
+ <xsl:when test="starts-with($type, 'xml:')">
396
+ <xsl:variable name="localName" select="substring-after($type, ':')"/>
397
+ <rng:attribute name="{$localName}" ns="http://www.w3.org/XML/1998/namespace">
398
+ <xsl:choose>
399
+ <xsl:when test="$localName='lang'">
400
+ <rng:value type="language"/>
401
+ </xsl:when>
402
+ <xsl:when test="$localName='space'">
403
+ <rng:choice>
404
+ <rng:value>default</rng:value>
405
+ <rng:value>preserve</rng:value>
406
+ </rng:choice>
407
+ </xsl:when>
408
+ <xsl:otherwise>
409
+ <rng:text/>
410
+ </xsl:otherwise>
411
+ </xsl:choose>
412
+ </rng:attribute>
413
+ </xsl:when>
414
+ <xsl:otherwise>
415
+ <xsl:choose>
416
+ <xsl:when test="contains($type, ':')">
417
+ <rng:ref name="{substring-after($type, ':')}"/>
418
+ <xsl:apply-templates/>
419
+ </xsl:when>
420
+ <xsl:otherwise>
421
+ <rng:ref name="{$type}"/>
422
+ <xsl:apply-templates/>
423
+ </xsl:otherwise>
424
+ </xsl:choose>
425
+ </xsl:otherwise>
426
+ </xsl:choose>
427
+ </xsl:template>
428
+
429
+ <xsl:template name="declareMemberTypes">
430
+ <xsl:param name="memberTypes"/>
431
+ <xsl:choose>
432
+ <xsl:when test="contains($memberTypes, ' ')">
433
+ <xsl:call-template name="type">
434
+ <xsl:with-param name="type" select="substring-before($memberTypes, ' ')"/>
435
+ </xsl:call-template>
436
+ <xsl:call-template name="declareMemberTypes">
437
+ <xsl:with-param name="memberTypes" select="substring-after($memberTypes, ' ')"/>
438
+ </xsl:call-template>
439
+ </xsl:when>
440
+ <xsl:otherwise>
441
+ <xsl:call-template name="type">
442
+ <xsl:with-param name="type" select="$memberTypes"/>
443
+ </xsl:call-template>
444
+ </xsl:otherwise>
445
+ </xsl:choose>
446
+ </xsl:template>
447
+
448
+ </xsl:stylesheet>
data/lib/xml/smart.rb ADDED
@@ -0,0 +1,177 @@
1
+ require 'rubygems'
2
+ require 'nokogiri'
3
+ require 'lockfile'
4
+
5
+ require File.expand_path(File.dirname(__FILE__) + '/smart_qname')
6
+ require File.expand_path(File.dirname(__FILE__) + '/smart_dom')
7
+ require File.expand_path(File.dirname(__FILE__) + '/smart_domelement')
8
+ require File.expand_path(File.dirname(__FILE__) + '/smart_domnodeset')
9
+ require File.expand_path(File.dirname(__FILE__) + '/smart_domtext')
10
+ require File.expand_path(File.dirname(__FILE__) + '/smart_domother')
11
+ require File.expand_path(File.dirname(__FILE__) + '/smart_domattributeset')
12
+ require File.expand_path(File.dirname(__FILE__) + '/smart_domattribute')
13
+ require File.expand_path(File.dirname(__FILE__) + '/smart_domnamespaceset')
14
+ require File.expand_path(File.dirname(__FILE__) + '/smart_domnamespace')
15
+
16
+ module Nokogiri
17
+ module XML
18
+ class Document
19
+ def ns_counter
20
+ @ns_counter ||= 1
21
+ end
22
+ def ns_update
23
+ @ns_counter ||= 1
24
+ @ns_counter += 1
25
+ self
26
+ end
27
+
28
+ def custom_namespace_prefixes_update
29
+ result = {}
30
+
31
+ diffs = []
32
+ ns = self.xpath('//namespace::*').to_a.delete_if do |n|
33
+ if diffs.include? n.href
34
+ true
35
+ else
36
+ diffs.push(n.href).uniq!
37
+ false
38
+ end
39
+ end
40
+
41
+ de = ns.find_all{|n| n.prefix.nil?}
42
+ if de.length == 1
43
+ result['xmlns'] = de[0].href
44
+ end
45
+ if de.length > 1
46
+ i = 0
47
+ de.each do |n|
48
+ unless result.has_value? n.href
49
+ result["xmlns#{i}"] = n.href
50
+ i += 1
51
+ end
52
+ end
53
+ end
54
+
55
+ ns.find_all{|n| !n.prefix.nil? && !(n.prefix == 'xml')}.each do |n|
56
+ result[n.prefix] = n.href
57
+ end
58
+ @custom_namespace_prefixes = result
59
+ end
60
+ def custom_namespace_prefixes
61
+ @custom_namespace_prefixes || custom_namespace_prefixes_update
62
+ end
63
+ def user_custom_namespace_prefixes
64
+ @user_custom_namespace_prefixes ||= {}
65
+ end
66
+ def user_custom_namespace_prefixes=(h)
67
+ @user_custom_namespace_prefixes = h
68
+ end
69
+ end
70
+
71
+ class Node
72
+ def xpath_plain(path)
73
+ XPathContext.new(self).evaluate(path)
74
+ end
75
+ def xpath_fast(path)
76
+ return xpath(path,self.document.custom_namespace_prefixes.merge(self.document.user_custom_namespace_prefixes))
77
+ return NodeSet.new(document) unless document
78
+ @nsc ||= 0
79
+ if @nsc != self.document.ns_counter
80
+ @ctx = XPathContext.new(self)
81
+ @ctx.register_namespaces(self.document.custom_namespace_prefixes.merge(self.document.user_custom_namespace_prefixes))
82
+ @nsc = self.document.ns_counter
83
+ end
84
+ path = path.gsub(/xmlns:/, ' :') unless Nokogiri.uses_libxml?
85
+ @ctx.evaluate(path)
86
+ end
87
+ end
88
+ end
89
+ end
90
+
91
+ module XML
92
+ VERSION = '0.3.0'
93
+ LIBXML_VERSION = Nokogiri::VERSION_INFO['libxml']['loaded']
94
+ LOCKFILE = {
95
+ :min_sleep => 0.25,
96
+ :max_sleep => 5,
97
+ :sleep_inc => 0.25,
98
+ :max_age => 5
99
+ }
100
+
101
+ module Smart
102
+ COPY = 0
103
+ MOVE = 1
104
+
105
+ def initialize(name,default=nil); open(name,default); end
106
+
107
+ def self::modify(name,default=nil,&block)
108
+ raise Error, 'first parameter has to be a filename or filehandle' unless name.is_a?(String) || name.is_a?(IO)
109
+ raise Error, 'a block is mandatory' unless block_given?
110
+ lfname = name.is_a?(String) ? name : name.fileno.to_s
111
+ lockfile = Lockfile.new(lfname + '.lock',LOCKFILE)
112
+ begin
113
+ lockfile.lock
114
+ so = Smart::open_unprotected(name,default)
115
+ block.call(so)
116
+ so.save_as(name)
117
+ ensure
118
+ lockfile.unlock
119
+ end
120
+ nil
121
+ end
122
+
123
+ def self::open(name,default=nil)
124
+ raise Error, 'first parameter has to be a filename or filehandle' unless name.is_a?(String) || name.is_a?(IO)
125
+ raise Error, 'second parameter has to be an xml string' unless default.is_a?(String) || default.nil?
126
+ lfname = name.is_a?(String) ? name : name.fileno.to_s
127
+ lockfile = Lockfile.new(lfname + '.lock',LOCKFILE)
128
+ dom = nil
129
+ begin
130
+ lockfile.lock
131
+ dom = Smart::open_unprotected(name,default)
132
+ ensure
133
+ lockfile.unlock
134
+ end
135
+ if dom && block_given?
136
+ yield dom
137
+ nil
138
+ else
139
+ dom
140
+ end
141
+ end
142
+
143
+ def self::open_unprotected(name,default=nil)
144
+ raise Error, 'first parameter has to be a filename or filehandle' unless name.is_a?(String) || name.is_a?(IO)
145
+ raise Error, 'second parameter has to be an xml string' unless default.is_a?(String) || default.nil?
146
+ dom = begin
147
+ io = name.is_a?(String) ? ::Kernel::open(name) : name
148
+ Dom.new Nokogiri::XML::parse(io){|config| config.noblanks.noent.nsclean.strict }
149
+ rescue
150
+ if default.nil?
151
+ raise Error, "could not open #{name}"
152
+ else
153
+ Smart::string(default)
154
+ end
155
+ end
156
+ if block_given?
157
+ yield dom
158
+ nil
159
+ else
160
+ dom
161
+ end
162
+ end
163
+
164
+ def self::string(str)
165
+ raise Error, 'first parameter has to be stringable (:to_s)' unless str.is_a?(String)
166
+ dom = Dom.new Nokogiri::XML::parse(str.to_s){|config| config.noblanks.noent.nsclean.strict }
167
+ if block_given?
168
+ yield dom
169
+ nil
170
+ else
171
+ dom
172
+ end
173
+ end
174
+
175
+ class Error < RuntimeError; end
176
+ end
177
+ end