expressir 2.1.30 → 2.1.31

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 (107) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/docs.yml +98 -0
  3. data/.github/workflows/links.yml +100 -0
  4. data/.github/workflows/rake.yml +4 -0
  5. data/.github/workflows/release.yml +5 -0
  6. data/.github/workflows/validate_schemas.yml +1 -1
  7. data/.gitignore +3 -0
  8. data/.rubocop.yml +1 -1
  9. data/.rubocop_todo.yml +244 -39
  10. data/Gemfile +2 -1
  11. data/README.adoc +621 -54
  12. data/docs/Gemfile +12 -0
  13. data/docs/_config.yml +141 -0
  14. data/docs/_guides/changes/changes-format.adoc +778 -0
  15. data/docs/_guides/changes/importing-eengine.adoc +898 -0
  16. data/docs/_guides/changes/index.adoc +396 -0
  17. data/docs/_guides/changes/programmatic-usage.adoc +1038 -0
  18. data/docs/_guides/changes/validating-changes.adoc +681 -0
  19. data/docs/_guides/cli/benchmark-performance.adoc +834 -0
  20. data/docs/_guides/cli/coverage-analysis.adoc +921 -0
  21. data/docs/_guides/cli/format-schemas.adoc +547 -0
  22. data/docs/_guides/cli/index.adoc +8 -0
  23. data/docs/_guides/cli/managing-changes.adoc +927 -0
  24. data/docs/_guides/cli/validate-ascii.adoc +645 -0
  25. data/docs/_guides/cli/validate-schemas.adoc +534 -0
  26. data/docs/_guides/index.adoc +165 -0
  27. data/docs/_guides/ler/creating-packages.adoc +664 -0
  28. data/docs/_guides/ler/index.adoc +305 -0
  29. data/docs/_guides/ler/loading-packages.adoc +707 -0
  30. data/docs/_guides/ler/package-formats.adoc +748 -0
  31. data/docs/_guides/ler/querying-packages.adoc +826 -0
  32. data/docs/_guides/ler/validating-packages.adoc +750 -0
  33. data/docs/_guides/liquid/basic-templates.adoc +813 -0
  34. data/docs/_guides/liquid/documentation-generation.adoc +1042 -0
  35. data/docs/_guides/liquid/drops-reference.adoc +829 -0
  36. data/docs/_guides/liquid/filters-and-tags.adoc +912 -0
  37. data/docs/_guides/liquid/index.adoc +468 -0
  38. data/docs/_guides/manifests/creating-manifests.adoc +483 -0
  39. data/docs/_guides/manifests/index.adoc +307 -0
  40. data/docs/_guides/manifests/resolving-manifests.adoc +557 -0
  41. data/docs/_guides/manifests/validating-manifests.adoc +713 -0
  42. data/docs/_guides/ruby-api/formatting-schemas.adoc +605 -0
  43. data/docs/_guides/ruby-api/index.adoc +257 -0
  44. data/docs/_guides/ruby-api/parsing-files.adoc +421 -0
  45. data/docs/_guides/ruby-api/search-engine.adoc +609 -0
  46. data/docs/_guides/ruby-api/working-with-repository.adoc +577 -0
  47. data/docs/_pages/data-model.adoc +665 -0
  48. data/docs/_pages/express-language.adoc +506 -0
  49. data/docs/_pages/getting-started.adoc +414 -0
  50. data/docs/_pages/index.adoc +116 -0
  51. data/docs/_pages/introduction.adoc +256 -0
  52. data/docs/_pages/ler-packages.adoc +837 -0
  53. data/docs/_pages/parsers.adoc +683 -0
  54. data/docs/_pages/schema-manifests.adoc +431 -0
  55. data/docs/_references/index.adoc +228 -0
  56. data/docs/_tutorials/creating-ler-package.adoc +735 -0
  57. data/docs/_tutorials/documentation-coverage.adoc +795 -0
  58. data/docs/_tutorials/index.adoc +221 -0
  59. data/docs/_tutorials/liquid-templates.adoc +806 -0
  60. data/docs/_tutorials/parsing-your-first-schema.adoc +522 -0
  61. data/docs/_tutorials/querying-schemas.adoc +751 -0
  62. data/docs/_tutorials/working-with-multiple-schemas.adoc +676 -0
  63. data/docs/index.adoc +242 -0
  64. data/docs/lychee.toml +84 -0
  65. data/examples/demo_ler_usage.sh +86 -0
  66. data/examples/ler/README.md +111 -0
  67. data/examples/ler/simple_example.ler +0 -0
  68. data/examples/ler/simple_schema.exp +33 -0
  69. data/examples/ler_build.rb +75 -0
  70. data/examples/ler_cli.rb +79 -0
  71. data/examples/ler_demo_complete.rb +276 -0
  72. data/examples/ler_query.rb +91 -0
  73. data/examples/ler_query_examples.rb +305 -0
  74. data/examples/ler_stats.rb +81 -0
  75. data/examples/phase3_demo.rb +159 -0
  76. data/examples/query_demo_simple.rb +131 -0
  77. data/expressir.gemspec +2 -0
  78. data/lib/expressir/cli.rb +12 -4
  79. data/lib/expressir/commands/manifest.rb +427 -0
  80. data/lib/expressir/commands/package.rb +1274 -0
  81. data/lib/expressir/commands/validate.rb +70 -37
  82. data/lib/expressir/commands/validate_ascii.rb +607 -0
  83. data/lib/expressir/commands/validate_load.rb +88 -0
  84. data/lib/expressir/express/formatter.rb +5 -1
  85. data/lib/expressir/express/formatters/remark_item_formatter.rb +25 -0
  86. data/lib/expressir/express/parser.rb +33 -0
  87. data/lib/expressir/manifest/resolver.rb +213 -0
  88. data/lib/expressir/manifest/validator.rb +195 -0
  89. data/lib/expressir/model/declarations/entity.rb +6 -0
  90. data/lib/expressir/model/dependency_resolver.rb +270 -0
  91. data/lib/expressir/model/indexes/entity_index.rb +103 -0
  92. data/lib/expressir/model/indexes/reference_index.rb +148 -0
  93. data/lib/expressir/model/indexes/type_index.rb +149 -0
  94. data/lib/expressir/model/interface_validator.rb +384 -0
  95. data/lib/expressir/model/repository.rb +400 -5
  96. data/lib/expressir/model/repository_validator.rb +295 -0
  97. data/lib/expressir/model/search_engine.rb +525 -0
  98. data/lib/expressir/model.rb +4 -94
  99. data/lib/expressir/package/builder.rb +200 -0
  100. data/lib/expressir/package/metadata.rb +81 -0
  101. data/lib/expressir/package/reader.rb +165 -0
  102. data/lib/expressir/schema_manifest.rb +11 -1
  103. data/lib/expressir/version.rb +1 -1
  104. data/lib/expressir.rb +15 -2
  105. metadata +114 -4
  106. data/docs/benchmarking.adoc +0 -107
  107. data/docs/liquid_drops.adoc +0 -1547
@@ -0,0 +1,898 @@
1
+ ---
2
+ title: Importing from Express Engine
3
+ parent: Changes
4
+ grand_parent: Overview
5
+ nav_order: 3
6
+ ---
7
+
8
+ = Importing from Express Engine
9
+
10
+ == Purpose
11
+
12
+ Express Engine (eengine) is a commercial tool that can compare EXPRESS schema
13
+ versions and generate detailed XML comparison reports. Expressir can import
14
+ these reports to create or update EXPRESS Changes files automatically.
15
+
16
+ == References
17
+
18
+ * link:index.html[Changes Overview] - Introduction to Changes files
19
+ * link:changes-format.html[Changes Format] - YAML format specification
20
+ * link:validating-changes.html[Validating Changes] - Validation guide
21
+ * link:programmatic-usage.html[Programmatic Usage] - Ruby API for import
22
+
23
+ == Concepts
24
+
25
+ Express Engine:: Commercial EXPRESS schema comparison tool that generates XML
26
+ reports showing differences between schema versions
27
+
28
+ comparison report:: XML document describing additions, modifications, and
29
+ deletions between two schema versions
30
+
31
+ automatic mode detection:: Expressir automatically detects whether XML uses
32
+ Schema, ARM, or MIM mode
33
+
34
+ incremental import:: Adding new versions to existing Changes files without
35
+ replacing previous versions
36
+
37
+ interfaced_items:: Field tracking which items are imported via `USE_FROM` or
38
+ `REFERENCE_FROM` statements
39
+
40
+ == Express Engine XML format
41
+
42
+ === What is Express Engine?
43
+
44
+ Express Engine (eengine) is a commercial tool developed for working with
45
+ EXPRESS schemas. One of its key features is comparing two versions of a schema
46
+ and generating a detailed XML report of the differences.
47
+
48
+ Expressir is compatible with **Express Engine v5.2.7** XML output format.
49
+
50
+ === Three XML modes
51
+
52
+ Express Engine generates comparison reports in three different modes, each with
53
+ a distinct XML structure:
54
+
55
+ Schema mode:: Standard schema comparison
56
+ +
57
+ [source,xml]
58
+ ----
59
+ <schema.changes schema_name="action_schema">
60
+ <schema.modifications>
61
+ <modified.object type="ENTITY" name="action"/>
62
+ </schema.modifications>
63
+ <schema.additions>
64
+ <modified.object type="FUNCTION" name="new_function"/>
65
+ </schema.additions>
66
+ <schema.deletions>
67
+ <modified.object type="CONSTANT" name="old_constant"/>
68
+ </schema.deletions>
69
+ </schema.changes>
70
+ ----
71
+
72
+ ARM mode:: Application Reference Model comparison
73
+ +
74
+ [source,xml]
75
+ ----
76
+ <arm.changes schema_name="action_arm">
77
+ <arm.modifications>
78
+ <modified.object type="ENTITY" name="arm_entity"/>
79
+ </arm.modifications>
80
+ <arm.additions>
81
+ <modified.object type="TYPE" name="new_arm_type"/>
82
+ </arm.additions>
83
+ <arm.deletions>
84
+ <modified.object type="FUNCTION" name="old_arm_function"/>
85
+ </arm.deletions>
86
+ </arm.changes>
87
+ ----
88
+
89
+ MIM mode:: Module Implementation Model comparison
90
+ +
91
+ [source,xml]
92
+ ----
93
+ <mim.changes schema_name="action_mim">
94
+ <mim.modifications>
95
+ <modified.object type="ENTITY" name="mim_entity"/>
96
+ </mim.modifications>
97
+ <mim.additions>
98
+ <modified.object type="TYPE" name="new_mim_type"/>
99
+ </mim.additions>
100
+ <mim.deletions>
101
+ <modified.object type="FUNCTION" name="old_mim_function"/>
102
+ </mim.deletions>
103
+ </mim.changes>
104
+ ----
105
+
106
+ === Automatic mode detection
107
+
108
+ Expressir automatically detects which mode is used by examining the XML root
109
+ element:
110
+
111
+ * `<schema.changes>` → Schema mode
112
+ * `<arm.changes>` → ARM mode
113
+ * `<mim.changes>` → MIM mode
114
+
115
+ You don't need to specify the mode manually.
116
+
117
+ === XML structure elements
118
+
119
+ Each XML comparison report contains:
120
+
121
+ modified.object:: Individual change item with attributes:
122
+ * `type` - EXPRESS construct type (ENTITY, FUNCTION, etc.)
123
+ * `name` - Name of the changed item
124
+ * `interfaced.items` - For USE_FROM/REFERENCE_FROM (optional)
125
+
126
+ description:: Optional nested element with HTML-formatted change description
127
+
128
+ .XML with descriptions
129
+ [example]
130
+ ====
131
+ [source,xml]
132
+ ----
133
+ <schema.changes schema_name="action_schema">
134
+ <schema.modifications>
135
+ <modified.object type="ENTITY" name="action">
136
+ <description>
137
+ <ul>
138
+ <li>Added new attribute 'status'</li>
139
+ <li>Modified WHERE rules</li>
140
+ </ul>
141
+ </description>
142
+ </modified.object>
143
+ </schema.modifications>
144
+ </schema.changes>
145
+ ----
146
+
147
+ This converts to:
148
+
149
+ [source,yaml]
150
+ ----
151
+ modifications:
152
+ - type: ENTITY
153
+ name: action
154
+ description:
155
+ - Added new attribute 'status'
156
+ - Modified WHERE rules
157
+ ----
158
+ ====
159
+
160
+ == CLI import
161
+
162
+ === Basic import syntax
163
+
164
+ [source,bash]
165
+ ----
166
+ expressir changes import-eengine INPUT_XML SCHEMA_NAME VERSION [options]
167
+ ----
168
+
169
+ Where:
170
+
171
+ `INPUT_XML`:: Path to Express Engine comparison XML file
172
+ `SCHEMA_NAME`:: Name of the schema being tracked
173
+ `VERSION`:: Version number for these changes
174
+
175
+ === Import to stdout
176
+
177
+ Import and display YAML on stdout:
178
+
179
+ [source,bash]
180
+ ----
181
+ expressir changes import-eengine comparison.xml action_schema "2"
182
+ ----
183
+
184
+ .Output example
185
+ [example]
186
+ ====
187
+ [source,yaml]
188
+ ----
189
+ schema: action_schema
190
+ versions:
191
+ - version: 2
192
+ additions:
193
+ - type: ENTITY
194
+ name: new_entity
195
+ modifications:
196
+ - type: FUNCTION
197
+ name: updated_function
198
+ ----
199
+ ====
200
+
201
+ === Import to file
202
+
203
+ Save imported changes to a YAML file:
204
+
205
+ [source,bash]
206
+ ----
207
+ expressir changes import-eengine comparison.xml action_schema "2" \
208
+ -o action_schema.changes.yaml
209
+ ----
210
+
211
+ Or using long format:
212
+
213
+ [source,bash]
214
+ ----
215
+ expressir changes import-eengine comparison.xml action_schema "2" \
216
+ --output action_schema.changes.yaml
217
+ ----
218
+
219
+ === Verbose output
220
+
221
+ Show detailed information during import:
222
+
223
+ [source,bash]
224
+ ----
225
+ expressir changes import-eengine comparison.xml action_schema "2" \
226
+ -o output.yaml --verbose
227
+ ----
228
+
229
+ .Verbose output example
230
+ [example]
231
+ ====
232
+ [source,bash]
233
+ ----
234
+ $ expressir changes import-eengine comparison.xml action_schema "2" \
235
+ -o output.yaml --verbose
236
+ Detected mode: schema
237
+ Found 5 additions
238
+ Found 3 modifications
239
+ Found 1 deletion
240
+ Change YAML file written to: output.yaml
241
+ ----
242
+ ====
243
+
244
+ === Import options
245
+
246
+ [options="header"]
247
+ |===
248
+ | Option | Short | Description | Example
249
+
250
+ | `--output PATH`
251
+ | `-o PATH`
252
+ | Output YAML file path
253
+ | `-o output.yaml`
254
+
255
+ | `--verbose`
256
+ | N/A
257
+ | Show detailed output
258
+ | `--verbose`
259
+ |===
260
+
261
+ == Building change history
262
+
263
+ === Incremental version building
264
+
265
+ When the output file already exists, the import command intelligently merges
266
+ the new version with existing versions:
267
+
268
+ Same version:: Replaces the existing version with that version number
269
+ +
270
+ [source,bash]
271
+ ----
272
+ # First import (creates file)
273
+ expressir changes import-eengine v2.xml schema "2" -o changes.yaml
274
+
275
+ # Reimport same version (replaces version 2)
276
+ expressir changes import-eengine v2_updated.xml schema "2" -o changes.yaml
277
+ ----
278
+
279
+ New version:: Adds the new version to the file
280
+ +
281
+ [source,bash]
282
+ ----
283
+ # First import (creates file with version 2)
284
+ expressir changes import-eengine v2.xml schema "2" -o changes.yaml
285
+
286
+ # Import version 3 (appends to existing file)
287
+ expressir changes import-eengine v3.xml schema "3" -o changes.yaml
288
+ ----
289
+
290
+ === Multi-version import workflow
291
+
292
+ Build a complete change history incrementally:
293
+
294
+ .Importing multiple versions
295
+ [example]
296
+ ====
297
+ [source,bash]
298
+ ----
299
+ # Import version 2
300
+ expressir changes import-eengine v2_comparison.xml action_schema "2" \
301
+ -o action_schema.changes.yaml
302
+
303
+ # Import version 3 (appends)
304
+ expressir changes import-eengine v3_comparison.xml action_schema "3" \
305
+ -o action_schema.changes.yaml
306
+
307
+ # Import version 4 (appends)
308
+ expressir changes import-eengine v4_comparison.xml action_schema "4" \
309
+ -o action_schema.changes.yaml
310
+
311
+ # Verify complete history
312
+ cat action_schema.changes.yaml
313
+ ----
314
+
315
+ Results in:
316
+
317
+ [source,yaml]
318
+ ----
319
+ schema: action_schema
320
+ versions:
321
+ - version: 2
322
+ additions: [...]
323
+ modifications: [...]
324
+ - version: 3
325
+ additions: [...]
326
+ modifications: [...]
327
+ - version: 4
328
+ additions: [...]
329
+ modifications: [...]
330
+ ----
331
+ ====
332
+
333
+ === Overwriting existing versions
334
+
335
+ If you reimport the same version, it replaces the existing one:
336
+
337
+ [source,bash]
338
+ ----
339
+ # Initial import
340
+ expressir changes import-eengine v2.xml schema "2" -o changes.yaml
341
+
342
+ # Update version 2 (replaces existing version 2)
343
+ expressir changes import-eengine v2_revised.xml schema "2" -o changes.yaml
344
+ ----
345
+
346
+ This is useful when:
347
+
348
+ * Express Engine comparison was incorrect
349
+ * Need to update descriptions
350
+ * XML format changed
351
+
352
+ == Interface changes
353
+
354
+ === Understanding interfaced_items
355
+
356
+ The `interfaced.items` attribute in Express Engine XML specifies which items
357
+ are being imported or referenced from another schema via `USE_FROM` or
358
+ `REFERENCE_FROM` statements.
359
+
360
+ .XML with interface changes
361
+ [example]
362
+ ====
363
+ [source,xml]
364
+ ----
365
+ <schema.changes schema_name="aic_csg">
366
+ <schema.additions>
367
+ <modified.object type="USE_FROM" name="geometric_model_schema"
368
+ interfaced.items="convex_hexahedron" />
369
+
370
+ <modified.object type="USE_FROM" name="geometric_model_schema"
371
+ interfaced.items="cyclide_segment_solid" />
372
+
373
+ <modified.object type="REFERENCE_FROM" name="measure_schema"
374
+ interfaced.items="length_measure" />
375
+ </schema.additions>
376
+ </schema.changes>
377
+ ----
378
+
379
+ Converts to:
380
+
381
+ [source,yaml]
382
+ ----
383
+ schema: aic_csg
384
+ versions:
385
+ - version: 2
386
+ additions:
387
+ - type: USE_FROM
388
+ name: geometric_model_schema
389
+ interfaced_items: convex_hexahedron
390
+ - type: USE_FROM
391
+ name: geometric_model_schema
392
+ interfaced_items: cyclide_segment_solid
393
+ - type: REFERENCE_FROM
394
+ name: measure_schema
395
+ interfaced_items: length_measure
396
+ ----
397
+ ====
398
+
399
+ === Separate entries per item
400
+
401
+ Express Engine creates separate `<modified.object>` entries for each imported
402
+ item, even from the same schema. Expressir preserves this structure:
403
+
404
+ [source,xml]
405
+ ----
406
+ <!-- Separate entries for each item -->
407
+ <modified.object type="USE_FROM" name="schema_a"
408
+ interfaced.items="item1" />
409
+ <modified.object type="USE_FROM" name="schema_a"
410
+ interfaced.items="item2" />
411
+ ----
412
+
413
+ This ensures clarity about which specific items changed.
414
+
415
+ == Description handling
416
+
417
+ === HTML to array conversion
418
+
419
+ Express Engine descriptions can contain HTML formatting. Expressir automatically
420
+ converts HTML lists to YAML arrays:
421
+
422
+ .HTML list in XML
423
+ [example]
424
+ ====
425
+ [source,xml]
426
+ ----
427
+ <modified.object type="ENTITY" name="action">
428
+ <description>
429
+ <ul>
430
+ <li>Added new attribute 'priority'</li>
431
+ <li>Modified WHERE rule WR1</li>
432
+ <li>Updated documentation</li>
433
+ </ul>
434
+ </description>
435
+ </modified.object>
436
+ ----
437
+
438
+ Converts to:
439
+
440
+ [source,yaml]
441
+ ----
442
+ - type: ENTITY
443
+ name: action
444
+ description:
445
+ - Added new attribute 'priority'
446
+ - Modified WHERE rule WR1
447
+ - Updated documentation
448
+ ----
449
+ ====
450
+
451
+ === Plain text descriptions
452
+
453
+ Non-list descriptions are preserved as single-item arrays:
454
+
455
+ [source,xml]
456
+ ----
457
+ <modified.object type="FUNCTION" name="validate">
458
+ <description>Updated validation logic</description>
459
+ </modified.object>
460
+ ----
461
+
462
+ Converts to:
463
+
464
+ [source,yaml]
465
+ ----
466
+ - type: FUNCTION
467
+ name: validate
468
+ description:
469
+ - Updated validation logic
470
+ ----
471
+
472
+ === Missing descriptions
473
+
474
+ Items without descriptions in the XML will not have a `description` field in
475
+ the YAML:
476
+
477
+ [source,xml]
478
+ ----
479
+ <modified.object type="TYPE" name="status_type" />
480
+ ----
481
+
482
+ Converts to:
483
+
484
+ [source,yaml]
485
+ ----
486
+ - type: TYPE
487
+ name: status_type
488
+ ----
489
+
490
+ == API import
491
+
492
+ === From XML string
493
+
494
+ Import Express Engine XML directly from a string:
495
+
496
+ [source,ruby]
497
+ ----
498
+ require "expressir/commands/changes_import_eengine"
499
+
500
+ xml_content = File.read("comparison.xml")
501
+
502
+ # Parse and convert to SchemaChange
503
+ changes = Expressir::Commands::ChangesImportEengine.from_xml(
504
+ xml_content,
505
+ "action_schema", # Schema name
506
+ "2" # Version
507
+ )
508
+
509
+ # Access imported data
510
+ puts "Schema: #{changes.schema}"
511
+ changes.versions.first.additions.each do |item|
512
+ puts "Added #{item.type}: #{item.name}"
513
+ end
514
+
515
+ # Save to file
516
+ changes.to_file("output.changes.yaml")
517
+ ----
518
+
519
+ === From XML file
520
+
521
+ Import directly from a file (backward compatible method):
522
+
523
+ [source,ruby]
524
+ ----
525
+ require "expressir/commands/changes_import_eengine"
526
+
527
+ # Import and save
528
+ Expressir::Commands::ChangesImportEengine.call(
529
+ "comparison.xml", # Input XML file
530
+ "output.changes.yaml", # Output YAML file
531
+ "action_schema", # Schema name
532
+ "2", # Version
533
+ verbose: true # Show progress
534
+ )
535
+ ----
536
+
537
+ === Appending to existing file
538
+
539
+ Add a new version to an existing Changes file:
540
+
541
+ [source,ruby]
542
+ ----
543
+ require "expressir/changes"
544
+ require "expressir/commands/changes_import_eengine"
545
+
546
+ # Load existing changes
547
+ existing = if File.exist?("schema.changes.yaml")
548
+ Expressir::Changes::SchemaChange.from_file("schema.changes.yaml")
549
+ end
550
+
551
+ # Import new version
552
+ xml_content = File.read("v3_comparison.xml")
553
+ updated = Expressir::Commands::ChangesImportEengine.from_xml(
554
+ xml_content,
555
+ "action_schema",
556
+ "3",
557
+ existing_schema: existing # Pass existing to append
558
+ )
559
+
560
+ # Save combined result
561
+ updated.to_file("schema.changes.yaml")
562
+ ----
563
+
564
+ === Processing multiple versions
565
+
566
+ Automate importing multiple versions:
567
+
568
+ [source,ruby]
569
+ ----
570
+ require "expressir/commands/changes_import_eengine"
571
+
572
+ schema_name = "action_schema"
573
+ output_file = "#{schema_name}.changes.yaml"
574
+
575
+ # Import versions 2-5
576
+ (2..5).each do |version|
577
+ xml_file = "v#{version}_comparison.xml"
578
+
579
+ if File.exist?(xml_file)
580
+ puts "Importing version #{version}..."
581
+
582
+ Expressir::Commands::ChangesImportEengine.call(
583
+ xml_file,
584
+ output_file,
585
+ schema_name,
586
+ version.to_s,
587
+ verbose: true
588
+ )
589
+ else
590
+ puts "Warning: #{xml_file} not found, skipping"
591
+ end
592
+ end
593
+
594
+ puts "Import complete: #{output_file}"
595
+ ----
596
+
597
+ == Troubleshooting
598
+
599
+ === Invalid XML errors
600
+
601
+ **Error**: `Invalid XML format`
602
+
603
+ **Causes**:
604
+ * Malformed XML syntax
605
+ * Incorrect encoding
606
+ * Truncated file
607
+
608
+ **Solutions**:
609
+
610
+ [source,bash]
611
+ ----
612
+ # Validate XML syntax
613
+ xmllint comparison.xml
614
+
615
+ # Check encoding
616
+ file comparison.xml
617
+
618
+ # Verify file is complete
619
+ tail comparison.xml # Should see closing tags
620
+ ----
621
+
622
+ === Mode detection issues
623
+
624
+ **Error**: `Unable to detect XML mode`
625
+
626
+ **Cause**: XML doesn't match any expected root element
627
+
628
+ **Solution**: Ensure XML starts with one of:
629
+ * `<schema.changes>`
630
+ * `<arm.changes>`
631
+ * `<mim.changes>`
632
+
633
+ [source,bash]
634
+ ----
635
+ # Check root element
636
+ head -n 5 comparison.xml
637
+ ----
638
+
639
+ === Missing interfaced_items
640
+
641
+ **Issue**: `USE_FROM` or `REFERENCE_FROM` items missing `interfaced_items`
642
+
643
+ **Cause**: Express Engine XML missing `interfaced.items` attribute
644
+
645
+ **Impact**: Import succeeds but `interfaced_items` field will be empty
646
+
647
+ **Solution**: Manually add `interfaced_items` to YAML after import:
648
+
649
+ [source,yaml]
650
+ ----
651
+ # After import, manually add:
652
+ - type: USE_FROM
653
+ name: geometry_schema
654
+ interfaced_items: point # Add this manually
655
+ ----
656
+
657
+ === File permission errors
658
+
659
+ **Error**: `Permission denied`
660
+
661
+ **Cause**: No write permission for output file or directory
662
+
663
+ **Solutions**:
664
+
665
+ [source,bash]
666
+ ----
667
+ # Check permissions
668
+ ls -la output_directory/
669
+
670
+ # Fix permissions
671
+ chmod +w output_directory/
672
+
673
+ # Or save to different location
674
+ expressir changes import-eengine comparison.xml schema "2" \
675
+ -o ~/tmp/output.yaml
676
+ ----
677
+
678
+ === Version conflicts
679
+
680
+ **Issue**: Existing version has different content
681
+
682
+ **Behavior**: Import replaces existing version with same number
683
+
684
+ **Solution**: If you need to preserve both:
685
+
686
+ [source,bash]
687
+ ----
688
+ # Save current version
689
+ cp schema.changes.yaml schema.changes.yaml.v2.backup
690
+
691
+ # Import new version 2 (replaces)
692
+ expressir changes import-eengine new_v2.xml schema "2" \
693
+ -o schema.changes.yaml
694
+
695
+ # Compare differences
696
+ diff schema.changes.yaml.v2.backup schema.changes.yaml
697
+ ----
698
+
699
+ == Complete workflow examples
700
+
701
+ === Simple import workflow
702
+
703
+ [source,bash]
704
+ ----
705
+ # 1. Get Express Engine comparison XML
706
+ # (Generated by Express Engine comparing v1 to v2)
707
+
708
+ # 2. Import to YAML
709
+ expressir changes import-eengine v2_comparison.xml action_schema "2" \
710
+ -o action_schema.changes.yaml
711
+
712
+ # 3. Validate
713
+ expressir changes validate action_schema.changes.yaml --verbose
714
+
715
+ # 4. Review
716
+ cat action_schema.changes.yaml
717
+
718
+ # 5. Commit
719
+ git add action_schema.changes.yaml
720
+ git commit -m "Import version 2 changes from Express Engine"
721
+ ----
722
+
723
+ === Multi-version workflow
724
+
725
+ [source,bash]
726
+ ----
727
+ # Import versions 2-4 incrementally
728
+ for version in 2 3 4; do
729
+ echo "Importing version $version..."
730
+ expressir changes import-eengine \
731
+ "v${version}_comparison.xml" \
732
+ action_schema \
733
+ "$version" \
734
+ -o action_schema.changes.yaml \
735
+ --verbose
736
+ done
737
+
738
+ # Validate final result
739
+ expressir changes validate action_schema.changes.yaml --verbose
740
+
741
+ # Review complete history
742
+ cat action_schema.changes.yaml
743
+ ----
744
+
745
+ === Automated CI workflow
746
+
747
+ [source,bash]
748
+ ----
749
+ #!/bin/bash
750
+ # import-changes.sh - Automated import script
751
+
752
+ SCHEMA_NAME="action_schema"
753
+ XML_DIR="eengine_reports"
754
+ OUTPUT_FILE="${SCHEMA_NAME}.changes.yaml"
755
+
756
+ # Find all comparison XMLs
757
+ for xml in ${XML_DIR}/v*_comparison.xml; do
758
+ # Extract version from filename (e.g., v2_comparison.xml -> 2)
759
+ version=$(basename "$xml" | sed 's/v\([0-9]*\)_comparison.xml/\1/')
760
+
761
+ echo "Importing version $version from $xml..."
762
+ expressir changes import-eengine \
763
+ "$xml" \
764
+ "$SCHEMA_NAME" \
765
+ "$version" \
766
+ -o "$OUTPUT_FILE" \
767
+ --verbose || exit 1
768
+ done
769
+
770
+ # Validate result
771
+ echo "Validating result..."
772
+ expressir changes validate "$OUTPUT_FILE" --verbose || exit 1
773
+
774
+ # Normalize for consistency
775
+ echo "Normalizing..."
776
+ expressir changes validate "$OUTPUT_FILE" --normalize --in-place
777
+
778
+ echo "Import complete: $OUTPUT_FILE"
779
+ ----
780
+
781
+ == Best practices
782
+
783
+ === Keep Express Engine XMLs
784
+
785
+ Archive Express Engine comparison XMLs for reference:
786
+
787
+ [source]
788
+ ----
789
+ project/
790
+ ├── schemas/
791
+ │ └── action_schema.exp
792
+ ├── changes/
793
+ │ └── action_schema.changes.yaml
794
+ └── eengine_reports/
795
+ ├── v2_comparison.xml
796
+ ├── v3_comparison.xml
797
+ └── v4_comparison.xml
798
+ ----
799
+
800
+ === Import in order
801
+
802
+ Import versions chronologically:
803
+
804
+ [source,bash]
805
+ ----
806
+ # Good: chronological order
807
+ expressir changes import-eengine v2.xml schema "2" -o changes.yaml
808
+ expressir changes import-eengine v3.xml schema "3" -o changes.yaml
809
+ expressir changes import-eengine v4.xml schema "4" -o changes.yaml
810
+
811
+ # Avoid: out of order (though technically works)
812
+ expressir changes import-eengine v4.xml schema "4" -o changes.yaml
813
+ expressir changes import-eengine v2.xml schema "2" -o changes.yaml
814
+ ----
815
+
816
+ === Validate after import
817
+
818
+ Always validate imported files:
819
+
820
+ [source,bash]
821
+ ----
822
+ expressir changes import-eengine comparison.xml schema "2" -o changes.yaml
823
+ expressir changes validate changes.yaml --verbose
824
+ ----
825
+
826
+ === Review before committing
827
+
828
+ Review imported changes before committing:
829
+
830
+ [source,bash]
831
+ ----
832
+ # Import
833
+ expressir changes import-eengine comparison.xml schema "2" -o changes.yaml
834
+
835
+ # Review
836
+ cat changes.yaml
837
+
838
+ # Verify specific changes
839
+ grep -A 5 "additions:" changes.yaml
840
+
841
+ # Commit if satisfied
842
+ git add changes.yaml
843
+ git commit -m "Import version 2 from Express Engine"
844
+ ----
845
+
846
+ === Enhance descriptions
847
+
848
+ Express Engine descriptions may be minimal. Consider enhancing them:
849
+
850
+ [source,yaml]
851
+ ----
852
+ # After import - minimal Express Engine description
853
+ - type: ENTITY
854
+ name: action
855
+ description:
856
+ - Modified
857
+
858
+ # Enhance with details
859
+ - type: ENTITY
860
+ name: action
861
+ description:
862
+ - Added new attribute 'priority'
863
+ - Modified WHERE rule WR1 to allow null status
864
+ - Updated subtype relationship to action_base
865
+ ----
866
+
867
+ == Next steps
868
+
869
+ After importing from Express Engine:
870
+
871
+ * link:validating-changes.html[Validate Changes] - Validate imported files
872
+ * link:changes-format.html[Changes Format] - Understand the YAML structure
873
+ * link:programmatic-usage.html[Programmatic Usage] - Work with changes via API
874
+
875
+ == Summary
876
+
877
+ Importing from Express Engine automates change tracking:
878
+
879
+ * Three XML modes automatically detected (Schema, ARM, MIM)
880
+ * Simple CLI command for import
881
+ * Incremental version building support
882
+ * Automatic interface change handling via `interfaced_items`
883
+ * HTML description conversion to YAML arrays
884
+ * Both CLI and API import methods
885
+ * Smart versioning (replace same, append new)
886
+ * Compatible with Express Engine v5.2.7 format
887
+
888
+ Key takeaways:
889
+
890
+ * Express Engine comparison XMLs convert to Changes YAML
891
+ * Mode detection is automatic
892
+ * Build change history incrementally across versions
893
+ * Interface changes preserve `interfaced_items` information
894
+ * Always validate after import
895
+ * Keep Express Engine XMLs for reference
896
+ * Import in chronological order
897
+ * Review and enhance descriptions as needed
898
+ * Automate import in CI/CD workflows