rgen 0.3.0 → 0.4.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 (145) hide show
  1. data/CHANGELOG +20 -1
  2. data/MIT-LICENSE +1 -1
  3. data/README +12 -9
  4. data/lib/instantiators/ea_instantiator.rb +36 -0
  5. data/lib/metamodels/uml13_metamodel.rb +559 -0
  6. data/lib/metamodels/uml13_metamodel_ext.rb +26 -0
  7. data/lib/mmgen/metamodel_generator.rb +5 -5
  8. data/lib/mmgen/mm_ext/ecore_ext.rb +95 -0
  9. data/lib/mmgen/mmgen.rb +6 -4
  10. data/lib/mmgen/templates/annotations.tpl +37 -0
  11. data/lib/mmgen/templates/metamodel_generator.tpl +171 -0
  12. data/lib/rgen/ecore/ecore.rb +190 -0
  13. data/lib/rgen/ecore/ecore_instantiator.rb +25 -0
  14. data/lib/rgen/ecore/ecore_transformer.rb +85 -0
  15. data/lib/rgen/environment.rb +9 -24
  16. data/lib/rgen/find_helper.rb +68 -0
  17. data/lib/rgen/{instantiator.rb → instantiator/abstract_instantiator.rb} +6 -2
  18. data/lib/rgen/instantiator/abstract_xml_instantiator.rb +59 -0
  19. data/lib/rgen/instantiator/default_xml_instantiator.rb +117 -0
  20. data/lib/rgen/instantiator/ecore_xml_instantiator.rb +144 -0
  21. data/lib/rgen/instantiator/nodebased_xml_instantiator.rb +157 -0
  22. data/lib/rgen/instantiator/xmi11_instantiator.rb +164 -0
  23. data/lib/rgen/metamodel_builder.rb +103 -9
  24. data/lib/rgen/metamodel_builder/build_helper.rb +26 -4
  25. data/lib/rgen/metamodel_builder/builder_extensions.rb +285 -88
  26. data/lib/rgen/metamodel_builder/builder_runtime.rb +7 -1
  27. data/lib/rgen/metamodel_builder/data_types.rb +67 -0
  28. data/lib/rgen/metamodel_builder/intermediate/annotation.rb +30 -0
  29. data/lib/rgen/metamodel_builder/metamodel_description.rb +232 -0
  30. data/lib/rgen/metamodel_builder/mm_multiple.rb +23 -0
  31. data/lib/rgen/metamodel_builder/module_extension.rb +33 -0
  32. data/lib/rgen/model_comparator.rb +56 -0
  33. data/lib/rgen/model_dumper.rb +5 -5
  34. data/lib/rgen/name_helper.rb +17 -1
  35. data/lib/rgen/template_language.rb +148 -28
  36. data/lib/rgen/template_language/directory_template_container.rb +56 -38
  37. data/lib/rgen/template_language/output_handler.rb +93 -77
  38. data/lib/rgen/template_language/template_container.rb +186 -143
  39. data/lib/rgen/transformer.rb +19 -14
  40. data/lib/transformers/uml13_to_ecore.rb +75 -0
  41. data/redist/xmlscan/ChangeLog +1301 -0
  42. data/redist/xmlscan/README +34 -0
  43. data/redist/xmlscan/THANKS +11 -0
  44. data/redist/xmlscan/doc/changes.html +74 -0
  45. data/redist/xmlscan/doc/changes.rd +80 -0
  46. data/redist/xmlscan/doc/en/conformance.html +136 -0
  47. data/redist/xmlscan/doc/en/conformance.rd +152 -0
  48. data/redist/xmlscan/doc/en/manual.html +356 -0
  49. data/redist/xmlscan/doc/en/manual.rd +402 -0
  50. data/redist/xmlscan/doc/ja/conformance.ja.html +118 -0
  51. data/redist/xmlscan/doc/ja/conformance.ja.rd +134 -0
  52. data/redist/xmlscan/doc/ja/manual.ja.html +325 -0
  53. data/redist/xmlscan/doc/ja/manual.ja.rd +370 -0
  54. data/redist/xmlscan/doc/src/Makefile +41 -0
  55. data/redist/xmlscan/doc/src/conformance.rd.src +256 -0
  56. data/redist/xmlscan/doc/src/langsplit.rb +110 -0
  57. data/redist/xmlscan/doc/src/manual.rd.src +614 -0
  58. data/redist/xmlscan/install.rb +41 -0
  59. data/redist/xmlscan/lib/xmlscan/encoding.rb +311 -0
  60. data/redist/xmlscan/lib/xmlscan/htmlscan.rb +289 -0
  61. data/redist/xmlscan/lib/xmlscan/namespace.rb +352 -0
  62. data/redist/xmlscan/lib/xmlscan/parser.rb +299 -0
  63. data/redist/xmlscan/lib/xmlscan/scanner.rb +1109 -0
  64. data/redist/xmlscan/lib/xmlscan/version.rb +22 -0
  65. data/redist/xmlscan/lib/xmlscan/visitor.rb +158 -0
  66. data/redist/xmlscan/lib/xmlscan/xmlchar.rb +441 -0
  67. data/redist/xmlscan/memo/CONFORMANCE +1249 -0
  68. data/redist/xmlscan/memo/PRODUCTIONS +195 -0
  69. data/redist/xmlscan/memo/contentspec.ry +335 -0
  70. data/redist/xmlscan/samples/chibixml.rb +105 -0
  71. data/redist/xmlscan/samples/getxmlchar.rb +122 -0
  72. data/redist/xmlscan/samples/rexml.rb +159 -0
  73. data/redist/xmlscan/samples/xmlbench.rb +88 -0
  74. data/redist/xmlscan/samples/xmlbench/parser/chibixml.rb +22 -0
  75. data/redist/xmlscan/samples/xmlbench/parser/nqxml.rb +29 -0
  76. data/redist/xmlscan/samples/xmlbench/parser/rexml.rb +62 -0
  77. data/redist/xmlscan/samples/xmlbench/parser/xmlparser.rb +22 -0
  78. data/redist/xmlscan/samples/xmlbench/parser/xmlscan-0.0.10.rb +62 -0
  79. data/redist/xmlscan/samples/xmlbench/parser/xmlscan-chibixml.rb +22 -0
  80. data/redist/xmlscan/samples/xmlbench/parser/xmlscan-rexml.rb +22 -0
  81. data/redist/xmlscan/samples/xmlbench/parser/xmlscan.rb +99 -0
  82. data/redist/xmlscan/samples/xmlbench/xmlbench-lib.rb +116 -0
  83. data/redist/xmlscan/samples/xmlconftest.rb +200 -0
  84. data/redist/xmlscan/test.rb +7 -0
  85. data/redist/xmlscan/tests/deftestcase.rb +73 -0
  86. data/redist/xmlscan/tests/runtest.rb +47 -0
  87. data/redist/xmlscan/tests/testall.rb +14 -0
  88. data/redist/xmlscan/tests/testencoding.rb +438 -0
  89. data/redist/xmlscan/tests/testhtmlscan.rb +752 -0
  90. data/redist/xmlscan/tests/testnamespace.rb +457 -0
  91. data/redist/xmlscan/tests/testparser.rb +591 -0
  92. data/redist/xmlscan/tests/testscanner.rb +1749 -0
  93. data/redist/xmlscan/tests/testxmlchar.rb +143 -0
  94. data/redist/xmlscan/tests/visitor.rb +34 -0
  95. data/test/array_extensions_test.rb +2 -2
  96. data/test/ea_instantiator_test.rb +41 -0
  97. data/test/ecore_self_test.rb +53 -0
  98. data/test/environment_test.rb +11 -6
  99. data/test/metamodel_builder_test.rb +404 -245
  100. data/test/metamodel_roundtrip_test.rb +52 -0
  101. data/test/metamodel_roundtrip_test/TestModel.rb +65 -0
  102. data/test/metamodel_roundtrip_test/TestModel_Regenerated.rb +64 -0
  103. data/test/metamodel_roundtrip_test/houseMetamodel.ecore +32 -0
  104. data/test/metamodel_roundtrip_test/houseMetamodel_from_ecore.rb +39 -0
  105. data/test/rgen_test.rb +3 -3
  106. data/test/template_language_test.rb +65 -39
  107. data/test/template_language_test/expected_result.txt +24 -3
  108. data/test/template_language_test/templates/code/array.tpl +11 -0
  109. data/test/template_language_test/templates/content/author.tpl +7 -0
  110. data/test/template_language_test/templates/content/chapter.tpl +1 -1
  111. data/test/template_language_test/templates/root.tpl +17 -8
  112. data/test/template_language_test/testout.txt +24 -3
  113. data/test/testmodel/class_model_checker.rb +119 -0
  114. data/test/{xmi_instantiator_test/testmodel.eap → testmodel/ea_testmodel.eap} +0 -0
  115. data/test/{xmi_instantiator_test/testmodel.xml → testmodel/ea_testmodel.xml} +81 -14
  116. data/test/testmodel/ea_testmodel_partial.xml +317 -0
  117. data/test/testmodel/ecore_model_checker.rb +101 -0
  118. data/test/testmodel/manual_testmodel.xml +22 -0
  119. data/test/testmodel/object_model_checker.rb +67 -0
  120. data/test/transformer_test.rb +18 -10
  121. data/test/xml_instantiator_test.rb +81 -8
  122. data/test/xml_instantiator_test/simple_ecore_model_checker.rb +94 -0
  123. data/test/xml_instantiator_test/simple_xmi_ecore_instantiator.rb +53 -0
  124. data/test/xml_instantiator_test/simple_xmi_metamodel.rb +49 -0
  125. data/test/xml_instantiator_test/simple_xmi_to_ecore.rb +75 -0
  126. metadata +126 -28
  127. data/lib/ea/xmi_class_instantiator.rb +0 -46
  128. data/lib/ea/xmi_helper.rb +0 -26
  129. data/lib/ea/xmi_metamodel.rb +0 -34
  130. data/lib/ea/xmi_object_instantiator.rb +0 -46
  131. data/lib/ea/xmi_to_classmodel.rb +0 -78
  132. data/lib/ea/xmi_to_objectmodel.rb +0 -92
  133. data/lib/mmgen/mm_ext/uml_classmodel_ext.rb +0 -71
  134. data/lib/mmgen/templates/uml_classmodel.tpl +0 -63
  135. data/lib/rgen/xml_instantiator.rb +0 -132
  136. data/lib/uml/objectmodel_instantiator.rb +0 -53
  137. data/lib/uml/uml_classmodel.rb +0 -92
  138. data/lib/uml/uml_objectmodel.rb +0 -65
  139. data/test/metamodel_generator_test.rb +0 -44
  140. data/test/metamodel_generator_test/TestModel.rb +0 -40
  141. data/test/metamodel_generator_test/expected_result.txt +0 -40
  142. data/test/xmi_class_instantiator_test.rb +0 -24
  143. data/test/xmi_instantiator_test/class_model_checker.rb +0 -97
  144. data/test/xmi_object_instantiator_test.rb +0 -65
  145. data/test/xml_instantiator_test/testmodel.xml +0 -7
@@ -0,0 +1,352 @@
1
+ #
2
+ # xmlscan/namespace.rb
3
+ #
4
+ # Copyright (C) Ueno Katsuhiro 2002
5
+ #
6
+ # $Id: namespace.rb,v 1.13 2003/01/22 13:06:18 katsu Exp $
7
+ #
8
+
9
+ require 'xmlscan/parser'
10
+
11
+
12
+ module XMLScan
13
+
14
+ class NSParseError < ParseError ; end
15
+ class NSNotWellFormedError < NotWellFormedError ; end
16
+ class NSNotValidError < NotValidError ; end
17
+
18
+
19
+ module NSVisitor
20
+
21
+ include Visitor
22
+
23
+ def ns_parse_error(msg)
24
+ raise NSParseError.new(msg)
25
+ end
26
+
27
+ def ns_wellformed_error(msg)
28
+ raise NSNotWellFormedError.new(msg)
29
+ end
30
+
31
+ def ns_valid_error(msg)
32
+ raise NSNotValidError.new(msg)
33
+ end
34
+
35
+ #
36
+ # <foo:bar hoge:fuga='' hoge='' >
37
+ # <foo hoge:fuga='' hoge='' >
38
+ # ^ ^ ^ ^ ^ ^
39
+ # 1 2 3 4 5 6
40
+ #
41
+ # The following method will be called with the following arguments
42
+ # when the parser reaches the above point;
43
+ #
44
+ # 1: on_stag_ns ('foo:bar', 'foo', 'bar')
45
+ # or
46
+ # on_stag_ns ('foo', '', 'foo')
47
+ # 2: on_attribute_ns ('hoge:fuga', 'hoge', 'fuga')
48
+ # 3: on_attribute_end ('hoge:fuga')
49
+ # 4: on_attribute_ns ('hoge', nil, 'hoge')
50
+ # 5: on_attribute_end ('hoge')
51
+ # 6: on_stag_end_ns ('foo:bar', { 'foo' => '', ... })
52
+ # or
53
+ # on_stag_end_empty_ns ('foo:bar', { 'foo' => '', ... })
54
+ #
55
+
56
+ def on_stag_ns(qname, prefix, localpart)
57
+ end
58
+
59
+ def on_attribute_ns(qname, prefix, localpart)
60
+ end
61
+
62
+ def on_stag_end_ns(qname, namespaces)
63
+ end
64
+
65
+ def on_stag_end_empty_ns(qname, namespaces)
66
+ end
67
+
68
+ end
69
+
70
+
71
+
72
+
73
+ class XMLNamespaceDecoration < Decoration
74
+
75
+ proc {
76
+ h = {'foo'=>true} ; h['foo'] = nil
77
+ raise "requires Ruby-1.6 or above" unless h.key? 'foo'
78
+ }.call
79
+
80
+ PredefinedNamespace = {
81
+ 'xml' => 'http://www.w3.org/XML/1998/namespace',
82
+ 'xmlns' => 'http://www.w3.org/2000/xmlns/',
83
+ }
84
+
85
+ ReservedNamespace = PredefinedNamespace.invert
86
+
87
+
88
+ def ns_parse_error(msg)
89
+ @orig_visitor.ns_parse_error msg
90
+ end
91
+
92
+ def ns_wellformed_error(msg)
93
+ @orig_visitor.ns_wellformed_error msg
94
+ end
95
+
96
+ def ns_valid_error(msg)
97
+ @orig_visitor.ns_valid_error msg
98
+ end
99
+
100
+
101
+ def on_start_document
102
+ @namespace = {} #PredefinedNamespace.dup
103
+ @ns_hist = []
104
+ @ns_undeclared = {} # for checking undeclared namespace prefixes.
105
+ @prev_prefix = {} # for checking doubled attributes.
106
+ @dont_same = [] # ditto.
107
+ @xmlns = NamespaceDeclaration.new(self)
108
+ @orig_visitor = @visitor
109
+ @visitor.on_start_document
110
+ end
111
+
112
+
113
+ def on_stag(name)
114
+ @ns_hist.push nil
115
+ unless /:/n =~ name then
116
+ @visitor.on_stag_ns name, '', name
117
+ else
118
+ prefix, localpart = $`, $'
119
+ if localpart.include? ?: then
120
+ ns_parse_error "localpart `#{localpart}' includes `:'"
121
+ end
122
+ if prefix == 'xmlns' then
123
+ ns_wellformed_error \
124
+ "prefix `xmlns' is not used for namespace prefix declaration"
125
+ end
126
+ unless @namespace.key? prefix then
127
+ if uri = PredefinedNamespace[prefix] then
128
+ @namespace[prefix] = uri
129
+ else
130
+ @ns_undeclared[prefix] = true
131
+ end
132
+ end
133
+ @visitor.on_stag_ns name, prefix, localpart
134
+ end
135
+ end
136
+
137
+
138
+ def on_attribute(name)
139
+ if /:/n =~ name then
140
+ prefix, localpart = $`, $'
141
+ if localpart.include? ?: then
142
+ ns_parse_error "localpart `#{localpart}' includes `:'"
143
+ end
144
+ unless @namespace.key? prefix then
145
+ if uri = PredefinedNamespace[prefix] then
146
+ @namespace[prefix] = uri
147
+ else
148
+ @ns_undeclared[prefix] = true
149
+ end
150
+ end
151
+ if prefix == 'xmlns' then
152
+ @visitor = @xmlns
153
+ @xmlns.on_xmlns_start localpart
154
+ else
155
+ if prev = @prev_prefix[localpart] then
156
+ @dont_same.push [ prev, prefix, localpart ]
157
+ end
158
+ @prev_prefix[localpart] = prefix
159
+ @visitor.on_attribute_ns name, prefix, localpart
160
+ end
161
+ elsif name == 'xmlns' then
162
+ @visitor = @xmlns
163
+ @xmlns.on_xmlns_start ''
164
+ else
165
+ @visitor.on_attribute_ns name, nil, name
166
+ end
167
+ end
168
+
169
+
170
+ class NamespaceDeclaration
171
+
172
+ include XMLScan::Visitor
173
+
174
+ def initialize(parent)
175
+ @parent = parent
176
+ end
177
+
178
+ def on_xmlns_start(prefix)
179
+ @prefix = prefix
180
+ @nsdecl = ''
181
+ end
182
+
183
+ def on_attr_value(str)
184
+ @nsdecl << str
185
+ end
186
+
187
+ def on_attr_entityref(ref)
188
+ @parent.ns_wellformed_error \
189
+ "xmlns includes undeclared entity reference"
190
+ end
191
+
192
+ def on_attr_charref(code)
193
+ @nsdecl << [code].pack('U')
194
+ end
195
+
196
+ def on_attr_charref_hex(code)
197
+ @nsdecl << [code].pack('U')
198
+ end
199
+
200
+ def on_attribute_end(name)
201
+ @parent.on_xmlns_end @prefix, @nsdecl
202
+ end
203
+
204
+ end
205
+
206
+
207
+ def on_xmlns_end(prefix, uri)
208
+ @visitor = @orig_visitor
209
+ if PredefinedNamespace.key? prefix then
210
+ if prefix == 'xmlns' then
211
+ ns_wellformed_error \
212
+ "prefix `xmlns' can't be bound to any namespace explicitly"
213
+ elsif (s = PredefinedNamespace[prefix]) != uri then
214
+ ns_wellformed_error \
215
+ "prefix `#{prefix}' can't be bound to any namespace except `#{s}'"
216
+ end
217
+ end
218
+ if uri.empty? then
219
+ if prefix.empty? then
220
+ uri = nil
221
+ else
222
+ ns_parse_error "`#{prefix}' is bound to empty namespace name"
223
+ end
224
+ elsif ReservedNamespace.key? uri then
225
+ unless (s = ReservedNamespace[uri]) == prefix then
226
+ ns_wellformed_error \
227
+ "namespace `#{uri}' is reserved for prefix `#{s}'"
228
+ end
229
+ end
230
+ (@ns_hist.last || @ns_hist[-1] = {})[prefix] = @namespace[prefix]
231
+ @namespace[prefix] = uri
232
+ @ns_undeclared.delete prefix
233
+ end
234
+
235
+
236
+ def fix_namespace
237
+ unless @ns_undeclared.empty? then
238
+ @ns_undeclared.each_key { |i|
239
+ @visitor.ns_wellformed_error "prefix `#{i}' is not declared"
240
+ }
241
+ @ns_undeclared.clear
242
+ end
243
+ unless @dont_same.empty? then
244
+ @dont_same.each { |n1,n2,l|
245
+ if @namespace[n1] == @namespace[n2] then
246
+ ns_wellformed_error \
247
+ "doubled localpart `#{l}' in the same namespace"
248
+ end
249
+ }
250
+ @dont_same.clear
251
+ end
252
+ @prev_prefix.clear
253
+ end
254
+
255
+
256
+ def on_stag_end(name)
257
+ fix_namespace
258
+ @visitor.on_stag_end_ns name, @namespace
259
+ end
260
+
261
+
262
+ def on_etag(name)
263
+ h = @ns_hist.pop and @namespace.update h
264
+ @visitor.on_etag name
265
+ end
266
+
267
+
268
+ def on_stag_end_empty(name)
269
+ fix_namespace
270
+ @visitor.on_stag_end_empty_ns name, @namespace
271
+ h = @ns_hist.pop and @namespace.update h
272
+ end
273
+
274
+
275
+ def on_doctype(root, pubid, sysid)
276
+ if root.count(':') > 1 then
277
+ ns_parse_error "qualified name `#{root}' includes `:'"
278
+ end
279
+ @visitor.on_doctype root, pubid, sysid
280
+ end
281
+
282
+
283
+ def on_pi(target, pi)
284
+ if target.include? ?: then
285
+ ns_parse_error "PI target `#{target}' includes `:'"
286
+ end
287
+ @visitor.on_pi target, pi
288
+ end
289
+
290
+
291
+ def on_entityref(ref)
292
+ if ref.include? ?: then
293
+ ns_parse_error "entity reference `#{ref}' includes `:'"
294
+ end
295
+ @visitor.on_entityref ref
296
+ end
297
+
298
+
299
+ def on_attr_entityref(ref)
300
+ if ref.include? ?: then
301
+ ns_parse_error "entity reference `#{ref}' includes `:'"
302
+ end
303
+ @visitor.on_attr_entityref ref
304
+ end
305
+
306
+ end
307
+
308
+
309
+
310
+ class XMLParserNS < XMLParser
311
+
312
+ def initialize(*)
313
+ super
314
+ @visitor = @decoration = XMLNamespaceDecoration.new(@visitor)
315
+ end
316
+
317
+ end
318
+
319
+ end
320
+
321
+
322
+
323
+
324
+
325
+ if $0 == __FILE__ then
326
+ class TestVisitor
327
+ include XMLScan::NSVisitor
328
+ def parse_error(msg)
329
+ STDERR.printf("%s:%d: %s\n", $s.path, $s.lineno, msg) if $VERBOSE
330
+ end
331
+ def wellformed_error(msg)
332
+ STDERR.printf("%s:%d: WFC: %s\n", $s.path, $s.lineno, msg) if $VERBOSE
333
+ end
334
+ def warning(msg)
335
+ STDERR.printf("%s:%d: warning: %s\n", $s.path,$s.lineno, msg) if $VERBOSE
336
+ end
337
+ def ns_parse_error(msg)
338
+ STDERR.printf("%s:%d: %s\n", $s.path, $s.lineno, msg) if $VERBOSE
339
+ end
340
+ def ns_wellformed_error(msg)
341
+ STDERR.printf("%s:%d: NSC: %s\n", $s.path, $s.lineno, msg) if $VERBOSE
342
+ end
343
+ end
344
+
345
+ $s = scan = XMLScan::XMLParserNS.new(TestVisitor.new)
346
+ src = ARGF
347
+ def src.path; filename; end
348
+ t1 = Time.times.utime
349
+ scan.parse src
350
+ t2 = Time.times.utime
351
+ STDERR.printf "%2.3f sec\n", t2 - t1
352
+ end
@@ -0,0 +1,299 @@
1
+ #
2
+ # xmlscan/parser.rb
3
+ #
4
+ # Copyright (C) Ueno Katsuhiro 2002
5
+ #
6
+ # $Id: parser.rb,v 1.10 2003/01/22 13:06:18 katsu Exp $
7
+ #
8
+
9
+ require 'xmlscan/scanner'
10
+
11
+
12
+ module XMLScan
13
+
14
+ class XMLParser < XMLScanner
15
+
16
+ class AttributeChecker < Hash
17
+ # AttributeChecker inherits Hash only for speed.
18
+
19
+ def check_unique(name)
20
+ not key? name and store(name, true)
21
+ end
22
+
23
+ end
24
+
25
+
26
+ #PredefinedEntity = {
27
+ # 'lt' => '<',
28
+ # 'gt' => '>',
29
+ # 'amp' => '&',
30
+ # 'quot' => '"',
31
+ # 'apos' => "'",
32
+ #}
33
+
34
+
35
+ def parse(*)
36
+ @elem = []
37
+ @attr = AttributeChecker.new
38
+ @standalone = nil
39
+ super
40
+ end
41
+
42
+
43
+ private
44
+
45
+ def on_xmldecl_version(str)
46
+ unless str == '1.0' then
47
+ warning "unsupported XML version `#{str}'"
48
+ end
49
+ @visitor.on_xmldecl_version str
50
+ end
51
+
52
+
53
+ def on_xmldecl_standalone(str)
54
+ if str == 'yes' then
55
+ @standalone = true
56
+ elsif str == 'no' then
57
+ @standalone = false
58
+ else
59
+ parse_error "standalone declaration must be either `yes' or `no'"
60
+ end
61
+ @visitor.on_xmldecl_standalone str
62
+ end
63
+
64
+
65
+ def on_doctype(name, pubid, sysid)
66
+ if pubid and not sysid then
67
+ parse_error "public external ID must have both public ID and system ID"
68
+ end
69
+ @visitor.on_doctype name, pubid, sysid
70
+ end
71
+
72
+
73
+ def on_prolog_space(s)
74
+ # just ignore it.
75
+ end
76
+
77
+
78
+ def on_pi(target, pi)
79
+ if target.downcase == 'xml' then
80
+ parse_error "reserved PI target `#{target}'"
81
+ end
82
+ @visitor.on_pi target, pi
83
+ end
84
+
85
+
86
+ #def on_entityref(ref)
87
+ # rep = PredefinedEntity[ref]
88
+ # if rep then
89
+ # @visitor.on_chardata rep
90
+ # else
91
+ # @visitor.on_entityref ref
92
+ # end
93
+ #end
94
+
95
+
96
+ #def on_attr_entityref(ref)
97
+ # rep = PredefinedEntity[ref]
98
+ # if rep then
99
+ # @visitor.on_attr_value rep
100
+ # else
101
+ # @visitor.on_attr_entityref ref
102
+ # end
103
+ #end
104
+
105
+
106
+ #def on_charref_hex(code)
107
+ # on_charref code
108
+ #end
109
+
110
+
111
+ #def on_attr_charref_hex(code)
112
+ # on_attr_charref code
113
+ #end
114
+
115
+
116
+ def on_stag(name)
117
+ @elem.push name
118
+ @visitor.on_stag name
119
+ @attr.clear
120
+ end
121
+
122
+ def on_attribute(name)
123
+ unless @attr.check_unique name then
124
+ wellformed_error "doubled attribute `#{name}'"
125
+ end
126
+ @visitor.on_attribute name
127
+ end
128
+
129
+ def on_attr_value(str)
130
+ str.tr! "\t\r\n", ' ' # normalize
131
+ @visitor.on_attr_value str
132
+ end
133
+
134
+ def on_stag_end_empty(name)
135
+ # @visitor.on_stag_end name
136
+ # @elem.pop
137
+ # @visitor.on_etag name
138
+ @visitor.on_stag_end_empty name
139
+ @elem.pop
140
+ end
141
+
142
+ def on_etag(name)
143
+ last = @elem.pop
144
+ if last == name then
145
+ @visitor.on_etag name
146
+ elsif last then
147
+ wellformed_error "element type `#{name}' is not matched"
148
+ @visitor.on_etag last
149
+ else
150
+ parse_error "end tag `#{name}' appears alone"
151
+ end
152
+ end
153
+
154
+
155
+ public
156
+
157
+
158
+ def scan_content(s)
159
+ elem = @elem # for speed
160
+ src = @src # for speed
161
+ found_root_element = false
162
+
163
+ begin
164
+
165
+ # -- first start tag --
166
+ elem.clear
167
+ found_stag = false
168
+
169
+ while s and not found_stag
170
+ if (c = s[0]) == ?< then
171
+ if (c = s[1]) == ?/ then
172
+ # should be a parse error
173
+ scan_etag s
174
+ elsif c == ?! then
175
+ if s[2] == ?- and s[3] == ?- then
176
+ scan_comment s
177
+ elsif /\A<!\[CDATA\[/n =~ s then
178
+ parse_error "CDATA section is found outside of root element"
179
+ scan_cdata $'
180
+ else
181
+ scan_bang_tag s
182
+ end
183
+ elsif c == ?? then
184
+ scan_pi s
185
+ else
186
+ found_root_element = true
187
+ found_stag = true
188
+ scan_stag s
189
+ end
190
+ else
191
+ parse_error "content of element is found outside of root element"
192
+ scan_chardata s
193
+ end
194
+ s = src.get
195
+ end
196
+
197
+ if not found_root_element and not found_stag then
198
+ parse_error "no root element was found"
199
+ end
200
+
201
+ # -- contents --
202
+ while s and not elem.empty?
203
+ if (c = s[0]) == ?< then
204
+ if (c = s[1]) == ?/ then
205
+ scan_etag s
206
+ elsif c == ?! then
207
+ if s[2] == ?- and s[3] == ?- then
208
+ scan_comment s
209
+ elsif /\A<!\[CDATA\[/n =~ s then
210
+ scan_cdata $'
211
+ else
212
+ scan_bang_tag s
213
+ end
214
+ elsif c == ?? then
215
+ scan_pi s
216
+ else
217
+ scan_stag s
218
+ end
219
+ else
220
+ scan_chardata s
221
+ end
222
+ s = src.get
223
+ end
224
+
225
+ unless elem.empty? then
226
+ while name = elem.pop
227
+ parse_error "unclosed element `#{name}' meets EOF"
228
+ @visitor.on_etag name
229
+ end
230
+ end
231
+
232
+ # -- epilogue --
233
+ finish = true
234
+
235
+ while s
236
+ if (c = s[0]) == ?< then
237
+ if (c = s[1]) == ?/ then
238
+ finish = false # content out of root element
239
+ break
240
+ elsif c == ?! then
241
+ if s[2] == ?- and s[3] == ?- then
242
+ scan_comment s
243
+ else
244
+ finish = false # content out of root element
245
+ break
246
+ end
247
+ elsif c == ?? then
248
+ scan_pi s
249
+ else
250
+ parse_error "another root element is found" # stag
251
+ finish = false
252
+ break
253
+ end
254
+ else
255
+ if s.strip.empty? then
256
+ on_prolog_space s
257
+ else
258
+ finish = false # content out of root element
259
+ break
260
+ end
261
+ end
262
+ s = src.get
263
+ end
264
+
265
+ end until finish
266
+
267
+ end
268
+ end
269
+
270
+
271
+ end
272
+
273
+
274
+
275
+
276
+
277
+
278
+ if $0 == __FILE__ then
279
+ class TestVisitor
280
+ include XMLScan::Visitor
281
+ def parse_error(msg)
282
+ STDERR.printf("%s:%d: %s\n", $s.path, $s.lineno, msg) if $VERBOSE
283
+ end
284
+ def wellformed_error(msg)
285
+ STDERR.printf("%s:%d: WFC: %s\n", $s.path, $s.lineno, msg) if $VERBOSE
286
+ end
287
+ def warning(msg)
288
+ STDERR.printf("%s:%d: warning: %s\n", $s.path,$s.lineno, msg) if $VERBOSE
289
+ end
290
+ end
291
+
292
+ $s = scan = XMLScan::XMLParser.new(TestVisitor.new)
293
+ src = ARGF
294
+ def src.path; filename; end
295
+ t1 = Time.times.utime
296
+ scan.parse src
297
+ t2 = Time.times.utime
298
+ STDERR.printf "%2.3f sec\n", t2 - t1
299
+ end