xseed 1.0.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 (41) hide show
  1. checksums.yaml +7 -0
  2. data/.github/workflows/rake.yml +16 -0
  3. data/.github/workflows/release.yml +25 -0
  4. data/.gitignore +72 -0
  5. data/.rspec +3 -0
  6. data/.rubocop.yml +11 -0
  7. data/.rubocop_todo.yml +432 -0
  8. data/CHANGELOG.adoc +446 -0
  9. data/Gemfile +21 -0
  10. data/LICENSE.adoc +29 -0
  11. data/README.adoc +386 -0
  12. data/Rakefile +11 -0
  13. data/examples/README.adoc +334 -0
  14. data/examples/advanced_usage.rb +286 -0
  15. data/examples/html_generation.rb +167 -0
  16. data/examples/parser_usage.rb +102 -0
  17. data/examples/schemas/person.xsd +171 -0
  18. data/examples/simple_generation.rb +149 -0
  19. data/exe/xseed +6 -0
  20. data/lib/xseed/cli.rb +376 -0
  21. data/lib/xseed/documentation/config.rb +101 -0
  22. data/lib/xseed/documentation/constants.rb +76 -0
  23. data/lib/xseed/documentation/generators/hierarchy_table_generator.rb +554 -0
  24. data/lib/xseed/documentation/generators/instance_sample_generator.rb +723 -0
  25. data/lib/xseed/documentation/generators/properties_table_generator.rb +983 -0
  26. data/lib/xseed/documentation/html_generator.rb +836 -0
  27. data/lib/xseed/documentation/html_generator.rb.bak +723 -0
  28. data/lib/xseed/documentation/presentation/css_generator.rb +510 -0
  29. data/lib/xseed/documentation/presentation/javascript_generator.rb +151 -0
  30. data/lib/xseed/documentation/presentation/navigation_builder.rb +169 -0
  31. data/lib/xseed/documentation/schema_loader.rb +121 -0
  32. data/lib/xseed/documentation/utils/helpers.rb +205 -0
  33. data/lib/xseed/documentation/utils/namespaces.rb +149 -0
  34. data/lib/xseed/documentation/utils/references.rb +135 -0
  35. data/lib/xseed/documentation/utils/strings.rb +75 -0
  36. data/lib/xseed/models/element_declaration.rb +144 -0
  37. data/lib/xseed/parser/xsd_parser.rb +192 -0
  38. data/lib/xseed/version.rb +5 -0
  39. data/lib/xseed.rb +76 -0
  40. data/xseed.gemspec +39 -0
  41. metadata +158 -0
data/README.adoc ADDED
@@ -0,0 +1,386 @@
1
+ = Xseed: Ruby XSD Documentation Generator
2
+
3
+ image:https://img.shields.io/gem/v/xseed.svg[RubyGems Version, link=https://rubygems.org/gems/xseed]
4
+ image:https://img.shields.io/github/license/metanorma/xseed.svg[License, link=https://github.com/metanorma/xseed/blob/main/LICENSE.adoc]
5
+ image:https://github.com/metanorma/xseed/actions/workflows/test.yml/badge.svg["Build", link="https://github.com/metanorma/xseed/actions/workflows/test.yml"]
6
+ image:https://img.shields.io/badge/parity-100%25-brightgreen[Parity]
7
+ image:https://img.shields.io/badge/coverage-87.63%25-brightgreen[Coverage]
8
+
9
+ == Purpose
10
+
11
+ Xseed provides comprehensive XSD documentation generation with a single command:
12
+
13
+ * **Automatic SVG generation** - When generating HTML, xseed automatically creates SVG diagrams for all elements using the xsdvi gem
14
+ * **HTML documentation** - Complete schema reference with embedded SVG diagrams (XS3P port)
15
+ * **Single-command workflow** - One command generates everything: HTML + all SVG diagrams
16
+
17
+ == Features
18
+
19
+ * **Single-command generation** - `xseed html` automatically generates HTML documentation and all SVG diagrams
20
+ * **Integrated SVG diagrams** - Uses xsdvi gem Ruby API to generate diagram for each element
21
+ * **Comprehensive HTML** - Schema properties, component listings, type hierarchies, XML samples
22
+ * <<cli-interface,Professional CLI>> - Thor-based with verbose mode and progress indicators
23
+ * <<performance,High performance>> - Generates complete documentation in milliseconds
24
+ * <<error-handling,Robust error handling>> - Graceful degradation with helpful messages
25
+ * **21 complete features** - All P0, P1, and P2 features implemented
26
+
27
+ == Quick Start
28
+
29
+ [source,shell]
30
+ ----
31
+ # Install the gem (includes xsdvi for SVG generation)
32
+ gem install xseed
33
+
34
+ # Generate complete documentation (HTML + all SVG diagrams)
35
+ xseed html schema.xsd -o docs/index.html
36
+
37
+ # Result:
38
+ # docs/index.html (HTML with embedded SVG references)
39
+ # docs/diagrams/*.svg (SVG diagram for each element)
40
+
41
+ # View schema information
42
+ xseed info schema.xsd
43
+
44
+ # Display help
45
+ xseed help
46
+ ----
47
+
48
+ == Complete Workflow
49
+
50
+ === Single-command integrated documentation
51
+
52
+ **One command does everything** - xseed automatically generates all SVG diagrams when creating HTML:
53
+
54
+ [source,shell]
55
+ ----
56
+ # This single command generates EVERYTHING:
57
+ xseed html schema.xsd -o docs/index.html
58
+ ----
59
+
60
+ **What it generates:**
61
+
62
+ * `docs/index.html` - Complete HTML documentation
63
+ * `docs/diagrams/*.svg` - SVG diagram for EVERY element (auto-generated using xsdvi)
64
+ * Proper `<object>` tag integration in HTML
65
+
66
+ **That's it!** No need for separate SVG generation commands.
67
+
68
+ .Real-world example with UnitsML (54 elements)
69
+ ====
70
+ [source,shell]
71
+ ----
72
+ $ xseed html unitsml-v1.0.xsd -o output/index.html --title "UnitsML Docs" --verbose
73
+
74
+ → Creating HTML generator for: unitsml-v1.0.xsd
75
+ → HTML generator initialized
76
+ → Generating HTML documentation...
77
+ ✓ Complete
78
+ ✓ HTML documentation generated: output/index.html
79
+ → Generation completed in 0.341s
80
+
81
+ # Generated files:
82
+ # output/index.html (752KB HTML)
83
+ # output/diagrams/Unit.svg (54 SVG files, one per element)
84
+ # output/diagrams/Quantity.svg
85
+ # output/diagrams/Prefix.svg
86
+ # ... (and 51 more)
87
+
88
+ $ open output/index.html
89
+ ----
90
+
91
+ The HTML automatically includes all 54 SVG diagrams with proper `<object>` tags.
92
+ ====
93
+ </commands>
94
+ * `-o, --output PATH` - Output HTML file path (required)
95
+ * `-t, --title TEXT` - Custom documentation title
96
+ * `-d, --diagrams-dir DIR` - Custom SVG directory name (default: "diagrams")
97
+ * `--css PATH` - External CSS file URL
98
+ * `-v, --verbose` - Show detailed progress
99
+ * `-f, --force` - Overwrite without confirmation
100
+
101
+ import@<interface>
102
+ QPushButton{
103
+ {name}:
104
+ {instruction
105
+ }
106
+ import@<interface>
107
+ QPushButton{
108
+ {name}:
109
+ {instruction
110
+ }
111
+ import@<interface>
112
+ QPushButton{
113
+ {name}:
114
+ {instruction
115
+ }
116
+ import@<interface>
117
+ QPushButton{
118
+ {name}:
119
+ {instruction
120
+ }
121
+ import@<interface>
122
+ QPushButton{
123
+ {name}:
124
+ {instruction
125
+ }
126
+ import@<interface>
127
+ QPushButton{
128
+ {name}:
129
+ {instruction
130
+ }
131
+ import@<interface>
132
+ QPushButton{
133
+ {name}:
134
+ {instruction
135
+ }
136
+ import@<interface>
137
+ QPushButton{
138
+ {name}:
139
+ {instruction
140
+ }
141
+ import@<interface>
142
+ QPushButton{
143
+ {name}:
144
+ {instruction
145
+ }
146
+ import@<interface>
147
+ QPushButton{
148
+ {name}:
149
+ {instruction
150
+ }
151
+ import@<interface>
152
+ QPushButton{
153
+ {name}:
154
+ {instruction
155
+ }
156
+ import@<interface>
157
+ QPushButton{
158
+ {name}:
159
+ {instruction
160
+ }
161
+ import@<interface>
162
+ QPushButton{
163
+ {name}:
164
+ {instruction
165
+ }
166
+ import@<interface>
167
+ QPushButton{
168
+ {name}:
169
+ {instruction
170
+ }
171
+ import@<interface>
172
+ QPushButton{
173
+ {name}:
174
+ {instruction
175
+ }
176
+ import@<interface>
177
+ QPushButton{
178
+ {name}:
179
+ {instruction
180
+ }
181
+ import@<interface>
182
+ QPushButton{
183
+ {name}:
184
+ {instruction
185
+ }
186
+ import@<interface>
187
+ QPushButton{
188
+ {name}:
189
+ {instruction
190
+ }
191
+ import@<interface>
192
+ QPushButton{
193
+ {name}:
194
+ {instruction
195
+ }
196
+ import@<interface>
197
+ QPushButton{
198
+ {name}:
199
+ {instruction
200
+ }
201
+ import@<interface>
202
+ QPushButton{
203
+ {name}:
204
+ {instruction
205
+ }
206
+ import@<interface>
207
+ QPushButton{
208
+ {name}:
209
+ {instruction
210
+ }
211
+ import@<interface>
212
+ QPushButton{
213
+ {name}:
214
+ {instruction
215
+ }
216
+ import@<interface>
217
+ QPushButton{
218
+ {name}:
219
+ {instruction
220
+ }
221
+ import@<interface>
222
+ QPushButton{
223
+ {name}:
224
+ {instruction
225
+ }
226
+ import@<interface>
227
+ QPushButton{
228
+ {name}:
229
+ {instruction
230
+ }
231
+ import@<interface>
232
+ QPushButton{
233
+ {name}:
234
+ {instruction
235
+ }
236
+ import@<interface>
237
+ QPushButton{
238
+ {name}:
239
+ {instruction
240
+ }
241
+ import@<interface>
242
+ QPushButton{
243
+ {name}:
244
+ {instruction
245
+ }
246
+ import@<interface>
247
+ QPushButton{
248
+ {name}:
249
+ {instruction
250
+ }
251
+ import@<interface>
252
+ QPushButton{
253
+ {name}:
254
+ {instruction
255
+ }
256
+ import@<interface>
257
+ QPushButton{
258
+ {name}:
259
+ {instruction
260
+ }
261
+ import@<interface>
262
+ QPushButton{
263
+ {name}:
264
+ {instruction
265
+ }
266
+ import@<interface>
267
+ QPushButton{
268
+ {name}:
269
+ {instruction
270
+ }
271
+ import@<interface>
272
+ QPushButton{
273
+ {name}:
274
+ {instruction
275
+ }
276
+ import@<interface>
277
+ QPushButton{
278
+ {name}:
279
+ {instruction
280
+ }
281
+ import@<interface>
282
+ QPushButton{
283
+ {name}:
284
+ {instruction
285
+ }
286
+ import@<interface>
287
+ QPushButton{
288
+ {name}:
289
+ {instruction
290
+ }
291
+ import@<interface>
292
+ QPushButton{
293
+ {name}:
294
+ {instruction
295
+ }
296
+ import@<interface>
297
+ QPushButton{
298
+ {name}:
299
+ {instruction
300
+ }
301
+ import@<interface>
302
+ QPushButton{
303
+ {name}:
304
+ {instruction
305
+ }
306
+ import@<interface>
307
+ QPushButton{
308
+ {name}:
309
+ {instruction
310
+ }
311
+ import@<interface>
312
+ QPushButton{
313
+ {name}:
314
+ {instruction
315
+ }
316
+ import@<interface>
317
+ QPushButton{
318
+ {name}:
319
+ {instruction}
320
+ }
321
+ import@<interface>
322
+ QPushButton{
323
+ {name}:
324
+ {instruction}
325
+ }
326
+ import@<interface>
327
+ QPushButton{
328
+ {name}:
329
+ {instruction}
330
+ }
331
+ import@<interface>
332
+ QPushButton{
333
+ {name}:
334
+ {instruction}
335
+ }
336
+ import@<interface>
337
+ QPushButton{
338
+ {name}:
339
+ {instruction}
340
+ }
341
+ import@<interface>
342
+ QPushButton{
343
+ {name}:
344
+ {instruction}
345
+ }
346
+ import@<interface>
347
+ QPushButton{
348
+ {name}:
349
+ {instruction}
350
+ }
351
+ /**
352
+ * Define a QPushButton class
353
+ * @class {class_name}
354
+ * @burnsPanel {bool}
355
+ * @order {number}
356
+ * @classname {string}
357
+ * @compName {string}
358
+ * @instruction {string}
359
+ * @defaultValues {any}
360
+ * @interface {any}
361
+ */
362
+ class ${currentSymbol}(${interface}) {
363
+ :
364
+ //////////////////////////////////////
365
+ private:
366
+ signals:
367
+ /**
368
+ * Construct a QPushButton with the given panel
369
+ * @constructor
370
+ * @return {void}
371
+ * @param {QObject} parent -
372
+ * @description Constructor that will be called from Panel
373
+ */
374
+ ${currentSymbol} Sweeper(QWidget* parent) : QPushButton(parent){
375
+ this->settings.definition$is_GeneratableNewPanel = true;
376
+ this->settings.definition$is_BurnsPanel = ${classdata.burnsPanel};
377
+ this->settings.definition$order = ${classdata.order};
378
+ this->settings.definition.className = "${className}";
379
+ this->settings.definition.compName = "${classCompName}";
380
+ this->settings.definition.instructions = "${instruction}";
381
+ this->settings.definition.defaultValue = varObject${functionSeparator}${className};
382
+ this->settings.definition.defaults.push_back(varObject(${functionSeparator}"${className}"));
383
+ this->settings.definition.interface = ${interface};
384
+ //this->setParent(parent);
385
+ }
386
+ }
data/Rakefile ADDED
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/gem_tasks"
4
+ require "rspec/core/rake_task"
5
+ require "rubocop/rake_task"
6
+
7
+ RSpec::Core::RakeTask.new(:spec)
8
+
9
+ RuboCop::RakeTask.new
10
+
11
+ task default: %i[spec rubocop]
@@ -0,0 +1,334 @@
1
+ = Xseed Examples
2
+
3
+ This directory contains comprehensive examples demonstrating various features and usage patterns of the Xseed gem.
4
+
5
+ == Quick Start
6
+
7
+ [source,shell]
8
+ ----
9
+ # Run simple examples
10
+ ruby examples/simple_generation.rb
11
+
12
+ # Run advanced examples
13
+ ruby examples/advanced_usage.rb
14
+ ----
15
+
16
+ == Example Files
17
+
18
+ === Simple Generation (`simple_generation.rb`)
19
+
20
+ Demonstrates basic SVG generation workflows:
21
+
22
+ * **Example 1**: Generate SVG to stdout
23
+ * **Example 2**: Generate SVG to file
24
+ * **Example 3**: Error handling patterns
25
+ * **Example 4**: Schema inspection before generation
26
+ * **Example 5**: Batch processing multiple schemas
27
+
28
+ [source,shell]
29
+ ----
30
+ ruby examples/simple_generation.rb
31
+ ----
32
+
33
+ === Advanced Usage (`advanced_usage.rb`)
34
+
35
+ Demonstrates advanced features and patterns:
36
+
37
+ * **Example 1**: Parser introspection and metadata extraction
38
+ * **Example 2**: Conditional generation based on schema analysis
39
+ * **Example 3**: Custom error handling and logging
40
+ * **Example 4**: Performance monitoring and profiling
41
+ * **Example 5**: Integration with other tools
42
+
43
+ [source,shell]
44
+ ----
45
+ ruby examples/advanced_usage.rb
46
+ ----
47
+
48
+ == Example Schemas
49
+
50
+ === person.xsd
51
+
52
+ A comprehensive example schema demonstrating:
53
+
54
+ * **Simple types** with restrictions and enumerations
55
+ * **Complex types** with sequences and choices
56
+ * **Nested structures** (Address within Person)
57
+ * **Attributes** (required and optional)
58
+ * **Documentation** annotations throughout
59
+ * **Namespaces** and target namespace usage
60
+
61
+ This schema serves as a realistic example for testing and demonstration purposes.
62
+
63
+ == Output
64
+
65
+ Generated SVG files are saved to `examples/output/`. This directory is created automatically when examples are run.
66
+
67
+ == Common Patterns
68
+
69
+ === Basic Generation
70
+
71
+ [source,ruby]
72
+ ----
73
+ require "xseed"
74
+
75
+ generator = Xseed::Svg::SvgGenerator.new("schema.xsd")
76
+ svg_content = generator.generate
77
+ ----
78
+
79
+ === Generate to File
80
+
81
+ [source,ruby]
82
+ ----
83
+ require "xseed"
84
+
85
+ generator = Xseed::Svg::SvgGenerator.new("schema.xsd")
86
+ generator.generate_file("diagram.svg")
87
+ ----
88
+
89
+ === Inspect Schema First
90
+
91
+ [source,ruby]
92
+ ----
93
+ require "xseed"
94
+
95
+ parser = Xseed::Parser::XsdParser.new("schema.xsd")
96
+ puts "Elements: #{parser.elements.size}"
97
+ puts "Types: #{parser.types.size}"
98
+
99
+ # Then generate
100
+ generator = Xseed::Svg::SvgGenerator.new("schema.xsd")
101
+ generator.generate_file("diagram.svg")
102
+ ----
103
+
104
+ === Error Handling
105
+
106
+ [source,ruby]
107
+ ----
108
+ require "xseed"
109
+
110
+ begin
111
+ generator = Xseed::Svg::SvgGenerator.new("schema.xsd")
112
+ generator.generate_file("output.svg")
113
+ rescue Xseed::ParserError => e
114
+ puts "Parser error: #{e.message}"
115
+ rescue Xseed::Svg::GenerationError => e
116
+ puts "Generation error: #{e.message}"
117
+ end
118
+ ----
119
+
120
+ === Batch Processing
121
+
122
+ [source,ruby]
123
+ ----
124
+ require "xseed"
125
+
126
+ Dir.glob("schemas/*.xsd").each do |xsd_file|
127
+ basename = File.basename(xsd_file, ".xsd")
128
+ output = "output/#{basename}-diagram.svg"
129
+
130
+ generator = Xseed::Svg::SvgGenerator.new(xsd_file)
131
+ generator.generate_file(output)
132
+ puts "Generated: #{output}"
133
+ end
134
+ ----
135
+
136
+ == Integration Examples
137
+
138
+ === Rake Task
139
+
140
+ [source,ruby]
141
+ ----
142
+ # Rakefile
143
+ require "xseed"
144
+
145
+ desc "Generate SVG diagrams from XSD schemas"
146
+ task :diagrams do
147
+ Dir.glob("schemas/*.xsd").each do |xsd|
148
+ svg = xsd.sub("schemas/", "docs/diagrams/").sub(".xsd", ".svg")
149
+ FileUtils.mkdir_p(File.dirname(svg))
150
+
151
+ generator = Xseed::Svg::SvgGenerator.new(xsd)
152
+ generator.generate_file(svg)
153
+ puts "Generated: #{svg}"
154
+ end
155
+ end
156
+ ----
157
+
158
+ === Makefile
159
+
160
+ [source,makefile]
161
+ ----
162
+ # Makefile
163
+ SCHEMAS = $(wildcard schemas/*.xsd)
164
+ DIAGRAMS = $(SCHEMAS:schemas/%.xsd=docs/diagrams/%.svg)
165
+
166
+ all: diagrams
167
+
168
+ diagrams: $(DIAGRAMS)
169
+
170
+ docs/diagrams/%.svg: schemas/%.xsd
171
+ @mkdir -p $(dir $@)
172
+ @xseed svg $< -o $@
173
+ @echo "Generated: $@"
174
+
175
+ clean:
176
+ rm -rf docs/diagrams/*.svg
177
+
178
+ .PHONY: all diagrams clean
179
+ ----
180
+
181
+ === CI/CD Pipeline
182
+
183
+ [source,yaml]
184
+ ----
185
+ # .github/workflows/diagrams.yml
186
+ name: Generate Diagrams
187
+
188
+ on:
189
+ push:
190
+ paths:
191
+ - 'schemas/**.xsd'
192
+
193
+ jobs:
194
+ generate:
195
+ runs-on: ubuntu-latest
196
+ steps:
197
+ - uses: actions/checkout@v3
198
+
199
+ - uses: ruby/setup-ruby@v1
200
+ with:
201
+ ruby-version: '3.2'
202
+ bundler-cache: true
203
+
204
+ - name: Generate SVG diagrams
205
+ run: |
206
+ bundle exec rake diagrams
207
+
208
+ - name: Commit diagrams
209
+ run: |
210
+ git config user.name github-actions
211
+ git config user.email github-actions@github.com
212
+ git add docs/diagrams/*.svg
213
+ git commit -m "docs: regenerate SVG diagrams" || true
214
+ git push
215
+ ----
216
+
217
+ == Customization Examples
218
+
219
+ === Custom Output Directory
220
+
221
+ [source,ruby]
222
+ ----
223
+ require "xseed"
224
+ require "fileutils"
225
+
226
+ output_dir = "custom/output/path"
227
+ FileUtils.mkdir_p(output_dir)
228
+
229
+ generator = Xseed::Svg::SvgGenerator.new("schema.xsd")
230
+ output_file = File.join(output_dir, "diagram.svg")
231
+ generator.generate_file(output_file)
232
+ ----
233
+
234
+ === Conditional Generation
235
+
236
+ [source,ruby]
237
+ ----
238
+ require "xseed"
239
+
240
+ xsd_file = "schema.xsd"
241
+ parser = Xseed::Parser::XsdParser.new(xsd_file)
242
+
243
+ # Only generate if schema is complex enough
244
+ if parser.types.size > 5
245
+ generator = Xseed::Svg::SvgGenerator.new(xsd_file)
246
+ generator.generate_file("diagram.svg")
247
+ puts "Generated diagram for complex schema"
248
+ else
249
+ puts "Schema too simple, skipping diagram"
250
+ end
251
+ ----
252
+
253
+ === Performance Monitoring
254
+
255
+ [source,ruby]
256
+ ----
257
+ require "xseed"
258
+ require "benchmark"
259
+
260
+ xsd_file = "schema.xsd"
261
+
262
+ elapsed = Benchmark.realtime do
263
+ generator = Xseed::Svg::SvgGenerator.new(xsd_file)
264
+ generator.generate_file("diagram.svg")
265
+ end
266
+
267
+ puts "Generation took: #{(elapsed * 1000).round(2)}ms"
268
+ ----
269
+
270
+ == Troubleshooting
271
+
272
+ === Missing Dependencies
273
+
274
+ If examples fail with "cannot load such file" errors:
275
+
276
+ [source,shell]
277
+ ----
278
+ # Install dependencies
279
+ bundle install
280
+
281
+ # Run examples from project root
282
+ cd /path/to/xseed
283
+ ruby examples/simple_generation.rb
284
+ ----
285
+
286
+ === Permission Errors
287
+
288
+ If you get permission errors when writing files:
289
+
290
+ [source,shell]
291
+ ----
292
+ # Make output directory writable
293
+ chmod 755 examples/output
294
+
295
+ # Or run with appropriate permissions
296
+ ----
297
+
298
+ === Schema Not Found
299
+
300
+ Ensure schema files exist in the expected locations:
301
+
302
+ [source,shell]
303
+ ----
304
+ # Check schema files
305
+ ls examples/schemas/
306
+
307
+ # Use absolute paths if needed
308
+ ruby -e 'puts File.expand_path("examples/schemas/person.xsd")'
309
+ ----
310
+
311
+ == Additional Resources
312
+
313
+ * link:../README.adoc[Main README]
314
+ * link:../docs/SVG_GENERATION.adoc[SVG Generation Guide]
315
+ * link:../docs/ARCHITECTURE.adoc[Technical Architecture]
316
+ * https://github.com/metanorma/xseed[GitHub Repository]
317
+
318
+ == Contributing Examples
319
+
320
+ To contribute new examples:
321
+
322
+ 1. Create a descriptive Ruby file in `examples/`
323
+ 2. Include clear comments explaining the example
324
+ 3. Add error handling
325
+ 4. Update this README
326
+ 5. Test the example works standalone
327
+
328
+ Examples should:
329
+
330
+ * Be self-contained
331
+ * Include error handling
332
+ * Use the person.xsd schema when possible
333
+ * Output to `examples/output/`
334
+ * Include helpful console output