xml-smart 0.3.0

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.
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