activefacts 0.7.3 → 0.8.5

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