xmi 0.3.21 → 0.5.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 (54) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/release.yml +13 -6
  3. data/.gitignore +2 -1
  4. data/.rubocop.yml +12 -13
  5. data/.rubocop_todo.yml +150 -13
  6. data/CHANGELOG.md +55 -0
  7. data/CODE_OF_CONDUCT.md +84 -0
  8. data/Gemfile +10 -0
  9. data/README.adoc +319 -6
  10. data/benchmark_parse.rb +60 -0
  11. data/docs/migration.md +141 -0
  12. data/docs/versioning.md +255 -0
  13. data/lib/xmi/add.rb +14 -38
  14. data/lib/xmi/{the_custom_profile.rb → custom_profile.rb} +25 -25
  15. data/lib/xmi/delete.rb +14 -38
  16. data/lib/xmi/difference.rb +14 -38
  17. data/lib/xmi/documentation.rb +16 -101
  18. data/lib/xmi/ea_root.rb +114 -33
  19. data/lib/xmi/extension.rb +6 -6
  20. data/lib/xmi/namespace/dynamic.rb +28 -0
  21. data/lib/xmi/namespace/omg.rb +81 -0
  22. data/lib/xmi/namespace/sparx.rb +39 -0
  23. data/lib/xmi/namespace.rb +9 -0
  24. data/lib/xmi/namespace_detector.rb +138 -0
  25. data/lib/xmi/namespace_registry.rb +119 -0
  26. data/lib/xmi/parsing.rb +113 -0
  27. data/lib/xmi/replace.rb +14 -38
  28. data/lib/xmi/root.rb +49 -213
  29. data/lib/xmi/sparx/connector.rb +241 -0
  30. data/lib/xmi/sparx/custom_profile.rb +19 -0
  31. data/lib/xmi/sparx/diagram.rb +97 -0
  32. data/lib/xmi/sparx/ea_stub.rb +20 -0
  33. data/lib/xmi/{extensions/eauml.rb → sparx/ea_uml.rb} +3 -2
  34. data/lib/xmi/sparx/element.rb +453 -0
  35. data/lib/xmi/sparx/extension.rb +43 -0
  36. data/lib/xmi/{extensions → sparx}/gml.rb +9 -3
  37. data/lib/xmi/sparx/mappings/base_mapping.rb +182 -0
  38. data/lib/xmi/sparx/mappings.rb +10 -0
  39. data/lib/xmi/sparx/primitive_type.rb +18 -0
  40. data/lib/xmi/sparx/root.rb +60 -0
  41. data/lib/xmi/sparx/sys_ph_s.rb +18 -0
  42. data/lib/xmi/sparx.rb +17 -1376
  43. data/lib/xmi/type.rb +37 -0
  44. data/lib/xmi/uml.rb +191 -469
  45. data/lib/xmi/v20110701.rb +81 -0
  46. data/lib/xmi/v20131001.rb +68 -0
  47. data/lib/xmi/v20161101.rb +61 -0
  48. data/lib/xmi/version.rb +1 -1
  49. data/lib/xmi/version_registry.rb +164 -0
  50. data/lib/xmi/versioned.rb +142 -0
  51. data/lib/xmi.rb +83 -11
  52. data/scripts-xmi-profile/profile_xmi_simple.rb +213 -0
  53. data/xmi.gemspec +3 -9
  54. metadata +38 -77
data/README.adoc CHANGED
@@ -6,6 +6,13 @@ This Ruby object mapper is a module designed to convert XMI (XML Metadata Interc
6
6
 
7
7
  == Installation
8
8
 
9
+ === Requirements
10
+
11
+ * Ruby 3.0 or later
12
+ * lutaml-model 0.8.0 or later (for `Lutaml::Xml::Namespace` support)
13
+
14
+ === Installing the gem
15
+
9
16
  Add this line to your application's Gemfile:
10
17
 
11
18
  [source,ruby]
@@ -37,7 +44,7 @@ To convert XMI file into Ruby objects, run:
37
44
  ----
38
45
  xml = "path/to/your/file.xmi"
39
46
  xml_content = File.read(xml)
40
- xmi_root_model = Xmi::Sparx::SparxRoot.parse_xml(xml_content)
47
+ xmi_root_model = Xmi::Sparx::Root.parse_xml(xml_content)
41
48
  ----
42
49
 
43
50
  This method takes the path to an XMI file and generate the Ruby objects.
@@ -52,12 +59,12 @@ Xmi::EaRoot.load_extension("path/to/your/extension.xml")
52
59
 
53
60
  xml = "path/to/your/file.xmi"
54
61
  xml_content = File.read(xml)
55
- xmi_root_model = Xmi::Sparx::SparxRoot.parse_xml(xml_content)
62
+ xmi_root_model = Xmi::Sparx::Root.parse_xml(xml_content)
56
63
  ----
57
64
 
58
65
  `Xmi::EaRoot.load_extension` takes the path to an XML file and generate the
59
66
  Ruby classes and modules defined in XML file dynamically.
60
- Then, you can generate Ruby objects by `Xmi::Sparx::SparxRoot.parse_xml`.
67
+ Then, you can generate Ruby objects by `Xmi::Sparx::Root.parse_xml`.
61
68
 
62
69
  === Output Classes and Modules Generated from Extension into Ruby Files
63
70
 
@@ -154,14 +161,320 @@ module Xmi
154
161
  end
155
162
  ----
156
163
 
164
+ == Namespace Architecture
165
+
166
+ === General
167
+
168
+ The XMI library normalizes all input namespace versions to a canonical version
169
+ (20131001) before parsing. This allows the library to handle XMI files with
170
+ different namespace versions (2011, 2013, 2016) using a single set of model
171
+ classes.
172
+
173
+ === Namespace Normalization
174
+
175
+ The normalization is performed by [`SparxRoot.replace_xmlns`](lib/xmi/sparx.rb:1158) which rewrites
176
+ namespace URIs in the input XML:
177
+
178
+ .Example of namespace normalization
179
+ ====
180
+ [source,xml]
181
+ ----
182
+ <!-- Input XMI with various namespace versions -->
183
+ <xmi:XMI xmlns:xmi="http://www.omg.org/spec/XMI/20110701"
184
+ xmlns:uml="http://www.omg.org/spec/UML/20161101">
185
+ <!-- content -->
186
+ </xmi:XMI>
187
+
188
+ <!-- After normalization, becomes -->
189
+ <xmi:XMI xmlns:xmi="http://www.omg.org/spec/XMI/20131001"
190
+ xmlns:uml="http://www.omg.org/spec/UML/20131001">
191
+ <!-- content -->
192
+ </xmi:XMI>
193
+ ----
194
+ ====
195
+
196
+ === Namespace Classes
197
+
198
+ Namespace classes are defined in [`lib/xmi/namespace/omg.rb`](lib/xmi/namespace/omg.rb:1):
199
+
200
+ * **Version-specific classes**: `Xmi20110701`, `Uml20131001`, etc.
201
+ * **Version-agnostic aliases**: `Xmi`, `Uml`, `UmlDi`, `UmlDc`
202
+
203
+ The aliases inherit from the 20131001 versions (the normalized version):
204
+
205
+ .Alias class definitions
206
+ ====
207
+ [source,ruby]
208
+ ----
209
+ class Xmi < Lutaml::Xml::Namespace
210
+ uri "http://www.omg.org/spec/XMI/20131001"
211
+ prefix_default "xmi"
212
+ end
213
+
214
+ class Uml < Lutaml::Xml::Namespace
215
+ uri "http://www.omg.org/spec/UML/20131001"
216
+ prefix_default "uml"
217
+ end
218
+ ----
219
+ ====
220
+
221
+ This allows models to use clean namespace references without worrying about
222
+ specific versions:
223
+
224
+ .Using namespace aliases in model definitions
225
+ ====
226
+ [source,ruby]
227
+ ----
228
+ class MyModel < Lutaml::Model::Serializable
229
+ xml do
230
+ root "Model"
231
+ namespace ::Xmi::Namespace::Omg::Uml
232
+ namespace_scope [
233
+ ::Xmi::Namespace::Omg::Xmi,
234
+ ::Xmi::Namespace::Omg::Uml,
235
+ ::Xmi::Namespace::Omg::UmlDi,
236
+ ]
237
+ end
238
+ end
239
+ ----
240
+ ====
241
+
242
+
243
+ === Namespace-Qualified Mapping Declaration
244
+
245
+ All element and attribute mappings explicitly declare their namespace to ensure
246
+ proper XML parsing and serialization. This is required even when types have
247
+ `xml_namespace` declared.
248
+
249
+ .Element mapping with namespace
250
+ ====
251
+ [source,ruby]
252
+ ----
253
+ xml do
254
+ root "Model"
255
+ namespace ::Xmi::Namespace::Omg::Uml
256
+
257
+ # Element mapping with explicit namespace
258
+ map_element "packagedElement", to: :packaged_element,
259
+ namespace: "http://www.omg.org/spec/UML/20131001",
260
+ prefix: "uml"
261
+ end
262
+ ----
263
+ ====
264
+
265
+ === Attribute Namespace Handling
266
+
267
+ For attributes with namespace prefixes in XML (e.g., `<uml:Model xmi:id="...">`),
268
+ both `namespace:` and `prefix:` parameters are required in `map_attribute`, even
269
+ when the attribute type has `xml_namespace` declared.
270
+
271
+ .Attribute mapping with namespace prefix
272
+ ====
273
+ [source,ruby]
274
+ ----
275
+ xml do
276
+ root "Model"
277
+ namespace ::Xmi::Namespace::Omg::Uml
278
+
279
+ # XMI-typed attribute with explicit namespace declaration
280
+ map_attribute "id", to: :id,
281
+ namespace: "http://www.omg.org/spec/XMI/20131001",
282
+ prefix: "xmi"
283
+
284
+ # Regular attribute without namespace prefix
285
+ map_attribute "name", to: :name
286
+ end
287
+ ----
288
+
289
+ Without explicit namespace declarations in `map_attribute`, attributes with
290
+ namespace prefixes will parse as `nil`.
291
+ ====
292
+
293
+ === Sparx Systems Namespaces
294
+
295
+ Sparx-specific namespaces are defined in [`lib/xmi/namespace/sparx.rb`](lib/xmi/namespace/sparx.rb:1):
296
+
297
+ * **SysPhS** - System Physical Systems profile
298
+ * **GML** - Geography Markup Language profile
299
+ * **EaUml** - Enterprise Architect UML extensions
300
+ * **CustomProfile** - Custom profile support
301
+ * **CityGML** - City Geography Markup Language
302
+
303
+ .Using Sparx namespaces
304
+ ====
305
+ [source,ruby]
306
+ ----
307
+ xml do
308
+ root "ModelicaParameter"
309
+ namespace ::Xmi::Namespace::Sparx::SysPhS
310
+
311
+ map_attribute "base_Package", to: :base_package
312
+ map_attribute "name", to: :name
313
+ end
314
+ ----
315
+ ====
316
+
317
+ === Extension Namespaces
318
+
319
+ Dynamically loaded extensions (via [`EaRoot.load_extension`](lib/xmi/ea_root.rb:54)) also use
320
+ namespace-qualified mappings:
321
+
322
+ .Extension with namespace mapping
323
+ ====
324
+ [source,ruby]
325
+ ----
326
+ map_element "ApplicationSchema", to: :gml_application_schema,
327
+ namespace: "http://www.sparxsystems.com/profiles/GML/1.0",
328
+ prefix: "GML"
329
+ ----
330
+ ====
331
+
157
332
  === Limitation
158
333
 
159
334
  This module is designed to work with XMI files generated by Enterprise
160
335
  Architect. It may not work with other XMI files.
161
336
 
162
- Some XML elements, for example `GML:ApplicationSchema`, use `xmlns` as
163
- attributes. As `Lutaml::Model::Serializable` uses `xmlns` as an internal
164
- keyword, these attributes will be renamed to `altered_xmlns`.
337
+ == Version-Aware Parsing
338
+
339
+ The XMI gem supports parsing XMI files from different versions (2.1, 2.5.1, 2.5.2) without preprocessing normalization.
340
+
341
+ === Automatic Version Detection
342
+
343
+ [source,ruby]
344
+ ----
345
+ require 'xmi'
346
+
347
+ # Parse with automatic version detection
348
+ doc = Xmi.parse(xml_content)
349
+
350
+ # Get version information without parsing
351
+ info = Xmi::Parsing.detect_version(xml_content)
352
+ puts info[:xmi_version] # => "20131001"
353
+ puts info[:uml_version] # => "20131001"
354
+ ----
355
+
356
+ === Explicit Version Specification
357
+
358
+ [source,ruby]
359
+ ----
360
+ # Parse with explicit version
361
+ doc = Xmi.parse_with_version(xml_content, "20131001")
362
+
363
+ # Check if version is supported
364
+ Xmi::Parsing.version_supported?("20131001") # => true
365
+ Xmi::Parsing.supported_versions # => ["20110701", "20131001", "20161101"]
366
+ ----
367
+
368
+ === Supported Versions
369
+
370
+ | Version | Date | XMI Namespace |
371
+ |---------|------|---------------|
372
+ | XMI 2.1 | 20110701 | `http://www.omg.org/spec/XMI/20110701` |
373
+ | XMI 2.5.1 | 20131001 | `http://www.omg.org/spec/XMI/20131001` |
374
+ | XMI 2.5.2 | 20161101 | `http://www.omg.org/spec/XMI/20161101` |
375
+
376
+ === Fallback Chain
377
+
378
+ Version-specific registers form a fallback hierarchy:
379
+
380
+ ....
381
+ xmi_20161101
382
+ ↓ fallback
383
+ xmi_20131001
384
+ ↓ fallback
385
+ xmi_20110701
386
+ ↓ fallback
387
+ xmi_common
388
+ ↓ fallback
389
+ default
390
+ ....
391
+
392
+ Types not found in a version fall back to older versions. For example,
393
+ XMI 2.5.2 uses XMI 2.5.1's `Documentation` model (same structure).
394
+
395
+ === Migration from Old API
396
+
397
+ The old API used `SparxRoot.parse_xml` with automatic namespace normalization:
398
+
399
+ [source,ruby]
400
+ ----
401
+ # Old API (still works, but version-aware API is recommended)
402
+ doc = Xmi::Sparx::SparxRoot.parse_xml(xml_content)
403
+ ----
404
+
405
+ The new version-aware API:
406
+
407
+ [source,ruby]
408
+ ----
409
+ # New API - explicit about version handling
410
+ doc = Xmi::Sparx::SparxRoot.parse_xml_with_versioning(xml_content)
411
+
412
+ # Or use the module-level API
413
+ doc = Xmi.parse(xml_content)
414
+ ----
415
+
416
+ === Enterprise Architect Quirks
417
+
418
+ Enterprise Architect (EA) generates XMI files with several non-standard
419
+ behaviors that this library handles through preprocessing.
420
+
421
+ ==== OMG Namespace Version Normalization
422
+
423
+ OMG publishes XMI and UML specifications with dated namespace URIs
424
+ (e.g., `http://www.omg.org/spec/XMI/20110701`, `20131001`, `20161101`).
425
+ While these represent different specification versions, the core XMI
426
+ structure is compatible across versions.
427
+
428
+ This library normalizes all OMG namespace versions to the canonical
429
+ `20131001` version during parsing, allowing a single set of model classes
430
+ to handle all versions.
431
+
432
+ [source,xml]
433
+ ----
434
+ <!-- Input with mixed versions -->
435
+ <xmi:XMI xmlns:xmi="http://www.omg.org/spec/XMI/20110701"
436
+ xmlns:uml="http://www.omg.org/spec/UML/20161101">
437
+
438
+ <!-- After normalization -->
439
+ <xmi:XMI xmlns:xmi="http://www.omg.org/spec/XMI/20131001"
440
+ xmlns:uml="http://www.omg.org/spec/UML/20131001">
441
+ ----
442
+
443
+ ==== EA's Misuse of the `xmlns` Attribute
444
+
445
+ In standard XML, the `xmlns` attribute has special meaning—it declares the
446
+ default namespace for an element and its descendants. The XML specification
447
+ reserves this attribute name for namespace declarations.
448
+
449
+ However, Enterprise Architect incorrectly uses `xmlns` as a *regular data
450
+ attribute* on certain stereotype elements, storing arbitrary URI values that
451
+ have nothing to do with XML namespace declarations. This is a violation of
452
+ XML conventions.
453
+
454
+ This quirk has been observed on:
455
+ - `GML:ApplicationSchema` (Geography Markup Language profile)
456
+ - `CityGML:ApplicationSchema` (City Geography Markup Language profile)
457
+
458
+ [source,xml]
459
+ ----
460
+ <!-- EA-generated XMI with xmlns as a data attribute -->
461
+ <GML:ApplicationSchema xmlns="http://some-uri-value"
462
+ targetNamespace="http://example.org/ns">
463
+ ----
464
+
465
+ This creates parsing conflicts because XML libraries treat `xmlns` as a
466
+ reserved keyword. This library works around the issue by renaming the
467
+ `xmlns` attribute to `altered_xmlns` before parsing:
468
+
469
+ [source,xml]
470
+ ----
471
+ <!-- After preprocessing -->
472
+ <GML:ApplicationSchema altered_xmlns="http://some-uri-value"
473
+ targetNamespace="http://example.org/ns">
474
+ ----
475
+
476
+ The corresponding model classes (e.g., `Xmi::Sparx::Gml::ApplicationSchema`)
477
+ define an `altered_xmlns` attribute to receive this value.
165
478
 
166
479
  == Development
167
480
 
@@ -0,0 +1,60 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Benchmark script for XMI parsing performance.
4
+ # Usage: bundle exec ruby benchmark_parse.rb
5
+ #
6
+ # Parses the full-242.xmi fixture (3.5 MB) multiple times and reports
7
+ # average, min, and max parse times.
8
+
9
+ require "bundler/setup"
10
+ require "xmi"
11
+
12
+ FIXTURE_PATH = File.join(__dir__, "spec", "fixtures", "full-242.xmi")
13
+ WARMUP_RUNS = 2
14
+ BENCH_RUNS = 5
15
+
16
+ abort "Fixture not found: #{FIXTURE_PATH}" unless File.exist?(FIXTURE_PATH)
17
+
18
+ xml_content = File.read(FIXTURE_PATH)
19
+ file_size_mb = File.size(FIXTURE_PATH).to_f / (1024 * 1024)
20
+
21
+ puts "XMI Parsing Benchmark"
22
+ puts "=" * 50
23
+ puts "File: #{FIXTURE_PATH}"
24
+ puts "Size: #{file_size_mb.round(2)} MB"
25
+ puts "Ruby: #{RUBY_VERSION} (#{RUBY_PLATFORM})"
26
+ puts "Warmup runs: #{WARMUP_RUNS}"
27
+ puts "Benchmark runs: #{BENCH_RUNS}"
28
+ puts
29
+
30
+ # Warmup
31
+ puts "Warming up..."
32
+ WARMUP_RUNS.times do |i|
33
+ GC.start
34
+ Xmi::Sparx::SparxRoot.parse_xml(xml_content)
35
+ puts " Warmup #{i + 1}/#{WARMUP_RUNS} complete"
36
+ end
37
+
38
+ # Benchmark
39
+ puts "Benchmarking..."
40
+ times = BENCH_RUNS.times.map do |i|
41
+ GC.start
42
+ t0 = Process.clock_gettime(Process::CLOCK_MONOTONIC)
43
+ Xmi::Sparx::SparxRoot.parse_xml(xml_content)
44
+ t1 = Process.clock_gettime(Process::CLOCK_MONOTONIC)
45
+ elapsed = t1 - t0
46
+ puts " Run #{i + 1}/#{BENCH_RUNS}: #{elapsed.round(3)}s"
47
+ elapsed
48
+ end
49
+
50
+ avg = times.sum / times.size
51
+ min = times.min
52
+ max = times.max
53
+
54
+ puts
55
+ puts "Results"
56
+ puts "-" * 50
57
+ puts "Average: #{avg.round(3)} s"
58
+ puts "Min: #{min.round(3)} s"
59
+ puts "Max: #{max.round(3)} s"
60
+ puts "StdDev: #{Math.sqrt(times.sum { |t| (t - avg)**2 } / times.size).round(3)} s"
data/docs/migration.md ADDED
@@ -0,0 +1,141 @@
1
+ # Migration Guide: Version-Aware Parsing
2
+
3
+ ## Overview
4
+
5
+ This guide helps you migrate from the old XMI parsing API to the new version-aware parsing system.
6
+
7
+ ## Old API (Pre-Versioning)
8
+
9
+ The old API used `SparxRoot.parse_xml` with automatic namespace normalization:
10
+
11
+ ```ruby
12
+ require 'xmi'
13
+
14
+ # Old approach - normalizes all namespaces to 20131001
15
+ doc = Xmi::Sparx::SparxRoot.parse_xml(xml_content)
16
+ ```
17
+
18
+ This approach:
19
+ - Preprocesses XML to normalize namespace versions
20
+ - Uses a single set of model classes
21
+ - Works for all XMI versions
22
+
23
+ ## New API (Version-Aware)
24
+
25
+ The new API detects and uses the correct version automatically:
26
+
27
+ ```ruby
28
+ require 'xmi'
29
+
30
+ # New approach - version-aware parsing
31
+ doc = Xmi.parse(xml_content)
32
+
33
+ # Or for Sparx EA files
34
+ doc = Xmi::Sparx::SparxRoot.parse_xml_with_versioning(xml_content)
35
+ ```
36
+
37
+ This approach:
38
+ - Detects version from XML namespace
39
+ - Uses version-specific model classes when needed
40
+ - Falls back gracefully for shared types
41
+
42
+ ## Quick Migration
43
+
44
+ ### For Basic Parsing
45
+
46
+ ```ruby
47
+ # Before
48
+ doc = Xmi::Sparx::SparxRoot.parse_xml(xml_content)
49
+
50
+ # After
51
+ doc = Xmi::Sparx::SparxRoot.parse_xml_with_versioning(xml_content)
52
+
53
+ # Or
54
+ doc = Xmi.parse(xml_content)
55
+ ```
56
+
57
+ ### For Version Detection
58
+
59
+ ```ruby
60
+ # Before
61
+ # No built-in version detection
62
+
63
+ # After
64
+ info = Xmi::Parsing.detect_version(xml_content)
65
+ puts info[:xmi_version] # => "20131001"
66
+ ```
67
+
68
+ ### For Explicit Version
69
+
70
+ ```ruby
71
+ # Before
72
+ # No explicit version support
73
+
74
+ # After
75
+ doc = Xmi.parse_with_version(xml_content, "20131001")
76
+ ```
77
+
78
+ ## Benefits of Version-Aware Parsing
79
+
80
+ 1. **Correct Types**: Version-specific models are used when structures differ
81
+ 2. **No Preprocessing**: XML is parsed directly without modification
82
+ 3. **Graceful Fallback**: Shared types work across versions
83
+ 4. **Future Extensibility**: Easy to add new version support
84
+
85
+ ## When to Use Each API
86
+
87
+ | Use Case | Recommended API |
88
+ |----------|----------------|
89
+ | Sparx EA files | `Xmi::Sparx::SparxRoot.parse_xml_with_versioning` |
90
+ | General XMI files | `Xmi.parse` |
91
+ | Version detection | `Xmi::Parsing.detect_version` |
92
+ | Known version | `Xmi.parse_with_version(xml, version)` |
93
+
94
+ ## Backward Compatibility
95
+
96
+ The old `parse_xml` method still works but normalizes namespaces:
97
+
98
+ ```ruby
99
+ # Old API - still supported
100
+ doc = Xmi::Sparx::SparxRoot.parse_xml(xml_content)
101
+
102
+ # This internally normalizes to 20131001 namespace
103
+ ```
104
+
105
+ ## Troubleshooting
106
+
107
+ ### Version Not Detected
108
+
109
+ If version detection fails:
110
+
111
+ ```ruby
112
+ # Check what was detected
113
+ info = Xmi::Parsing.detect_version(xml_content)
114
+
115
+ # Use explicit version if needed
116
+ doc = Xmi.parse_with_version(xml_content, "20131001")
117
+ ```
118
+
119
+ ### Type Resolution Fails
120
+
121
+ If a type isn't resolved correctly:
122
+
123
+ ```ruby
124
+ # Initialize versioning explicitly
125
+ Xmi.init_versioning!
126
+
127
+ # Check what version was detected
128
+ info = Xmi::Parsing.detect_version(xml_content)
129
+
130
+ # Use explicit version
131
+ doc = Xmi.parse_with_version(xml_content, info[:xmi_version])
132
+ ```
133
+
134
+ ## API Comparison
135
+
136
+ | Old API | New API |
137
+ |---------|---------|
138
+ | `SparxRoot.parse_xml` | `SparxRoot.parse_xml_with_versioning` |
139
+ | (no detection) | `Xmi::Parsing.detect_version` |
140
+ | (no explicit) | `Xmi.parse_with_version` |
141
+ | `Xmi.parse` (not existed) | `Xmi.parse` (auto-detect) |