activefacts 0.7.3 → 0.8.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (94) hide show
  1. data/LICENSE +19 -0
  2. data/Manifest.txt +24 -2
  3. data/Rakefile +25 -3
  4. data/bin/afgen +1 -1
  5. data/bin/cql +13 -2
  6. data/css/offline.css +3 -0
  7. data/css/orm2.css +24 -0
  8. data/css/print.css +8 -0
  9. data/css/style-print.css +357 -0
  10. data/css/style.css +387 -0
  11. data/download.html +85 -0
  12. data/examples/CQL/Address.cql +3 -3
  13. data/examples/CQL/Blog.cql +13 -14
  14. data/examples/CQL/CompanyDirectorEmployee.cql +4 -4
  15. data/examples/CQL/Death.cql +3 -2
  16. data/examples/CQL/Genealogy.cql +13 -11
  17. data/examples/CQL/Marriage.cql +2 -2
  18. data/examples/CQL/Metamodel.cql +136 -93
  19. data/examples/CQL/MultiInheritance.cql +2 -2
  20. data/examples/CQL/OilSupply.cql +14 -10
  21. data/examples/CQL/Orienteering.cql +22 -19
  22. data/examples/CQL/PersonPlaysGame.cql +3 -2
  23. data/examples/CQL/SchoolActivities.cql +4 -2
  24. data/examples/CQL/SimplestUnary.cql +1 -1
  25. data/examples/CQL/SubtypePI.cql +6 -7
  26. data/examples/CQL/Warehousing.cql +16 -19
  27. data/examples/CQL/unit.cql +584 -0
  28. data/examples/index.html +276 -0
  29. data/examples/intro.html +497 -0
  30. data/examples/local.css +20 -0
  31. data/index.html +96 -0
  32. data/lib/activefacts/api/concept.rb +48 -46
  33. data/lib/activefacts/api/constellation.rb +43 -23
  34. data/lib/activefacts/api/entity.rb +2 -2
  35. data/lib/activefacts/api/instance.rb +6 -2
  36. data/lib/activefacts/api/instance_index.rb +5 -0
  37. data/lib/activefacts/api/value.rb +8 -2
  38. data/lib/activefacts/api/vocabulary.rb +15 -10
  39. data/lib/activefacts/cql/CQLParser.treetop +109 -88
  40. data/lib/activefacts/cql/Concepts.treetop +32 -10
  41. data/lib/activefacts/cql/Context.treetop +34 -0
  42. data/lib/activefacts/cql/Expressions.treetop +9 -9
  43. data/lib/activefacts/cql/FactTypes.treetop +30 -31
  44. data/lib/activefacts/cql/Language/English.treetop +50 -0
  45. data/lib/activefacts/cql/LexicalRules.treetop +2 -1
  46. data/lib/activefacts/cql/Terms.treetop +117 -0
  47. data/lib/activefacts/cql/ValueTypes.treetop +152 -0
  48. data/lib/activefacts/cql/compiler.rb +1718 -0
  49. data/lib/activefacts/cql/parser.rb +124 -57
  50. data/lib/activefacts/generate/absorption.rb +1 -1
  51. data/lib/activefacts/generate/cql.rb +111 -100
  52. data/lib/activefacts/generate/cql/html.rb +5 -5
  53. data/lib/activefacts/generate/oo.rb +3 -3
  54. data/lib/activefacts/generate/ordered.rb +51 -19
  55. data/lib/activefacts/generate/ruby.rb +10 -8
  56. data/lib/activefacts/generate/sql/mysql.rb +14 -10
  57. data/lib/activefacts/generate/sql/server.rb +29 -24
  58. data/lib/activefacts/input/cql.rb +9 -1264
  59. data/lib/activefacts/input/orm.rb +213 -200
  60. data/lib/activefacts/persistence/columns.rb +11 -10
  61. data/lib/activefacts/persistence/index.rb +15 -18
  62. data/lib/activefacts/persistence/reference.rb +17 -17
  63. data/lib/activefacts/persistence/tables.rb +50 -51
  64. data/lib/activefacts/version.rb +1 -1
  65. data/lib/activefacts/vocabulary/extensions.rb +79 -8
  66. data/lib/activefacts/vocabulary/metamodel.rb +183 -114
  67. data/spec/absorption_ruby_spec.rb +99 -0
  68. data/spec/absorption_spec.rb +3 -4
  69. data/spec/api/constellation.rb +1 -1
  70. data/spec/api/entity_type.rb +3 -1
  71. data/spec/api/instance.rb +4 -2
  72. data/spec/api/roles.rb +8 -6
  73. data/spec/api_spec.rb +1 -2
  74. data/spec/cql/context_spec.rb +71 -0
  75. data/spec/cql/samples_spec.rb +154 -0
  76. data/spec/cql/unit_spec.rb +375 -0
  77. data/spec/cql_cql_spec.rb +31 -21
  78. data/spec/cql_mysql_spec.rb +70 -0
  79. data/spec/cql_parse_spec.rb +15 -9
  80. data/spec/cql_ruby_spec.rb +27 -13
  81. data/spec/cql_sql_spec.rb +42 -16
  82. data/spec/cql_symbol_tables_spec.rb +2 -3
  83. data/spec/cqldump_spec.rb +7 -7
  84. data/spec/helpers/file_matcher.rb +39 -0
  85. data/spec/norma_cql_spec.rb +20 -12
  86. data/spec/norma_ruby_spec.rb +6 -3
  87. data/spec/norma_sql_spec.rb +6 -3
  88. data/spec/norma_tables_spec.rb +6 -4
  89. data/spec/spec_helper.rb +27 -8
  90. data/status.html +69 -0
  91. data/why.html +60 -0
  92. metadata +34 -11
  93. data/lib/activefacts/cql/DataTypes.treetop +0 -81
  94. data/spec/cql_unit_spec.rb +0 -330
@@ -9,9 +9,21 @@
9
9
  # As we build ActiveFacts objects to match, we index those in @by_id[].
10
10
  # Both these hashes may be looked up by any of the ref="..." values in the file.
11
11
  #
12
- require 'rexml/document'
12
+ require 'nokogiri'
13
13
  require 'activefacts/vocabulary'
14
14
 
15
+ module Nokogiri
16
+ module XML
17
+ class Node
18
+ def elements
19
+ children.select{|n|
20
+ Nokogiri::XML::Element === n
21
+ }
22
+ end
23
+ end
24
+ end
25
+ end
26
+
15
27
  module ActiveFacts
16
28
  module Input
17
29
  # Compile a NORMA (.orm) file to an ActiveFacts vocabulary.
@@ -38,22 +50,23 @@ module ActiveFacts
38
50
  public
39
51
  def read #:nodoc:
40
52
  begin
41
- @document = REXML::Document.new(@file)
53
+ @document = Nokogiri::XML(@file)
42
54
  rescue => e
43
55
  puts "Failed to parse XML in #{@filename}: #{e.inspect}"
44
56
  end
45
57
 
46
58
  # Find the Vocabulary and do some setup:
47
- root = @document.elements[1]
48
- if root.expanded_name == "ormRoot:ORM2"
49
- x_models = root.elements.to_a("orm:ORMModel")
59
+ root = @document.root
60
+ #p((root.methods-0.methods).sort.grep(/name/))
61
+ if root.name == "ORM2" && root.namespace.prefix == "ormRoot"
62
+ x_models = root.xpath('orm:ORMModel')
50
63
  throw "No vocabulary found" unless x_models.size == 1
51
64
  @x_model = x_models[0]
52
65
  elsif root.name == "ORMModel"
53
- @x_model = @document.elements[1]
66
+ p @document.children.map(&:name)
67
+ @x_model = @document.children[0]
54
68
  else
55
- pp root
56
- throw "NORMA vocabulary not found in file"
69
+ throw "NORMA model not found in #{@filename}"
57
70
  end
58
71
 
59
72
  read_vocabulary
@@ -64,12 +77,13 @@ module ActiveFacts
64
77
 
65
78
  def read_vocabulary
66
79
  @constellation = ActiveFacts::API::Constellation.new(ActiveFacts::Metamodel)
67
- @vocabulary = @constellation.Vocabulary(@x_model.attributes['Name'])
80
+ vocabulary_name = @x_model['Name']
81
+ @vocabulary = @constellation.Vocabulary(@x_model['Name'])
68
82
 
69
83
  # Find all elements having an "id" attribute and index them
70
- x_identified = @x_model.elements.to_a("//*[@id]")
84
+ x_identified = @x_model.xpath(".//*[@id]")
71
85
  @x_by_id = x_identified.inject({}){|h, x|
72
- id = x.attributes['id']
86
+ id = x['id']
73
87
  h[id] = x
74
88
  h
75
89
  }
@@ -91,24 +105,23 @@ module ActiveFacts
91
105
  def read_entity_types
92
106
  # get and process all the entity types:
93
107
  entity_types = []
94
- x_entity_types = @x_model.elements.to_a("orm:Objects/orm:EntityType")
108
+ x_entity_types = @x_model.xpath("orm:Objects/orm:EntityType")
95
109
  x_entity_types.each{|x|
96
- id = x.attributes['id']
97
- name = x.attributes['Name'] || ""
110
+ id = x['id']
111
+ name = x['Name'] || ""
98
112
  name.gsub!(/\s/,'')
99
113
  name = nil if name.size == 0
100
- # puts "EntityType #{name} is #{id}"
101
114
  entity_types <<
102
115
  @by_id[id] =
103
116
  entity_type =
104
117
  @constellation.EntityType(@vocabulary, name)
105
- independent = x.attributes['IsIndependent']
118
+ independent = x['IsIndependent']
106
119
  entity_type.is_independent = true if independent && independent == 'true'
107
- personal = x.attributes['IsPersonal']
120
+ personal = x['IsPersonal']
108
121
  entity_type.pronoun = 'personal' if personal && personal == 'true'
109
- # x_pref = x.elements.to_a("orm:PreferredIdentifier")[0]
122
+ # x_pref = x.xpath("orm:PreferredIdentifier")[0]
110
123
  # if x_pref
111
- # pi_id = x_pref.attributes['ref']
124
+ # pi_id = x_pref['ref']
112
125
  # @pref_id_for[pi_id] = x
113
126
  # end
114
127
  }
@@ -117,20 +130,20 @@ module ActiveFacts
117
130
  def read_value_types
118
131
  # Now the value types:
119
132
  value_types = []
120
- x_value_types = @x_model.elements.to_a("orm:Objects/orm:ValueType")
133
+ x_value_types = @x_model.xpath("orm:Objects/orm:ValueType")
121
134
  #pp x_value_types
122
135
  x_value_types.each{|x|
123
- id = x.attributes['id']
124
- name = x.attributes['Name'] || ""
136
+ id = x['id']
137
+ name = x['Name'] || ""
125
138
  name.gsub!(/\s/,'')
126
139
  name = nil if name.size == 0
127
140
 
128
- cdt = x.elements.to_a('orm:ConceptualDataType')[0]
129
- scale = cdt.attributes['Scale']
141
+ cdt = x.xpath('orm:ConceptualDataType')[0]
142
+ scale = cdt['Scale']
130
143
  scale = scale != "" && scale.to_i
131
- length = cdt.attributes['Length']
144
+ length = cdt['Length']
132
145
  length = length != "" && length.to_i
133
- base_type = @x_by_id[cdt.attributes['ref']]
146
+ base_type = @x_by_id[cdt['ref']]
134
147
  type_name = "#{base_type.name}"
135
148
  type_name.sub!(/^orm:/,'')
136
149
  type_name.sub!(/DataType\Z/,'')
@@ -139,21 +152,20 @@ module ActiveFacts
139
152
  length = 32 if type_name =~ /Integer\Z/ && length.to_i == 0 # Set default integer length
140
153
 
141
154
  # REVISIT: Need to handle standard types better here:
142
- data_type = type_name != name ? @constellation.ValueType(@vocabulary, type_name) : nil
155
+ value_super_type = type_name != name ? @constellation.ValueType(@vocabulary, type_name) : nil
143
156
 
144
- # puts "ValueType #{name} is #{id}"
145
157
  value_types <<
146
158
  @by_id[id] =
147
159
  vt = @constellation.ValueType(@vocabulary, name)
148
- vt.supertype = data_type
160
+ vt.supertype = value_super_type
149
161
  vt.length = length if length
150
162
  vt.scale = scale if scale
151
- independent = x.attributes['IsIndependent']
163
+ independent = x['IsIndependent']
152
164
  vt.is_independent = true if independent && independent == 'true'
153
- personal = x.attributes['IsPersonal']
165
+ personal = x['IsPersonal']
154
166
  vt.pronoun = 'personal' if personal && personal == 'true'
155
167
 
156
- x_ranges = x.elements.to_a("orm:ValueRestriction/orm:ValueConstraint/orm:ValueRanges/orm:ValueRange")
168
+ x_ranges = x.xpath("orm:ValueRestriction/orm:ValueConstraint/orm:ValueRanges/orm:ValueRange")
157
169
  next if x_ranges.size == 0
158
170
  vt.value_restriction = @constellation.ValueRestriction(:new)
159
171
  x_ranges.each{|x_range|
@@ -164,35 +176,24 @@ module ActiveFacts
164
176
  end
165
177
 
166
178
  def value_range(x_range)
167
- min = x_range.attributes['MinValue']
168
- max = x_range.attributes['MaxValue']
169
- q = "'"
170
- min = case min
171
- when ""; nil
172
- when /[^0-9\.]/; q+min+q
173
- when /\./; Float(min)
174
- else Integer(min)
175
- end
176
- max = case max
177
- when ""; nil
178
- when /[^0-9\.]/; q+max+q
179
- when /\./; Float(max)
180
- else Integer(max)
181
- end
179
+ min = x_range['MinValue']
180
+ max = x_range['MaxValue']
181
+
182
+ strings = is_a_string(min) || is_a_string(max)
182
183
  # ValueRange takes a minimum and/or a maximum Bound, each takes value and whether inclusive
183
184
  @constellation.ValueRange(
184
- min ? [min.to_s, true] : nil,
185
- max ? [max.to_s, true] : nil
185
+ min && min != '' ? [[min, strings, nil], true] : nil,
186
+ max && max != '' ? [[max, strings, nil], true] : nil
186
187
  )
187
188
  end
188
189
 
189
190
  def read_fact_types
190
191
  # Handle the fact types:
191
192
  facts = []
192
- @x_facts = @x_model.elements.to_a("orm:Facts/orm:Fact")
193
+ @x_facts = @x_model.xpath("orm:Facts/orm:Fact")
193
194
  @x_facts.each{|x|
194
- id = x.attributes['id']
195
- name = x.attributes['Name'] || x.attributes['_Name']
195
+ id = x['id']
196
+ name = x['Name'] || x['_Name']
196
197
  name = "<unnamed>" if !name
197
198
  name.gsub!(/\s/,'')
198
199
  name = "" if !name || name.size == 0
@@ -206,29 +207,30 @@ module ActiveFacts
206
207
  def read_subtypes
207
208
  # Handle the subtype fact types:
208
209
  facts = []
209
- @x_subtypes = @x_model.elements.to_a("orm:Facts/orm:SubtypeFact")
210
- @x_mappings = @document.elements.to_a("ormRoot:ORM2/oialtocdb:MappingCustomization/oialtocdb:AssimilationMappings/oialtocdb:AssimilationMapping/oialtocdb:FactType")
210
+ @x_subtypes = @x_model.xpath("orm:Facts/orm:SubtypeFact")
211
+ if @document.namespaces['xmlns:oialtocdb']
212
+ oialtocdb = @document.xpath("ormRoot:ORM2/oialtocdb:MappingCustomization")
213
+ @x_mappings = oialtocdb.xpath(".//oialtocdb:AssimilationMappings/oialtocdb:AssimilationMapping/oialtocdb:FactType")
214
+ else
215
+ @x_mappings = []
216
+ end
211
217
 
212
218
  @x_subtypes.each{|x|
213
- id = x.attributes['id']
214
- name = x.attributes['Name'] || x.attributes['_Name'] || ''
219
+ id = x['id']
220
+ name = x['Name'] || x['_Name'] || ''
215
221
  name.gsub!(/\s/,'')
216
222
  name = nil if name.size == 0
217
223
  # puts "FactType #{name || id}"
218
224
 
219
- mapping = @x_mappings.detect{ |m| m.attributes['ref'] == id }
220
- mapping_choice = mapping ? mapping.parent.attributes['AbsorptionChoice'] : 'Absorbed'
221
-
222
- x_subtype_role = x.elements['orm:FactRoles/orm:SubtypeMetaRole']
223
- subtype_role_id = x_subtype_role.attributes['id']
224
- subtype_id = x_subtype_role.elements['orm:RolePlayer'].attributes['ref']
225
+ x_subtype_role = x.xpath('orm:FactRoles/orm:SubtypeMetaRole')[0]
226
+ subtype_role_id = x_subtype_role['id']
227
+ subtype_id = x_subtype_role.xpath('orm:RolePlayer')[0]['ref']
225
228
  subtype = @by_id[subtype_id]
226
- subtype.is_independent = true if mapping_choice == 'Separate'
227
229
  # REVISIT: Provide a way in the metamodel of handling Partition, (and mapping choices that vary for each supertype?)
228
230
 
229
- x_supertype_role = x.elements['orm:FactRoles/orm:SupertypeMetaRole']
230
- supertype_role_id = x_supertype_role.attributes['id']
231
- supertype_id = x_supertype_role.elements['orm:RolePlayer'].attributes['ref']
231
+ x_supertype_role = x.xpath('orm:FactRoles/orm:SupertypeMetaRole')[0]
232
+ supertype_role_id = x_supertype_role['id']
233
+ supertype_id = x_supertype_role.xpath('orm:RolePlayer')[0]['ref']
232
234
  supertype = @by_id[supertype_id]
233
235
 
234
236
  throw "For Subtype fact #{name}, the supertype #{supertype_id} was not found" if !supertype
@@ -237,29 +239,33 @@ module ActiveFacts
237
239
 
238
240
  inheritance_fact = @constellation.TypeInheritance(subtype, supertype)
239
241
  inheritance_fact.fact_type_id = :new
240
- if x.attributes["IsPrimary"] == "true" or # Old way
241
- x.attributes["PreferredIdentificationPath"] == "true" # Newer
242
+ if x["IsPrimary"] == "true" or # Old way
243
+ x["PreferredIdentificationPath"] == "true" # Newer
242
244
  # $stderr.puts "#{supertype.name} is primary supertype of #{subtype.name}"
243
245
  inheritance_fact.provides_identification = true
244
246
  end
247
+ mapping = @x_mappings.detect{ |m| m['ref'] == id }
248
+ mapping_choice = mapping ? mapping.parent['AbsorptionChoice'] : 'Absorbed'
249
+ inheritance_fact.assimilation = mapping_choice.downcase.sub(/partition/, 'partitioned') if mapping_choice != 'Absorbed'
245
250
  facts << @by_id[id] = inheritance_fact
246
251
 
247
252
  # Create the new Roles so we can find constraints on them:
248
- subtype_role = @by_id[subtype_role_id] = @constellation.Role(inheritance_fact, 0, subtype)
249
- supertype_role = @by_id[supertype_role_id] = @constellation.Role(inheritance_fact, 1, supertype)
253
+ subtype_role = @by_id[subtype_role_id] = @constellation.Role(inheritance_fact, 0, :concept => subtype)
254
+ supertype_role = @by_id[supertype_role_id] = @constellation.Role(inheritance_fact, 1, :concept => supertype)
250
255
 
251
256
  # Create readings, so constraints can be verbalised for example:
252
257
  rs = @constellation.RoleSequence(:new)
253
- @constellation.RoleRef(rs, 0).role = subtype_role
254
- @constellation.RoleRef(rs, 1).role = supertype_role
255
-
256
- # reading = @constellation.Reading(inheritance_fact, 0)
257
- # reading.reading_text = "{1} is {0}"
258
- # reading.role_sequence = rs
259
-
260
- reading = @constellation.Reading(inheritance_fact, 0)
261
- reading.reading_text = "{0} is a subtype of {1}"
262
- reading.role_sequence = rs
258
+ @constellation.RoleRef(rs, 0, :role => subtype_role)
259
+ @constellation.RoleRef(rs, 1, :role => supertype_role)
260
+ @constellation.Reading(inheritance_fact, 0, :role_sequence => rs, :text => "{0} is a kind of {1}")
261
+ @constellation.Reading(inheritance_fact, 1, :role_sequence => rs, :text => "{0} is a subtype of {1}")
262
+
263
+ rs2 = @constellation.RoleSequence(:new)
264
+ @constellation.RoleRef(rs2, 0, :role => supertype_role)
265
+ @constellation.RoleRef(rs2, 1, :role => subtype_role)
266
+ n = 'aeiouh'.include?(subtype_role.concept.name.downcase[0]) ? 1 : 0
267
+ @constellation.Reading(inheritance_fact, 2+n, :role_sequence => rs2, :text => "{0} is a {1}")
268
+ @constellation.Reading(inheritance_fact, 3-n, :role_sequence => rs2, :text => "{0} is an {1}")
263
269
 
264
270
  # The required uniqueness constraints are already present in the NORMA file, don't duplicate them
265
271
  =begin
@@ -295,17 +301,17 @@ module ActiveFacts
295
301
  # We'll ignore the fact roles (and constraints) that implied objectifications have.
296
302
  # This happens for all ternaries and higher order facts
297
303
  nested_types = []
298
- x_nested_types = @x_model.elements.to_a("orm:Objects/orm:ObjectifiedType")
304
+ x_nested_types = @x_model.xpath("orm:Objects/orm:ObjectifiedType")
299
305
  x_nested_types.each{|x|
300
- id = x.attributes['id']
301
- name = x.attributes['Name'] || ""
306
+ id = x['id']
307
+ name = x['Name'] || ""
302
308
  name.gsub!(/\s/,'')
303
309
  name = nil if name.size == 0
304
310
 
305
- x_fact_type = x.elements.to_a('orm:NestedPredicate')[0]
306
- is_implied = x_fact_type.attributes['IsImplied'] == "true"
311
+ x_fact_type = x.xpath('orm:NestedPredicate')[0]
312
+ is_implied = x_fact_type['IsImplied'] == "true"
307
313
 
308
- fact_id = x_fact_type.attributes['ref']
314
+ fact_id = x_fact_type['ref']
309
315
  fact_type = @by_id[fact_id]
310
316
  throw "Nested fact #{fact_id} not found" if !fact_type
311
317
 
@@ -325,67 +331,67 @@ module ActiveFacts
325
331
 
326
332
  def read_roles
327
333
  @x_facts.each{|x|
328
- id = x.attributes['id']
334
+ id = x['id']
329
335
  fact_type = @by_id[id]
330
- fact_name = x.attributes['Name'] || x.attributes['_Name'] || ''
336
+ fact_name = x['Name'] || x['_Name'] || ''
331
337
  fact_name.gsub!(/\s/,'')
332
338
  fact_name = nil if fact_name == ''
333
339
 
334
- x_fact_roles = x.elements.to_a('orm:FactRoles/*')
335
- x_reading_orders = x.elements.to_a('orm:ReadingOrders/*')
340
+ x_fact_roles = x.xpath('orm:FactRoles/*')
341
+ x_reading_orders = x.xpath('orm:ReadingOrders/*')
336
342
 
337
343
  # Deal with FactRoles (Roles):
338
344
  x_fact_roles.each{|x|
339
- name = x.attributes['Name'] || ""
345
+ name = x['Name'] || ""
340
346
  name.gsub!(/\s/,'')
341
347
  name = nil if name.size == 0
342
348
 
343
- # _IsMandatory = x.attributes['_IsMandatory']
344
- # _Multiplicity = x.attributes['_Multiplicity]
345
- id = x.attributes['id']
346
- ref = x.elements[1].attributes['ref']
349
+ # _IsMandatory = x['_IsMandatory']
350
+ # _Multiplicity = x['_Multiplicity]
351
+ id = x['id']
352
+ ref = x.xpath('orm:RolePlayer')[0]['ref']
347
353
 
348
354
  # Find the concept that plays the role:
349
355
  concept = @by_id[ref]
350
- throw "RolePlayer for #{name||ref} was not found" if !concept
356
+ throw "RolePlayer for '#{name}' #{ref} was not found" if !concept
351
357
 
352
358
  # Skip implicit roles added by NORMA to make unaries into binaries.
353
359
  # This would make constraints over the deleted roles impossible,
354
360
  # so as a SPECIAL CASE we index the unary role by the id of the
355
361
  # implicit role. That means care is needed when handling unary FTs.
356
- if (ox = @x_by_id[ref]) && ox.attributes['IsImplicitBooleanValue']
357
- x_other_role = x.parent.elements.to_a('orm:Role').reject{|x_role|
362
+ if (ox = @x_by_id[ref]) && ox['IsImplicitBooleanValue']
363
+ x_other_role = x.parent.xpath('orm:Role').reject{|x_role|
358
364
  x_role == x
359
365
  }[0]
360
- other_role_id = x_other_role.attributes["id"]
366
+ other_role_id = x_other_role["id"]
361
367
  other_role = @by_id[other_role_id]
362
368
  # puts "Indexing unary FT role #{other_role_id} by implicit boolean role #{id}"
363
369
  @by_id[id] = other_role
364
370
 
365
371
  # The role name of the ignored role is the one that applies:
366
- role_name = x.attributes['Name']
372
+ role_name = x['Name']
367
373
  other_role.role_name = role_name if role_name && role_name != ''
368
374
 
369
- concept.delete # Delete our object for the implicit boolean ValueType
375
+ concept.deny # Delete our object for the implicit boolean ValueType
370
376
  @by_id.delete(ref) # and de-index it from our list
371
377
  next
372
378
  end
373
379
 
374
- #puts "#{@vocabulary}, Name=#{x.attributes['Name']}, concept=#{concept}"
380
+ #puts "#{@vocabulary}, Name=#{x['Name']}, concept=#{concept}"
375
381
  throw "Role is played by #{concept.class} not Concept" if !(@constellation.vocabulary.concept(:Concept) === concept)
376
382
 
377
- name = x.attributes['Name'] || ''
383
+ name = x['Name'] || ''
378
384
  name.gsub!(/\s/,'')
379
385
  name = nil if name.size == 0
380
386
  #puts "Creating role #{name} nr#{fact_type.all_role.size} of #{fact_type.fact_type_id} played by #{concept.name}"
381
387
 
382
- role = @by_id[id] = @constellation.Role(fact_type, fact_type.all_role.size, concept)
388
+ role = @by_id[id] = @constellation.Role(fact_type, fact_type.all_role.size, :concept => concept)
383
389
  role.role_name = name if name
384
- # puts "Fact #{fact_name} (id #{fact_type.fact_type_id.object_id}) role #{x.attributes['Name']} is played by #{concept.name}, role is #{role.object_id}"
390
+ # puts "Fact #{fact_name} (id #{fact_type.fact_type_id.object_id}) role #{x['Name']} is played by #{concept.name}, role is #{role.object_id}"
385
391
 
386
- x_vr = x.elements.to_a("orm:ValueRestriction")
392
+ x_vr = x.xpath("orm:ValueRestriction")
387
393
  x_vr.each{|vr|
388
- x_ranges = vr.elements.to_a("orm:RoleValueConstraint/orm:ValueRanges/orm:ValueRange")
394
+ x_ranges = vr.xpath("orm:RoleValueConstraint/orm:ValueRanges/orm:ValueRange")
389
395
  next if x_ranges.size == 0
390
396
  role.role_value_restriction = @constellation.ValueRestriction(:new)
391
397
  x_ranges.each{|x_range|
@@ -401,11 +407,11 @@ module ActiveFacts
401
407
 
402
408
  # Deal with Readings:
403
409
  x_reading_orders.each{|x|
404
- x_role_sequence = x.elements.to_a('orm:RoleSequence/*')
405
- x_readings = x.elements.to_a('orm:Readings/orm:Reading/orm:Data')
410
+ x_role_sequence = x.xpath('orm:RoleSequence/*')
411
+ x_readings = x.xpath('orm:Readings/orm:Reading/orm:Data')
406
412
 
407
413
  # Build an array of the Roles needed:
408
- role_array = x_role_sequence.map{|x| @by_id[x.attributes['ref']] }
414
+ role_array = x_role_sequence.map{|x| @by_id[x['ref']] }
409
415
 
410
416
  # puts "Reading #{x_readings.map(&:text).inspect}"
411
417
  role_sequence = get_role_sequence(role_array)
@@ -418,14 +424,14 @@ module ActiveFacts
418
424
  reading = @constellation.Reading(fact_type, fact_type.all_reading.size)
419
425
  reading.role_sequence = role_sequence
420
426
  # REVISIT: The downcase here only needs to be the initial letter of each word, but be safe:
421
- reading.reading_text = extract_adjectives(x.text, role_sequence).downcase
427
+ reading.text = extract_adjectives(x.text, role_sequence).downcase
422
428
  }
423
429
  }
424
430
  }
425
431
  # @vocabulary.fact_types.each{|ft| puts ft }
426
432
  end
427
433
 
428
- def extract_adjectives(reading_text, role_sequence)
434
+ def extract_adjectives(text, role_sequence)
429
435
  all_role_refs = role_sequence.all_role_ref.sort_by{|rr| rr.ordinal}
430
436
  (0...all_role_refs.size).each{|i|
431
437
  role_ref = all_role_refs[i]
@@ -437,22 +443,22 @@ module ActiveFacts
437
443
  role_with_adjectives_re =
438
444
  %r| ?#{leading_adjectives_re}?\{#{i}\}#{trailing_adjectives_re}? ?|
439
445
 
440
- reading_text.gsub!(role_with_adjectives_re) {
446
+ text.gsub!(role_with_adjectives_re) {
441
447
  la = [[$1]*"", [$2]*""]*" ".gsub(/\s+/, ' ').sub(/\s+\Z/,'').strip
442
448
  ta = [[$1]*"", [$2]*""]*" ".gsub(/\s+/, ' ').sub(/\A\s+/,'').strip
443
- #puts "Setting leading adj #{la.inspect} from #{reading_text.inspect} for #{role_ref.role.concept.name}" if la != ""
449
+ #puts "Setting leading adj #{la.inspect} from #{text.inspect} for #{role_ref.role.concept.name}" if la != ""
444
450
  # REVISIT: Dunno what's up here, but removing the "if" test makes this chuck exceptions:
445
451
  role_ref.leading_adjective = la if la != ""
446
452
  role_ref.trailing_adjective = ta if ta != ""
447
453
 
448
- #puts "Reading '#{reading_text}' has role #{i} adjectives '#{la}' '#{ta}'" if la != "" || ta != ""
454
+ #puts "Reading '#{text}' has role #{i} adjectives '#{la}' '#{ta}'" if la != "" || ta != ""
449
455
 
450
456
  " {#{i}} "
451
457
  }
452
458
  }
453
- reading_text.sub!(/\A /, '')
454
- reading_text.sub!(/ \Z/, '')
455
- reading_text
459
+ text.sub!(/\A /, '')
460
+ text.sub!(/ \Z/, '')
461
+ text
456
462
  end
457
463
 
458
464
  def get_role_sequence(role_array)
@@ -478,18 +484,18 @@ module ActiveFacts
478
484
 
479
485
  def map_roles(x_roles, why = nil)
480
486
  role_array = x_roles.map{|x|
481
- id = x.attributes['ref']
487
+ id = x['ref']
482
488
  role = @by_id[id]
483
489
  if (why && !role)
484
490
  # We didn't make Implied objects, so some constraints are unconnectable
485
491
  x_role = @x_by_id[id]
486
- x_player = x_role.elements.to_a('orm:RolePlayer')[0]
487
- x_object = @x_by_id[x_player.attributes['ref']]
492
+ x_player = x_role.xpath('orm:RolePlayer')[0]
493
+ x_object = @x_by_id[x_player['ref']]
488
494
  x_nests = nil
489
495
  if (x_object.name.to_s == 'ObjectifiedType')
490
- x_nests = x_object.elements.to_a('orm:NestedPredicate')[0]
491
- implied = x_nests.attributes['IsImplied']
492
- x_fact = @x_by_id[x_nests.attributes['ref']]
496
+ x_nests = x_object.xpath('orm:NestedPredicate')[0]
497
+ implied = x_nests['IsImplied']
498
+ x_fact = @x_by_id[x_nests['ref']]
493
499
  end
494
500
 
495
501
  # This might have been a role of an ImpliedFact, which makes it safe to ignore.
@@ -526,38 +532,38 @@ module ActiveFacts
526
532
  end
527
533
 
528
534
  def read_mandatory_constraints
529
- x_mandatory_constraints = @x_model.elements.to_a("orm:Constraints/orm:MandatoryConstraint")
535
+ x_mandatory_constraints = @x_model.xpath("orm:Constraints/orm:MandatoryConstraint")
530
536
  @mandatory_constraints_by_rs = {}
531
537
  @mandatory_constraint_rs_by_id = {}
532
538
  x_mandatory_constraints.each{|x|
533
- name = x.attributes["Name"] || ''
539
+ name = x["Name"] || ''
534
540
  name.gsub!(/\s/,'')
535
541
  name = nil if name.size == 0
536
542
 
537
543
  # As of Feb 2008, all NORMA ValueTypes have an implied mandatory constraint.
538
- if x.elements.to_a("orm:ImpliedByObjectType").size > 0
544
+ if x.xpath("orm:ImpliedByObjectType").size > 0
539
545
  # $stderr.puts "Skipping ImpliedMandatoryConstraint #{name} over #{roles}"
540
546
  next
541
547
  end
542
548
 
543
- x_roles = x.elements.to_a("orm:RoleSequence/orm:Role")
549
+ x_roles = x.xpath("orm:RoleSequence/orm:Role")
544
550
  roles = map_roles(x_roles, "mandatory constraint #{name}")
545
551
  next if !roles
546
552
 
547
553
  # If X-OR mandatory, the Exclusion is accessed by:
548
- # x_exclusion = (ex = x.elements.to_a("orm:ExclusiveOrExclusionConstraint")[0]) &&
549
- # @x_by_id[ex.attributes['ref']]
550
- # puts "Mandatory #{name}(#{roles}) is paired with exclusive #{x_exclusion.attributes['Name']}" if x_exclusion
554
+ # x_exclusion = (ex = x.xpath("orm:ExclusiveOrExclusionConstraint")[0]) &&
555
+ # @x_by_id[ex['ref']]
556
+ # puts "Mandatory #{name}(#{roles}) is paired with exclusive #{x_exclusion['Name']}" if x_exclusion
551
557
 
552
558
  @mandatory_constraints_by_rs[roles] = x
553
- @mandatory_constraint_rs_by_id[x.attributes['id']] = roles
559
+ @mandatory_constraint_rs_by_id[x['id']] = roles
554
560
  }
555
561
  end
556
562
 
557
563
  def read_residual_mandatory_constraints
558
564
  @mandatory_constraints_by_rs.each { |roles, x|
559
565
  # Create a simply-mandatory PresenceConstraint for each mandatory constraint
560
- name = x.attributes["Name"] || ''
566
+ name = x["Name"] || ''
561
567
  name.gsub!(/\s/,'')
562
568
  name = nil if name.size == 0
563
569
  #puts "Residual Mandatory #{name}: #{roles.to_s}"
@@ -576,14 +582,14 @@ module ActiveFacts
576
582
  end
577
583
 
578
584
  def read_uniqueness_constraints
579
- x_uniqueness_constraints = @x_model.elements.to_a("orm:Constraints/orm:UniquenessConstraint")
585
+ x_uniqueness_constraints = @x_model.xpath("orm:Constraints/orm:UniquenessConstraint")
580
586
  x_uniqueness_constraints.each{|x|
581
- name = x.attributes["Name"] || ''
587
+ name = x["Name"] || ''
582
588
  name.gsub!(/\s/,'')
583
589
  name = nil if name.size == 0
584
- id = x.attributes["id"]
585
- x_pi = x.elements.to_a("orm:PreferredIdentifierFor")[0]
586
- pi = x_pi ? @by_id[eref = x_pi.attributes['ref']] : nil
590
+ id = x["id"]
591
+ x_pi = x.xpath("orm:PreferredIdentifierFor")[0]
592
+ pi = x_pi ? @by_id[eref = x_pi['ref']] : nil
587
593
 
588
594
  # Skip uniqueness constraints on implied concepts
589
595
  if x_pi && !pi
@@ -594,34 +600,36 @@ module ActiveFacts
594
600
  # A uniqueness constraint on a fact having an implied objectification isn't preferred:
595
601
  # if pi &&
596
602
  # (x_pi_for = @x_by_id[eref]) &&
597
- # (np = x_pi_for.elements.to_a('orm:NestedPredicate')[0]) &&
598
- # np.attributes['IsImplied']
603
+ # (np = x_pi_for.xpath('orm:NestedPredicate')[0]) &&
604
+ # np['IsImplied']
599
605
  # pi = nil
600
606
  # end
601
607
 
602
608
  # Get the RoleSequence:
603
- x_roles = x.elements.to_a("orm:RoleSequence/orm:Role")
609
+ x_roles = x.xpath("orm:RoleSequence/orm:Role")
604
610
  next if x_roles.size == 0
605
611
  roles = map_roles(x_roles, "uniqueness constraint #{name}")
606
612
  next if !roles
607
613
 
608
614
  # There is an implicit uniqueness constraint when any object plays a unary. Skip it.
609
615
  if (x_roles.size == 1 &&
610
- (id = x_roles[0].attributes['ref']) &&
616
+ (id = x_roles[0]['ref']) &&
611
617
  (x_role = @x_by_id[id]) &&
612
- x_role.parent.elements.size == 2 &&
613
- (sibling = x_role.parent.elements[2]) &&
614
- (ib_id = sibling.elements[1].attributes['ref']) &&
618
+ (nodes = x_role.parent.elements).size == 2 &&
619
+ (sibling = nodes[1]) &&
620
+ # x_role.parent.children.size == 2 &&
621
+ # (sibling = x_role.parent.children[1]) &&
622
+ (ib_id = sibling.elements[0]['ref']) &&
615
623
  (ib = @x_by_id[ib_id]) &&
616
- ib.attributes['IsImplicitBooleanValue'])
624
+ ib['IsImplicitBooleanValue'])
617
625
  unary_identifier = true
618
626
  end
619
627
 
620
628
  if (mc = @mandatory_constraints_by_rs[roles])
621
629
  # Remove absorbed mandatory constraints, leaving residual ones.
622
- # puts "Absorbing MC #{mc.attributes['Name']}"
630
+ # puts "Absorbing MC #{mc['Name']}"
623
631
  @mandatory_constraints_by_rs.delete(roles)
624
- @mandatory_constraint_rs_by_id.delete(mc.attributes['id'])
632
+ @mandatory_constraint_rs_by_id.delete(mc['id'])
625
633
  end
626
634
 
627
635
  # A UC that spans more than one Role of a fact will be a Preferred Id for the implied object
@@ -656,18 +664,18 @@ module ActiveFacts
656
664
  end
657
665
 
658
666
  def read_exclusion_constraints
659
- x_exclusion_constraints = @x_model.elements.to_a("orm:Constraints/orm:ExclusionConstraint")
667
+ x_exclusion_constraints = @x_model.xpath("orm:Constraints/orm:ExclusionConstraint")
660
668
  x_exclusion_constraints.each{|x|
661
- name = x.attributes["Name"] || ''
669
+ name = x["Name"] || ''
662
670
  name.gsub!(/\s/,'')
663
671
  name = nil if name.size == 0
664
- x_mandatory = (m = x.elements.to_a("orm:ExclusiveOrMandatoryConstraint")[0]) &&
665
- @x_by_id[mc_id = m.attributes['ref']]
672
+ x_mandatory = (m = x.xpath("orm:ExclusiveOrMandatoryConstraint")[0]) &&
673
+ @x_by_id[mc_id = m['ref']]
666
674
  role_sequences =
667
- x.elements.to_a("orm:RoleSequences/orm:RoleSequence").map{|x_rs|
668
- x_role_refs = x_rs.elements.to_a("orm:Role")
675
+ x.xpath("orm:RoleSequences/orm:RoleSequence").map{|x_rs|
676
+ x_role_refs = x_rs.xpath("orm:Role")
669
677
  map_roles(
670
- x_role_refs , # .map{|xr| @x_by_id[xr.attributes['ref']] },
678
+ x_role_refs , # .map{|xr| @x_by_id[xr['ref']] },
671
679
  "exclusion constraint #{name}"
672
680
  )
673
681
  }
@@ -690,16 +698,16 @@ module ActiveFacts
690
698
  end
691
699
 
692
700
  def read_equality_constraints
693
- x_equality_constraints = @x_model.elements.to_a("orm:Constraints/orm:EqualityConstraint")
701
+ x_equality_constraints = @x_model.xpath("orm:Constraints/orm:EqualityConstraint")
694
702
  x_equality_constraints.each{|x|
695
- name = x.attributes["Name"] || ''
703
+ name = x["Name"] || ''
696
704
  name.gsub!(/\s/,'')
697
705
  name = nil if name.size == 0
698
706
  role_sequences =
699
- x.elements.to_a("orm:RoleSequences/orm:RoleSequence").map{|x_rs|
700
- x_role_refs = x_rs.elements.to_a("orm:Role")
707
+ x.xpath("orm:RoleSequences/orm:RoleSequence").map{|x_rs|
708
+ x_role_refs = x_rs.xpath("orm:Role")
701
709
  map_roles(
702
- x_role_refs , # .map{|xr| @x_by_id[xr.attributes['ref']] },
710
+ x_role_refs , # .map{|xr| @x_by_id[xr['ref']] },
703
711
  "equality constraint #{name}"
704
712
  )
705
713
  }
@@ -715,16 +723,16 @@ module ActiveFacts
715
723
  end
716
724
 
717
725
  def read_subset_constraints
718
- x_subset_constraints = @x_model.elements.to_a("orm:Constraints/orm:SubsetConstraint")
726
+ x_subset_constraints = @x_model.xpath("orm:Constraints/orm:SubsetConstraint")
719
727
  x_subset_constraints.each{|x|
720
- name = x.attributes["Name"] || ''
728
+ name = x["Name"] || ''
721
729
  name.gsub!(/\s/,'')
722
730
  name = nil if name.size == 0
723
731
  role_sequences =
724
- x.elements.to_a("orm:RoleSequences/orm:RoleSequence").map{|x_rs|
725
- x_role_refs = x_rs.elements.to_a("orm:Role")
732
+ x.xpath("orm:RoleSequences/orm:RoleSequence").map{|x_rs|
733
+ x_role_refs = x_rs.xpath("orm:Role")
726
734
  map_roles(
727
- x_role_refs , # .map{|xr| @x_by_id[xr.attributes['ref']] },
735
+ x_role_refs , # .map{|xr| @x_by_id[xr['ref']] },
728
736
  "equality constraint #{name}"
729
737
  )
730
738
  }
@@ -739,12 +747,12 @@ module ActiveFacts
739
747
  end
740
748
 
741
749
  def read_ring_constraints
742
- x_ring_constraints = @x_model.elements.to_a("orm:Constraints/orm:RingConstraint")
750
+ x_ring_constraints = @x_model.xpath("orm:Constraints/orm:RingConstraint")
743
751
  x_ring_constraints.each{|x|
744
- name = x.attributes["Name"] || ''
752
+ name = x["Name"] || ''
745
753
  name.gsub!(/\s/,'')
746
754
  name = nil if name.size == 0
747
- type = x.attributes["Type"]
755
+ type = x["Type"]
748
756
  # begin
749
757
  # # Convert the RingConstraint name to a number:
750
758
  # type_num = eval("::ActiveFacts::RingConstraint::#{type}")
@@ -752,8 +760,8 @@ module ActiveFacts
752
760
  # throw "RingConstraint type #{type} isn't known"
753
761
  # end
754
762
 
755
- from, to = *x.elements.to_a("orm:RoleSequence/orm:Role").map{|xr|
756
- @by_id[xr.attributes['ref']]
763
+ from, to = *x.xpath("orm:RoleSequence/orm:Role").map{|xr|
764
+ @by_id[xr['ref']]
757
765
  }
758
766
  rc = @constellation.RingConstraint(:new)
759
767
  rc.vocabulary = @vocabulary
@@ -766,7 +774,7 @@ module ActiveFacts
766
774
  end
767
775
 
768
776
  def read_frequency_constraints
769
- x_frequency_constraints = @x_model.elements.to_a("orm:Constraints/orm:FrequencyConstraint")
777
+ x_frequency_constraints = @x_model.xpath("orm:Constraints/orm:FrequencyConstraint")
770
778
  # REVISIT: FrequencyConstraints not handled yet
771
779
  end
772
780
 
@@ -775,39 +783,39 @@ module ActiveFacts
775
783
 
776
784
  # Value instances first, then entities then facts:
777
785
 
778
- x_values = @x_model.elements.to_a("orm:Objects/orm:ValueType/orm:Instances/orm:ValueTypeInstance/orm:Value")
779
- #pp x_values.map{|v| [ v.parent.attributes['id'], v.text ] }
786
+ x_values = @x_model.xpath("orm:Objects/orm:ValueType/orm:Instances/orm:ValueTypeInstance/orm:Value")
787
+ #pp x_values.map{|v| [ v.parent['id'], v.text ] }
780
788
  x_values.each{|v|
781
- id = v.parent.attributes['id']
789
+ id = v.parent['id']
782
790
  # Get details of the ValueType:
783
791
  xvt = v.parent.parent.parent
784
- vt_id = xvt.attributes['id']
785
- vtname = xvt.attributes['Name'] || ''
792
+ vt_id = xvt['id']
793
+ vtname = xvt['Name'] || ''
786
794
  vtname.gsub!(/\s/,'')
787
795
  vtname = nil if name.size == 0
788
796
  vt = @by_id[vt_id]
789
797
  throw "ValueType #{vtname} not found" unless vt
790
798
 
791
- i = Instance.new(vt, v.text)
799
+ i = Instance.new(vt, [v.text, is_a_string(v.text), nil])
792
800
  @by_id[id] = i
793
801
  # show_xmlobj(v)
794
802
  }
795
803
 
796
804
  # Use the "id" attribute of EntityTypeInstance
797
- x_entities = @x_model.elements.to_a("orm:Objects/orm:EntityType/orm:Instances/orm:EntityTypeInstance")
805
+ x_entities = @x_model.xpath("orm:Objects/orm:EntityType/orm:Instances/orm:EntityTypeInstance")
798
806
  #pp x_entities
799
807
  # x_entities.each{|v| show_xmlobj(v) }
800
808
  last_et_id = nil
801
809
  last_et = nil
802
810
  et = nil
803
811
  x_entities.each{|v|
804
- id = v.attributes['id']
812
+ id = v['id']
805
813
 
806
814
  # Get details of the EntityType:
807
815
  xet = v.parent.parent
808
- et_id = xet.attributes['id']
816
+ et_id = xet['id']
809
817
  if (et_id != last_et_id)
810
- etname = xet.attributes['Name'] || ''
818
+ etname = xet['Name'] || ''
811
819
  etname.gsub!(/\s/,'')
812
820
  etname = nil if name.size == 0
813
821
  last_et = et = @by_id[et_id]
@@ -815,7 +823,7 @@ module ActiveFacts
815
823
  throw "EntityType #{etname} not found" unless et
816
824
  end
817
825
 
818
- instance = Instance.new(et)
826
+ instance = Instance.new(et, nil)
819
827
  @by_id[id] = instance
820
828
  # puts "Made new EntityType #{etname}"
821
829
  }
@@ -825,19 +833,19 @@ module ActiveFacts
825
833
  entity_count = 0
826
834
  pi_fact_count = 0
827
835
  x_entities.each{|v|
828
- id = v.attributes['id']
836
+ id = v['id']
829
837
  instance = @by_id[id]
830
- et = @by_id[v.parent.parent.attributes['id']]
838
+ et = @by_id[v.parent.parent['id']]
831
839
  next unless (preferred_id = et.preferred_identifier)
832
840
 
833
841
  # puts "Create identifying facts using #{preferred_id}"
834
842
 
835
843
  # Collate the referenced objects by role:
836
- role_instances = v.elements[1].elements.inject({}){|h, v|
837
- etri = @x_by_id[v.attributes['ref']]
838
- x_role_id = etri.parent.parent.attributes['id']
844
+ role_instances = v.elements[0].elements.inject({}){|h, v|
845
+ etri = @x_by_id[v['ref']]
846
+ x_role_id = etri.parent.parent['id']
839
847
  role = @by_id[x_role_id]
840
- object = @by_id[object_id = etri.attributes['ref']]
848
+ object = @by_id[object_id = etri['ref']]
841
849
  h[role] = object
842
850
  h
843
851
  }
@@ -862,14 +870,14 @@ module ActiveFacts
862
870
  # puts "Created #{pi_fact_count} facts to identify #{entity_count} entities"
863
871
 
864
872
  # Use the "ref" attribute of FactTypeRoleInstance:
865
- x_fact_roles = @x_model.elements.to_a("orm:Facts/orm:Fact/orm:Instances/orm:FactTypeInstance/orm:RoleInstances/orm:FactTypeRoleInstance")
873
+ x_fact_roles = @x_model.xpath("orm:Facts/orm:Fact/orm:Instances/orm:FactTypeInstance/orm:RoleInstances/orm:FactTypeRoleInstance")
866
874
 
867
875
  last_id = nil
868
876
  last_fact_type = nil
869
877
  fact_roles = []
870
878
  x_fact_roles.each{|v|
871
- fact_type_id = v.parent.parent.parent.parent.attributes['id']
872
- id = v.parent.parent.attributes['id']
879
+ fact_type_id = v.parent.parent.parent.parent['id']
880
+ id = v.parent.parent['id']
873
881
  fact_type = @by_id[fact_type_id]
874
882
  throw "Fact type #{fact_type_id} not found" unless fact_type
875
883
 
@@ -884,11 +892,11 @@ module ActiveFacts
884
892
  #show_xmlobj(v)
885
893
 
886
894
  last_id = id
887
- x_role_instance = @x_by_id[v.attributes['ref']]
888
- x_role_id = x_role_instance.parent.parent.attributes['id']
895
+ x_role_instance = @x_by_id[v['ref']]
896
+ x_role_id = x_role_instance.parent.parent['id']
889
897
  role = @by_id[x_role_id]
890
898
  throw "Role not found for instance #{x_role_id}" unless role
891
- instance_id = x_role_instance.attributes['ref']
899
+ instance_id = x_role_instance['ref']
892
900
  instance = @by_id[instance_id]
893
901
  throw "Instance not found for FactRole #{instance_id}" unless instance
894
902
  fact_roles << FactRole.new(role, instance)
@@ -901,20 +909,25 @@ module ActiveFacts
901
909
 
902
910
  end
903
911
 
912
+ # Detect numeric data and denote it as a string:
913
+ def is_a_string(value)
914
+ value =~ /[^ \d.]/
915
+ end
916
+
904
917
  def read_rest
905
918
  puts "Reading Implied Facts (not yet)"
906
919
  =begin
907
- x_implied_facts = @x_model.elements.to_a("orm:Facts/orm:ImpliedFact")
920
+ x_implied_facts = @x_model.xpath("orm:Facts/orm:ImpliedFact")
908
921
  pp x_implied_facts
909
922
  =end
910
923
  puts "Reading Data Types (not yet)"
911
924
  =begin
912
- x_datatypes = @x_model.elements.to_a("orm:DataTypes/*")
925
+ x_datatypes = @x_model.xpath("orm:DataTypes/*")
913
926
  pp x_datatypes
914
927
  =end
915
928
  puts "Reading Reference Mode Kinds (not yet)"
916
929
  =begin
917
- x_refmodekinds = @x_model.elements.to_a("orm:ReferenceModeKinds/*")
930
+ x_refmodekinds = @x_model.xpath("orm:ReferenceModeKinds/*")
918
931
  pp x_refmodekinds
919
932
  =end
920
933
  end
@@ -931,9 +944,9 @@ module ActiveFacts
931
944
  parentage.each{|p|
932
945
  next if REXML::Document === p
933
946
  puts "#{indent}\t#{p.name}#{
934
- }#{(n = p.attributes['Name']) ? " Name='#{n}'" : ""
935
- }#{(id = p.attributes['id']) ? " #{id}" : ""
936
- }#{(ref = p.attributes['ref']) ? " -> #{ref}" : ""
947
+ }#{(n = p['Name']) ? " Name='#{n}'" : ""
948
+ }#{(id = p['id']) ? " #{id}" : ""
949
+ }#{(ref = p['ref']) ? " -> #{ref}" : ""
937
950
  }#{/\S/ === ((text = p.text)) ? " "+text.inspect : ""
938
951
  }"
939
952
  show_xmlobj(@x_by_id[ref], "\t#{indent}") if ref