svg_conform 0.1.4 → 0.1.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 (38) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop_todo.yml +182 -21
  3. data/README.adoc +391 -989
  4. data/config/profiles/metanorma.yml +5 -0
  5. data/docs/api_reference.adoc +1355 -0
  6. data/docs/cli_guide.adoc +846 -0
  7. data/docs/reference_manifest.adoc +370 -0
  8. data/docs/requirements.adoc +68 -1
  9. data/examples/document_input_demo.rb +102 -0
  10. data/lib/svg_conform/document.rb +40 -1
  11. data/lib/svg_conform/profile.rb +15 -9
  12. data/lib/svg_conform/references/base_reference.rb +130 -0
  13. data/lib/svg_conform/references/id_definition.rb +38 -0
  14. data/lib/svg_conform/references/reference_classifier.rb +45 -0
  15. data/lib/svg_conform/references/reference_manifest.rb +129 -0
  16. data/lib/svg_conform/references.rb +11 -0
  17. data/lib/svg_conform/remediations/namespace_attribute_remediation.rb +34 -43
  18. data/lib/svg_conform/requirements/id_collection_requirement.rb +38 -0
  19. data/lib/svg_conform/requirements/id_reference_requirement.rb +11 -0
  20. data/lib/svg_conform/requirements/invalid_id_references_requirement.rb +3 -0
  21. data/lib/svg_conform/requirements/link_validation_requirement.rb +114 -31
  22. data/lib/svg_conform/requirements/no_external_css_requirement.rb +5 -2
  23. data/lib/svg_conform/requirements.rb +11 -9
  24. data/lib/svg_conform/sax_validation_handler.rb +16 -1
  25. data/lib/svg_conform/validation_context.rb +67 -1
  26. data/lib/svg_conform/validation_result.rb +43 -2
  27. data/lib/svg_conform/validator.rb +56 -16
  28. data/lib/svg_conform/version.rb +1 -1
  29. data/lib/svg_conform.rb +11 -2
  30. data/spec/svg_conform/commands/svgcheck_compare_command_spec.rb +1 -0
  31. data/spec/svg_conform/commands/svgcheck_compatibility_command_spec.rb +1 -0
  32. data/spec/svg_conform/commands/svgcheck_generate_command_spec.rb +1 -0
  33. data/spec/svg_conform/references/integration_spec.rb +206 -0
  34. data/spec/svg_conform/references/reference_classifier_spec.rb +142 -0
  35. data/spec/svg_conform/references/reference_manifest_spec.rb +307 -0
  36. data/spec/svg_conform/requirements/id_reference_state_spec.rb +93 -0
  37. data/spec/svg_conform/validator_input_types_spec.rb +172 -0
  38. metadata +17 -2
data/README.adoc CHANGED
@@ -25,6 +25,7 @@ SvgConform is distributed as a Ruby gem.
25
25
 
26
26
  * **Profile-based validation**: Validate SVG files against predefined or custom profiles
27
27
  * **Remediation**: Automatically fix common SVG conformance issues
28
+ * **Reference manifest**: Complete tracking of IDs and references for consumer-level validation
28
29
  * **Extensible architecture**: Easy to add new rules and profiles
29
30
  * **Command-line interface**: Validate and fix files from the command line
30
31
  * **Ruby API**: Integrate validation into Ruby applications
@@ -230,1227 +231,628 @@ if !result.valid? && profile.remediation_count > 0
230
231
  end
231
232
  ----
232
233
 
234
+ ==== Accepting multiple input types
233
235
 
236
+ The validator accepts multiple input types and always uses SAX validation for memory-safe processing:
234
237
 
235
- == Core components
236
-
237
- === Architecture
238
-
239
- The SvgConform architecture is built around a modular design that separates
240
- concerns and allows for easy extension.
241
-
242
-
243
- [source]
244
- ----
245
- ╭────────────────────────────────────────────────────────────────╮
246
- │ SvgConform │
247
- ├────────────────────────────────────────────────────────────────┤
248
- │ │
249
- │ ╭─────────────╮ ╭─────────────╮ ╭─────────────╮ │
250
- │ │ CLI │ │ Ruby API │ │ Profiles │ │
251
- │ │ │ │ │ │ Registry │ │
252
- │ ╰─────┬───────╯ ╰──────┬──────╯ ╰─────┬───────╯ │
253
- │ │ │ │ │
254
- │ └───────────────────┼─────────────────┘ │
255
- │ │ │
256
- │ ╭─────────────────────────▼─────────────────────────╮ │
257
- │ │ Validator │ │
258
- │ │ ╭─────────────╮ ╭─────────────╮ ╭─────────────╮ │ │
259
- │ │ │ Document │ │ Validation │ │ Remediation │ │ │
260
- │ │ │ Parser │ │ Engine │ │ Engine │ │ │
261
- │ │ ╰─────────────╯ ╰─────────────╯ ╰─────────────╯ │ │
262
- │ ╰─────────────────────────┬─────────────────────────╯ │
263
- │ │ │
264
- │ ╭─────────────────────────▼─────────────────────────╮ │
265
- │ │ Profile System │ │
266
- │ │ │ │
267
- │ │ ╭─────────────╮ ╭─────────────╮ ╭─────────────╮ │ │
268
- │ │ │ SVG 1.2 RFC │ │ Metanorma │ │ Future │ │ │
269
- │ │ │ Profile │ │ SVG Profile │ │ Profiles │ │ │
270
- │ │ │ │ │ │ │ │ │ │
271
- │ │ │ • svgcheck │ │ • ID links │ │ • Custom │ │ │
272
- │ │ │ compatible │ │ • No ext. │ │ rules │ │ │
273
- │ │ │ • Grayscale │ │ fonts │ │ • Org │ │ │
274
- │ │ │ • RFC 7996 │ │ • Font def. │ │ standards │ │ │
275
- │ │ ╰─────────────╯ ╰─────────────╯ ╰─────────────╯ │ │
276
- │ ╰─────────────────────────┬─────────────────────────╯ │
277
- │ │ │
278
- │ ╭─────────────────────────▼─────────────────────────╮ │
279
- │ │ Requirements & Remediations Engine │ │
280
- │ │ ╭─────────────╮ ╭─────────────╮ ╭─────────────╮ │ │
281
- │ │ │Requirements │ │Remediations │ │ Validation │ │ │
282
- │ │ │ System │ │ System │ │ Results │ │ │
283
- │ │ ╰─────────────╯ ╰─────────────╯ ╰─────────────╯ │ │
284
- │ ╰─────────────────────────┬─────────────────────────╯ │
285
- │ │ │
286
- │ ╭─────────────────────────▼─────────────────────────╮ │
287
- │ │ svgcheck Compatibility │ │
288
- │ │ ╭─────────────╮ ╭─────────────╮ ╭─────────────╮ │ │
289
- │ │ │ svgcheck │ │ YAML │ │ Report │ │ │
290
- │ │ │ Parser │ │ Mapping │ │ Comparator │ │ │
291
- │ │ ╰─────────────╯ ╰─────────────╯ ╰─────────────╯ │ │
292
- │ ╰─────────────────────────┬─────────────────────────╯ │
293
- │ │ │
294
- │ ╭─────────────────────────▼─────────────────────────╮ │
295
- │ │ Moxml │ │
296
- │ │ (XML Processing) │ │
297
- │ ╰───────────────────────────────────────────────────╯ │
298
- │ │
299
- ╰────────────────────────────────────────────────────────────────╯
300
- ----
301
-
302
-
303
- === Profiles
304
-
305
- SvgConform includes predefined profiles that can be used out-of-the-box.
306
- Each profile is designed for different use cases and compliance standards.
307
-
308
- .Predefined SVG profiles included in SvgConform
309
- [cols="2,3,3,2", options="header"]
310
- |===
311
- |Profile |Use Case |Key Features |Documentation
312
-
313
- |`base`
314
- |Foundation profile
315
- |Basic validation, namespace checks, starting point for custom profiles.
316
- |link:docs/profiles.adoc#base-profile[Details]
317
-
318
- |`metanorma`
319
- |Metanorma SVG profile
320
- |Standard SVG for Metanorma documents. Valid HREFs and ID linking. No external
321
- fonts, images and CSS. No non-SVG elements or attributes.
322
- |link:docs/profiles.adoc#no-external-css-profile[Details]
323
-
324
- |`svg_1_2_rfc`
325
- |IETF RFC SVG 1.2 profile
326
- |RFC 7996/6949 compliant. Black/white color only, limited elements, generic
327
- fonts. Fully compatible with `svgcheck` outcomes.
328
- |link:docs/profiles.adoc#svg-1-2-rfc-profile[Details]
329
-
330
- |`svg_1_2_rfc_with_rdf`
331
- |IETF RFC SVG 1.2 profile with RDF metadata
332
- |Same as `svg_1_2_rfc`, but allows RDF/Dublin Core metadata from design tools.
333
- Supported by `svgcheck`.
334
- |link:docs/profiles.adoc#svg-1-2-rfc-with-rdf-profile[Details]
335
-
336
- |`no_external_css`
337
- |Self-contained SVG
338
- |No external references, security-focused, offline usage.
339
- |link:docs/profiles.adoc#no-external-css-profile[Details]
340
-
341
- |`lucid_fix`
342
- |Lucid cleanup
343
- |Remove Lucid-specific metadata, clean standard SVG output
344
- |link:docs/profiles.adoc#lucid-fix-profile[Details]
345
- |===
346
-
347
- For complete profile documentation, including inheritance, customization, RDF
348
- metadata support, and selection guides, see
349
- link:docs/profiles.adoc[SVG Profiles Documentation].
350
-
351
- For detailed information about configuring RDF metadata support in profiles, see
352
- link:docs/rdf_metadata_support.adoc[RDF Metadata Support Documentation].
353
-
354
-
355
-
356
- === Requirements
357
-
358
- SvgConform includes different requirement checkers that validate various aspects
359
- of SVG documents.
360
-
361
- There are two main categories of requirements:
362
-
363
- * structural requirements: requirements set towards the XML structure and syntax of SVG documents
364
- * logical requirements: requirements set towards content and stylistic aspects of SVG documents
365
-
366
- .SvgConform supported requirement classes
367
- [cols="2,2,3", options="header"]
368
- |===
369
- |Type |Requirement |Description
370
-
371
- |Structural
372
- |link:docs/requirements.adoc#namespace-requirement[`NamespaceRequirement`]
373
- |Ensures proper SVG namespace declarations
374
-
375
- |Structural
376
- |link:docs/requirements.adoc#namespace-attributes-requirement[`NamespaceAttributesRequirement`]
377
- |Validates namespace attributes are from allowed namespaces
378
-
379
- |Structural
380
- |link:docs/requirements.adoc#allowed-elements-requirement[`AllowedElementsRequirement`]
381
- |Restricts which SVG elements are permitted
382
-
383
- |Structural
384
- |link:docs/requirements.adoc#viewbox-required-requirement[`ViewboxRequiredRequirement`]
385
- |Requires viewBox attributes on root elements
386
-
387
- |Logical
388
- |link:docs/requirements.adoc#color-restrictions-requirement[`ColorRestrictionsRequirement`]
389
- |Enforces color usage restrictions (e.g., grayscale only)
390
-
391
- |Logical
392
- |link:docs/requirements.adoc#font-family-requirement[`FontFamilyRequirement`]
393
- |Controls font family usage and validates font specifications
394
-
395
- |Logical
396
- |link:docs/requirements.adoc#no-external-css-requirement[`NoExternalCssRequirement`]
397
- |Prevents external CSS references to ensure self-contained documents
398
-
399
- |Logical
400
- |link:docs/requirements.adoc#no-external-fonts-requirement[`NoExternalFontsRequirement`]
401
- |Validates that no external font references are present
402
-
403
- |Logical
404
- |link:docs/requirements.adoc#no-external-images-requirement[`NoExternalImagesRequirement`]
405
- |Validates that no external image references are present
406
-
407
- |Logical
408
- |link:docs/requirements.adoc#forbidden-content-requirement[`ForbiddenContentRequirement`]
409
- |Prevents inclusion of forbidden elements and attributes
410
-
411
- |Logical
412
- |link:docs/requirements.adoc#id-reference-requirement[`IdReferenceRequirement`]
413
- |Validates that ID references point to existing elements
414
-
415
- |Logical
416
- |link:docs/requirements.adoc#invalid-id-references-requirement[`InvalidIdReferencesRequirement`]
417
- |Detects and validates broken ID references in SVG documents
418
-
419
- |Logical
420
- |link:docs/requirements.adoc#link-validation-requirement[`LinkValidationRequirement`]
421
- |Validates that links use only ASCII characters (IETF requirement)
422
-
423
- |Logical
424
- |link:docs/requirements.adoc#style-requirement[`StyleRequirement`]
425
- |Comprehensive CSS style validation including syntax and properties
426
-
427
- |Logical
428
- |link:docs/requirements.adoc#style-promotion-requirement[`StylePromotionRequirement`]
429
- |Detects style properties that should be promoted to SVG attributes
430
- |===
431
-
432
-
433
-
434
- === Remediations
435
-
436
- Remediations are automatic fixing actions that can resolve requirement failures.
437
- Each remediation targets one or more specific requirements.
438
-
439
- SvgConform includes different remediation actions that can automatically fix
440
- SVG documents to resolve requirement violations.
441
-
442
- .SvgConform supported remediation classes
443
- [cols="2,2,3,2", options="header"]
444
- |===
445
- |Type |Remediation |Description |Targets
446
-
447
- |Content Conversion
448
- |link:docs/remediation.adoc#color-remediation[`ColorRemediation`]
449
- |Converts invalid colors to allowed alternatives using threshold-based conversion
450
- |link:docs/requirements.adoc#color-restrictions-requirement[`ColorRestrictionsRequirement`]
451
-
452
- |Content Conversion
453
- |link:docs/remediation.adoc#font-remediation[`FontRemediation`]
454
- |Maps font families to generic alternatives (serif, sans-serif, monospace)
455
- |link:docs/requirements.adoc#font-family-requirement[`FontFamilyRequirement`]
456
-
457
- |Content Conversion
458
- |link:docs/remediation.adoc#font-embedding-remediation[`FontEmbeddingRemediation`]
459
- |Converts external font references to embedded data URIs
460
- |link:docs/requirements.adoc#no-external-fonts-requirement[`NoExternalFontsRequirement`]
461
-
462
- |Content Conversion
463
- |link:docs/remediation.adoc#image-embedding-remediation[`ImageEmbeddingRemediation`]
464
- |Converts external image references to embedded data URIs
465
- |link:docs/requirements.adoc#no-external-images-requirement[`NoExternalImagesRequirement`]
466
-
467
- |Element/Attribute Removal
468
- |link:docs/remediation.adoc#namespace-remediation[`NamespaceRemediation`]
469
- |Removes invalid namespace elements and cleans up namespace declarations
470
- |link:docs/requirements.adoc#namespace-requirement[`NamespaceRequirement`]
471
-
472
- |Element/Attribute Removal
473
- |link:docs/remediation.adoc#namespace-attribute-remediation[`NamespaceAttributeRemediation`]
474
- |Removes attributes from disallowed namespaces
475
- |link:docs/requirements.adoc#namespace-attributes-requirement[`NamespaceAttributesRequirement`]
476
-
477
- |Element/Attribute Removal
478
- |link:docs/remediation.adoc#no-external-css-remediation[`NoExternalCssRemediation`]
479
- |Removes external CSS references including @import and external stylesheets
480
- |link:docs/requirements.adoc#no-external-css-requirement[`NoExternalCssRequirement`]
481
-
482
- |Addition
483
- |link:docs/remediation.adoc#viewbox-remediation[`ViewboxRemediation`]
484
- |Adds missing viewBox attributes to root SVG elements
485
- |link:docs/requirements.adoc#viewbox-required-requirement[`ViewboxRequiredRequirement`]
486
-
487
- |Style Processing
488
- |link:docs/remediation.adoc#style-promotion-remediation[`StylePromotionRemediation`]
489
- |Promotes CSS style properties to equivalent SVG attributes
490
- |link:docs/requirements.adoc#style-promotion-requirement[`StylePromotionRequirement`]
491
-
492
- |Reference Fixing
493
- |link:docs/remediation.adoc#invalid-id-references-remediation[`InvalidIdReferencesRemediation`]
494
- |Fixes or removes broken ID references and invalid href attributes
495
- |link:docs/requirements.adoc#id-reference-requirement[`IdReferenceRequirement`], `InvalidIdReferencesRequirement`
496
- |===
497
-
498
-
499
- === Requirement and remediation mapping
500
-
501
- Remediations are mapped to requirements using the `targets` configuration in
502
- profile YAML files.
503
-
504
- [source,yaml]
505
- ----
506
- remediations:
507
- - id: "fix_invalid_colors"
508
- type: "ColorRemediationAction"
509
- description: "Convert invalid colors to black or white"
510
- targets: ["color_restrictions"] # Maps to ColorRestrictionsRequirement
238
+ [source,ruby]
511
239
  ----
240
+ validator = SvgConform::Validator.new
512
241
 
513
- This mapping system allows:
514
-
515
- * **Targeted fixes**: Remediations only run when their target requirements fail
516
- * **Flexible configuration**: Multiple remediations can target the same requirement
517
- * **Conditional application**: Remediations can be enabled/disabled per profile
518
-
519
-
242
+ # String input: Direct SAX parsing
243
+ result = validator.validate(svg_string, profile: :metanorma)
520
244
 
521
- === Validation and remediation flow
245
+ # Moxml documents/elements: Serialize once, then SAX validate
246
+ moxml_doc = Moxml.new.parse(svg_string)
247
+ result = validator.validate(moxml_doc, profile: :metanorma)
522
248
 
523
- The following steps illustrates the data flow through the core components of
524
- SvgConform.
249
+ moxml_element = moxml_doc.root
250
+ result = validator.validate(moxml_element, profile: :metanorma)
525
251
 
526
- . An SVG file is read and parsed into a Document object.
527
- . The Document is validated against a Profile using the Validator.
528
- . The Validator applies Requirements and collects results in a ConformanceReport object.
529
- . If fixing is enabled, the Validator uses the RemediationEngine to apply Remediations.
530
- . The fixed Document is returned along with the validation results in the ConformanceReport.
252
+ # Nokogiri documents/elements: Serialize once, then SAX validate
253
+ nokogiri_doc = Nokogiri::XML(svg_string)
254
+ result = validator.validate(nokogiri_doc, profile: :metanorma)
531
255
 
532
- [source]
256
+ nokogiri_element = nokogiri_doc.root # Common in metanorma integration
257
+ result = validator.validate(nokogiri_element, profile: :metanorma)
533
258
  ----
534
- ┌─────────────┐ ┌─────────────┐ ┌─────────────┐
535
- │ SVG File │───▶│ Document │───▶│ Validator │
536
- │ │ │ Parser │ │ │
537
- └─────────────┘ └─────────────┘ └─────┬───────┘
538
-
539
- ┌─────────────┐ │
540
- │ Profile │◀─────────┘
541
- └─────┬───────┘
542
-
543
- ┌─────▼───────┐
544
- │ Rules │
545
- └─────┬───────┘
546
-
547
- ┌─────▼───────┐ ┌─────────────┐
548
- │Requirements │───▶│ Validation │
549
- │ │ │ Result │
550
- └─────────────┘ └─────┬───────┘
551
-
552
- ┌─────────────┐ │
553
- │Remediations │◀─────────┘
554
- └─────┬───────┘
555
-
556
- ┌───────▼────────┐
557
- │ Fixed Document │
558
- └────────────────┘
559
- ----
560
-
561
- === Classes
562
259
 
563
- ==== Document (`SvgConform::Document`)
260
+ **Why SAX validation for all inputs?**
564
261
 
565
- Represents an SVG document. The SVG document in XML is parsed using the `Moxml`
566
- library, and provides SVG-specific functionality through the Document class.
262
+ SAX (Simple API for XML) parsing is memory-safe and can handle arbitrarily large SVG files without hanging. DOM-based validation loads the entire tree into memory, which can cause performance issues or crashes with large files.
567
263
 
568
- ==== Validator (`SvgConform::Validator`)
264
+ **Benefits of accepting DOM objects**:
569
265
 
570
- The validator is the main entry point for SVG validation. It orchestrates the
571
- validation process with loading profiles, applying rules, and collecting results.
266
+ When integrating with tools like Metanorma where SVG elements are already parsed:
572
267
 
573
- ==== Profile (`SvgConform::Profile`)
574
-
575
- A profile is a collection of requirements and remediations that define a specific
576
- SVG conformance standard. Profiles are defined in YAML configuration files and are
577
- loaded dynamically at runtime.
578
-
579
- Notice that there are requirement violations that cannot be automatically
580
- remediated. For example, if an SVG uses a forbidden element, the remediation may
581
- simply remove it, which could lead to loss of important content.
268
+ [source,ruby]
269
+ ----
270
+ # Old way: User manually serializes
271
+ result = validator.validate(svg_element.to_xml, profile: :metanorma)
582
272
 
273
+ # ✅ New way: Library handles serialization internally
274
+ result = validator.validate(svg_element, profile: :metanorma)
275
+ ----
583
276
 
584
- ==== Requirements
277
+ Benefits:
278
+ - **Cleaner API**: No need to call `.to_xml` explicitly
279
+ - **Type flexibility**: Works with Nokogiri, Moxml, or strings
280
+ - **Safe for large files**: Always uses memory-efficient SAX parsing
281
+ - **Backward compatible**: String input still works as before
585
282
 
586
- An SvgConform requirement is a specific validation check that determines if an SVG
587
- document meets certain criteria. Requirements are implemented as classes that inherit
588
- from `SvgConform::Requirements::BaseRequirement`.
589
283
 
590
- Each requirement class focuses on a single concern implemented using
591
- XML tree traversal and validation logic.
284
+ === Reference manifest
592
285
 
593
- Every requirement check can be configured with specific parameters to fine-tune
594
- its behavior.
286
+ SvgConform provides comprehensive ID and reference tracking through its reference manifest system:
595
287
 
596
- Profiles can include multiple requirements to cover various aspects of SVG
597
- conformance.
288
+ [source,ruby]
289
+ ----
290
+ result = validator.validate(svg_content, profile: :metanorma)
598
291
 
599
- ==== Remediations
292
+ # Access the reference manifest
293
+ manifest = result.reference_manifest
600
294
 
601
- An SvgConform remediation is an automatic fixing action that can be applied to
602
- an SVG document to resolve one or more requirement failures. Remediations are
603
- implemented as classes that inherit from `SvgConform::Remediations::BaseRemediation`.
295
+ # Get all defined IDs
296
+ manifest.available_ids.each do |id_def|
297
+ puts "ID: #{id_def.id_value} at line #{id_def.line_number}"
298
+ end
604
299
 
605
- Each remediation class focuses on a specific fixing action implemented using
606
- XML tree manipulation and editing.
300
+ # Check for unresolved internal references
301
+ if result.has_unresolved_references?
302
+ result.unresolved_internal_references.each do |ref|
303
+ puts "Unresolved reference: #{ref.value} at line #{ref.line_number}"
304
+ end
305
+ end
607
306
 
608
- Every remediation can be configured with specific parameters to customize its
609
- behavior. A remediation can target one or more specific requirements through
610
- configuration options.
307
+ # Check for external references
308
+ if result.has_external_references?
309
+ result.external_references.each do |ref|
310
+ puts "External reference: #{ref.value}"
311
+ end
312
+ end
313
+ ----
611
314
 
315
+ See link:docs/reference_manifest.adoc[Reference Manifest Documentation] for complete details.
612
316
 
613
317
 
614
318
  [[command_line_interface]]
615
319
  == Command line interface
616
320
 
617
- === General
618
-
619
- The `svg_conform` command provides a comprehensive CLI for validation and fixing.
321
+ The `svg_conform` command-line tool provides validation and remediation capabilities for SVG files.
620
322
 
323
+ === Basic commands
621
324
 
622
- === `svg_conform profiles`
623
-
624
- The `profiles` command lists all available SVG profiles included in SvgConform.
625
-
626
- Syntax:
325
+ ==== List available profiles
627
326
 
628
327
  [source,bash]
629
328
  ----
630
- svg_conform profiles [OPTIONS]
631
-
632
- Options:
633
- -v, --verbose Show detailed profile information
329
+ $ svg_conform profiles
634
330
  ----
635
331
 
636
- [example]
637
- ====
332
+ Show detailed information about profiles:
333
+
638
334
  [source,bash]
639
335
  ----
640
- # List all profiles
641
- $ svg_conform profiles
642
-
643
- Available SVG Profiles
644
- ========================================
645
-
646
- ╭──────────────────────┬───────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
647
- │ Profile │ Description │
648
- ├──────────────────────┼───────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
649
- │ base │ Base SVG validation profile with common requirements │
650
- │ lucid_fix │ Lucid SVG Fix Profile - Removes invalid use element references and namespace attributes from Lucid-generated SVGs │
651
- │ metanorma │ Metanorma SVG Profile - SVG requirements for Metanorma technical documents with embedded resources │
652
- │ no_external_css │ Security-focused profile that disallows external CSS references │
653
- │ svg_1_2_rfc │ SVG 1.2 RFC Profile (RFC 7996) - Black and white diagrams for technical documents │
654
- │ svg_1_2_rfc_with_rdf │ SVG 1.2 RFC Profile with RDF metadata support - Allows RDF/Dublin Core metadata in SVG files │
655
- ╰──────────────────────┴───────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
336
+ $ svg_conform profiles --verbose
656
337
  ----
657
- ====
658
-
659
338
 
660
-
661
- === `svg_conform check`
662
-
663
- The `check` command validates SVG files against a specified profile and optionally
664
- applies automatic remediations. It supports single files, multiple files via shell
665
- glob expansion, and directory scanning.
666
-
667
- Syntax:
339
+ ==== Validate a single SVG file
668
340
 
669
341
  [source,bash]
670
342
  ----
671
- svg_conform check [*FILES] [OPTIONS]
672
- svg_conform check --directory PATH [OPTIONS]
343
+ $ svg_conform check file.svg --profile=metanorma
344
+ ----
673
345
 
674
- Required Options:
675
- -p, --profile PROFILE Profile to validate against
346
+ Options:
676
347
 
677
- Input Options:
678
- -d, --directory PATH Directory to scan recursively for SVG files
348
+ * `--profile=PROFILE` or `-p`: Profile to validate against (default: `svg_1_2_rfc`)
349
+ * `--format=FORMAT`: Output format: `table` (default), `json`, or `yaml`
350
+ * `--output=FILE` or `-o`: Save report to file
679
351
 
680
- Remediation Options:
681
- -f, --fix Enable automatic remediation
682
- --output-dir DIR Output directory for remediated files (required for multi-file)
683
- --in-place Replace original files (requires --force)
684
- --force Confirm destructive operations
685
- --fix-output FILE Output file for single file mode (default: FILE.fixed.svg)
352
+ Example with JSON output:
686
353
 
687
- Reporting Options:
688
- --format FORMAT Output format for single file: table, yaml, json (default: table)
689
- -o, --output FILE Output file for single file mode
690
- --report-format FORMAT Batch report format: json, yaml
691
- --report-output FILE Save detailed batch report to file
692
- --manifest FILE Manifest file path (default: manifest.json with --fix)
693
- -q, --quiet Suppress per-file output, show summary only
694
- -v, --verbose Show detailed progress
354
+ [source,bash]
355
+ ----
356
+ $ svg_conform check file.svg -p metanorma --format=json --output=report.json
695
357
  ----
696
358
 
697
- The check command supports three operational modes:
698
-
699
- **Single File Mode:**
359
+ ==== Fix a single SVG file
700
360
 
701
- Validates a single SVG file and outputs a detailed validation report.
361
+ Apply automatic remediations to fix conformance issues:
702
362
 
703
363
  [source,bash]
704
364
  ----
705
- # Basic validation
706
- svg_conform check file.svg -p metanorma
707
-
708
- # With remediation
709
- svg_conform check file.svg -p metanorma -f --fix-output fixed.svg
710
-
711
- # Output YAML report
712
- svg_conform check file.svg -p metanorma --format yaml -o report.yaml
365
+ $ svg_conform check file.svg --profile=metanorma --fix
713
366
  ----
714
367
 
715
- **Multiple Files Mode (Shell Glob):**
716
-
717
- Validates multiple files specified via shell glob patterns. The shell expands
718
- patterns like `*.svg` before passing to the command.
368
+ Specify custom output file:
719
369
 
720
370
  [source,bash]
721
371
  ----
722
- # Validate all SVG files in current directory
723
- svg_conform check *.svg -p metanorma
724
-
725
- # Validate with pattern matching
726
- svg_conform check images/*/*.svg -p metanorma
372
+ $ svg_conform check file.svg -p metanorma -f --fix-output=fixed.svg
373
+ ----
727
374
 
728
- # Fix multiple files
729
- svg_conform check *.svg -p metanorma -f --output-dir fixed/
375
+ Options:
730
376
 
731
- # With JSON batch report
732
- svg_conform check *.svg -p metanorma --report-format json --report-output report.json
733
- ----
377
+ * `--fix` or `-f`: Enable automatic remediation
378
+ * `--fix-output=FILE`: Output file for remediated SVG (default: `FILE.fixed.svg`)
734
379
 
735
- **Directory Mode:**
380
+ ==== Process multiple files
736
381
 
737
- Recursively scans a directory for all SVG files using the `--directory` or `-d` flag.
382
+ Process multiple SVG files at once:
738
383
 
739
384
  [source,bash]
740
385
  ----
741
- # Scan directory and validate
742
- svg_conform check -d images/ -p metanorma
743
-
744
- # Scan and remediate to new directory
745
- svg_conform check -d images/ -p metanorma -f --output-dir fixed/
746
-
747
- # Replace files in place (requires confirmation)
748
- svg_conform check -d images/ -p metanorma -f --in-place --force
386
+ $ svg_conform check file1.svg file2.svg file3.svg --profile=metanorma
387
+ ----
749
388
 
750
- # Quiet mode with detailed JSON report
751
- svg_conform check -d images/ -p metanorma -f --output-dir fixed/ --quiet \
752
- --report-format json --report-output report.json
389
+ With remediation, an output directory is required:
753
390
 
754
- # With custom manifest file
755
- svg_conform check -d images/ -p metanorma -f --output-dir fixed/ --manifest mappings.json
391
+ [source,bash]
392
+ ----
393
+ $ svg_conform check *.svg -p metanorma --fix --output-dir=fixed/
756
394
  ----
757
395
 
758
- **Batch Report Format:**
396
+ ==== Process a directory
759
397
 
760
- When processing multiple files or directories, a batch summary is displayed:
398
+ Recursively process all SVG files in a directory:
761
399
 
762
- [source]
400
+ [source,bash]
763
401
  ----
764
- BATCH VALIDATION SUMMARY
765
- Directory: /path/to/images
766
- Profile: metanorma
767
- Files processed: 56
768
- Valid before: 0
769
- Remediated: 56
770
- Valid after: 56
771
- Failed: 0
772
- Success rate: 100.0%
773
- Manifest written to manifest.json
402
+ $ svg_conform check --directory=images/ --profile=metanorma
774
403
  ----
775
404
 
776
- If `--report-format` is specified, a detailed report is generated in JSON or
777
- YAML format using lutaml-model serialization:
405
+ With remediation:
778
406
 
779
- [source,json]
407
+ [source,bash]
780
408
  ----
781
- {
782
- "directory": "/path/to/images",
783
- "profile": "metanorma",
784
- "timestamp": "2025-10-12T15:36:25+08:00",
785
- "total_files": 56,
786
- "valid_before": 0,
787
- "valid_after": 56,
788
- "remediated": 56,
789
- "failed": 0,
790
- "success_rate": 100.0,
791
- "files": [
792
- {
793
- "filename": "diagram.svg",
794
- "original_path": "/path/to/images/diagram.svg",
795
- "valid_before": false,
796
- "valid_after": true,
797
- "errors_before": 3,
798
- "errors_after": 0,
799
- "remediated_path": "/path/to/fixed/diagram.svg",
800
- "status": "remediated"
801
- }
802
- ],
803
- "manifest": {
804
- "/path/to/images/diagram.svg": "/path/to/fixed/diagram.svg"
805
- }
806
- }
409
+ $ svg_conform check -d images/ -p metanorma --fix --output-dir=fixed/
807
410
  ----
808
411
 
809
- **Manifest File:**
412
+ Replace files in-place (use with caution):
810
413
 
811
- When using `--fix`, a manifest file is automatically created (or can be
812
- explicitly specified with `--manifest`). The manifest maps original file paths
813
- to their remediated counterparts:
814
-
815
- [source,json]
414
+ [source,bash]
816
415
  ----
817
- {
818
- "timestamp": "2025-10-12T15:00:00+08:00",
819
- "profile": "metanorma",
820
- "mappings": {
821
- "/original/path/file1.svg": "/fixed/path/file1.svg",
822
- "/original/path/file2.svg": "/fixed/path/file2.svg"
823
- }
824
- }
416
+ $ svg_conform check -d images/ -p metanorma --fix --in-place --force
825
417
  ----
826
418
 
419
+ ==== Batch processing options
827
420
 
828
- === `svg_conform version`
421
+ Additional options for batch processing:
829
422
 
830
- The `version` command displays the current version of SvgConform.
423
+ * `--quiet` or `-q`: Suppress per-file output, show summary only
424
+ * `--verbose` or `-v`: Show detailed progress
425
+ * `--report-format=FORMAT`: Generate detailed report in `json` or `yaml`
426
+ * `--report-output=FILE`: Save detailed batch report to file
427
+ * `--manifest=FILE`: Generate manifest mapping original to remediated files (default: `manifest.json`)
831
428
 
832
- Syntax:
429
+ Example with detailed reporting:
833
430
 
834
431
  [source,bash]
835
432
  ----
836
- svg_conform version
433
+ $ svg_conform check -d images/ -p metanorma -f --output-dir=fixed/ \
434
+ --report-format=json --report-output=batch-report.json \
435
+ --manifest=file-mapping.json
837
436
  ----
838
437
 
839
- [example]
438
+ ==== Display version
439
+
840
440
  [source,bash]
841
441
  ----
842
442
  $ svg_conform version
843
- SvgConform 0.1.0
844
443
  ----
845
444
 
445
+ === Exit codes
846
446
 
447
+ * `0`: All files valid or successfully remediated
448
+ * `1`: Validation failures or errors occurred
847
449
 
848
- [[ruby_api_reference]]
849
- == Ruby API
450
+ === Common workflows
850
451
 
851
- === Basic usage
452
+ ==== Quality control workflow
852
453
 
853
- [source,ruby]
454
+ Check all SVG files before deployment:
455
+
456
+ [source,bash]
457
+ ----
458
+ $ svg_conform check -d assets/images/ -p metanorma --quiet
854
459
  ----
855
- require 'svg_conform'
856
460
 
857
- # Validate a file
858
- result = SvgConform.validate_file('diagram.svg', profile: :svg_1_2_rfc)
461
+ ==== Batch remediation workflow
859
462
 
860
- # Check validation status
861
- puts "Valid: #{result.valid?}"
862
- puts "Errors: #{result.errors.count}"
863
- puts "Warnings: #{result.warnings.count}"
463
+ Fix all non-conforming files:
864
464
 
865
- # Get detailed error information
866
- result.errors.each do |error|
867
- puts "#{error.rule.id}: #{error.message}"
868
- puts " Element: #{error.element}" if error.element
869
- puts " Location: #{error.location}" if error.location
870
- end
465
+ [source,bash]
871
466
  ----
467
+ # 1. Validate and identify issues
468
+ $ svg_conform check -d images/ -p metanorma --report-format=json \
469
+ --report-output=pre-fix-report.json
872
470
 
873
- === Advanced usage
471
+ # 2. Apply fixes
472
+ $ svg_conform check -d images/ -p metanorma --fix --output-dir=fixed/ \
473
+ --manifest=manifest.json
874
474
 
875
- [source,ruby]
475
+ # 3. Verify fixes
476
+ $ svg_conform check -d fixed/ -p metanorma --report-format=json \
477
+ --report-output=post-fix-report.json
876
478
  ----
877
- # Create validator instance
878
- validator = SvgConform::Validator.new
879
479
 
880
- # Validate with custom options
881
- result = validator.validate_file('diagram.svg',
882
- profile: :svg_1_2_rfc,
883
- fix: true,
884
- strict: false
885
- )
480
+ ==== Integration with CI/CD
886
481
 
887
- # Access fixed document
888
- if result.fixed?
889
- fixed_svg = result.fixed_document.to_xml
890
- File.write('diagram_fixed.svg', fixed_svg)
891
- end
482
+ Validate SVGs in continuous integration:
892
483
 
893
- # Get profile information
894
- profile_info = validator.profile_info(:svg_1_2_rfc)
895
- puts "Profile: #{profile_info[:name]}"
896
- puts "Description: #{profile_info[:description]}"
897
- puts "Rules: #{profile_info[:rules].map { |r| r[:id] }.join(', ')}"
484
+ [source,bash]
898
485
  ----
486
+ $ svg_conform check -d docs/images/ -p metanorma --quiet
899
487
 
900
- === Working with loaded SVG content
901
-
902
- [source,ruby]
488
+ # Exit code 0 = pass, 1 = fail
903
489
  ----
904
- # Parse SVG content
905
- document = SvgConform::Document.from_content(svg_string)
906
490
 
907
- # Access document elements
908
- root = document.root
909
- puts "Root element: #{root.name}"
910
- puts "Namespace: #{root.namespace}"
491
+ === Complete reference
911
492
 
912
- # Find elements
913
- circles = document.find_elements('circle')
914
- texts = document.find_elements('text')
493
+ See link:docs/cli_guide.adoc[CLI Guide] for comprehensive documentation including:
915
494
 
916
- # Modify document
917
- fixer = SvgConform::Fixer.new(document)
918
- fixer.remove_element(some_element)
919
- fixer.set_attribute(element, 'fill', 'black')
495
+ * All available profiles and their requirements
496
+ * Detailed option descriptions
497
+ * Advanced usage patterns
498
+ * Troubleshooting common issues
499
+ * Integration examples
920
500
 
921
- # Get modified XML
922
- modified_svg = fixer.to_xml
923
- ----
924
501
 
502
+ [[ruby_api_reference]]
503
+ == Ruby API reference
925
504
 
926
- == Configuration
505
+ The SvgConform Ruby API provides programmatic access to SVG validation and remediation.
927
506
 
928
- === Profile configuration
507
+ === Basic validation
929
508
 
930
- Profiles can be configured using YAML files in the `config/profiles/` directory:
509
+ ==== Using the validator
931
510
 
932
- [source,yaml]
511
+ [source,ruby]
933
512
  ----
934
- # config/profiles/custom.yml
935
- name: "Custom Profile"
936
- description: "Custom SVG profile for specific requirements"
937
- extends: "base" # Optional: inherit from another profile
513
+ require 'svg_conform'
938
514
 
939
- rules:
940
- - id: "namespace"
941
- type: "namespace_rule"
942
- config:
943
- required_namespace: "http://www.w3.org/2000/svg"
515
+ validator = SvgConform::Validator.new
516
+ result = validator.validate(svg_content, profile: :metanorma)
944
517
 
945
- - id: "allowed_elements"
946
- type: "allowed_elements_rule"
947
- config:
948
- allowed_elements:
949
- - "svg"
950
- - "g"
951
- - "rect"
952
- - "circle"
953
- - "path"
954
- - "text"
518
+ puts "Valid: #{result.valid?}"
519
+ puts "Errors: #{result.errors.count}"
520
+ puts "Warnings: #{result.warnings.count}"
955
521
 
956
- - id: "color_restrictions"
957
- type: "color_restrictions_rule"
958
- config:
959
- grayscale_only: true
960
- allowed_colors:
961
- - "black"
962
- - "white"
963
- - "gray"
522
+ # Access error details
523
+ result.errors.each do |error|
524
+ puts "#{error.requirement_id}: #{error.message}"
525
+ puts " Location: #{error.element}" if error.element
526
+ end
964
527
  ----
965
528
 
966
- === Requirement configuration
967
-
968
- TODO.
969
-
970
- === Remediation configuration
971
-
972
- TODO.
973
-
974
-
975
- == Extending SvgConform
529
+ ==== Loading profiles
976
530
 
977
- === Custom profiles
531
+ Load a profile by name:
978
532
 
979
- Create a new profile by defining a YAML configuration:
980
-
981
- [source,yaml]
533
+ [source,ruby]
534
+ ----
535
+ profile = SvgConform::Profiles.get(:svg_1_2_rfc)
982
536
  ----
983
- # config/profiles/my_organization.yml
984
- profile:
985
- name: "My Organization SVG Profile"
986
- description: "SVG profile for internal use"
987
- import: "base" # Optional: inherit from another profile
988
-
989
- requirements:
990
- - id: "namespace"
991
- type: "NamespaceRequirement"
992
- description: "Ensure proper SVG namespace"
993
537
 
994
- - id: "custom_requirement"
995
- type: "CustomRequirement"
996
- description: "Validate custom elements"
997
- config:
998
- custom_option: "organization_value"
538
+ Available built-in profiles:
999
539
 
1000
- - id: "security_restrictions"
1001
- type: "NoExternalCssRequirement"
1002
- description: "Prevent external CSS references"
540
+ * `:base` - Minimal SVG validation
541
+ * `:svg_1_2_rfc` - RFC 7996 compliance (IETF XMLRFC documents)
542
+ * `:svg_1_2_rfc_with_rdf` - RFC 7996 with RDF metadata support
543
+ * `:metanorma` - Metanorma document requirements
544
+ * `:lucid` - Lucid profile
545
+ * `:no_external_css` - Disallow external CSS
1003
546
 
1004
- remediations:
1005
- - id: "fix_namespace"
1006
- type: "NamespaceRemediationAction"
1007
- description: "Add missing SVG namespace"
1008
- targets: ["namespace"]
547
+ Load a custom profile from file:
1009
548
 
1010
- - id: "fix_custom_elements"
1011
- type: "CustomRemediationAction"
1012
- description: "Fix custom element issues"
1013
- targets: ["custom_requirement"]
1014
- config:
1015
- default_value: "organization_default"
549
+ [source,ruby]
550
+ ----
551
+ profile = SvgConform::Profile.load_from_file('path/to/profile.yml')
1016
552
  ----
1017
553
 
1018
- Then load the profile:
554
+ ==== Validating with profiles
1019
555
 
1020
556
  [source,ruby]
1021
557
  ----
1022
- # Load and use the custom profile
1023
- profile = SvgConform::Profile.load_from_file('config/profiles/my_organization.yml')
558
+ profile = SvgConform::Profiles.get(:metanorma)
1024
559
  document = SvgConform::Document.new(svg_content)
1025
560
  result = profile.validate(document)
1026
561
 
1027
- # Apply remediations if needed
1028
- if !result.valid? && profile.remediation_count > 0
1029
- changes = profile.apply_remediations(document)
1030
- puts "Applied #{changes.length} remediations"
562
+ if result.valid?
563
+ puts "SVG is valid!"
564
+ else
565
+ puts "Found #{result.errors.count} errors"
1031
566
  end
1032
567
  ----
1033
568
 
1034
- [[external_compliance]]
1035
- == External compliance
1036
-
1037
- === General
569
+ === Applying remediations
1038
570
 
1039
- SvgConform supports external compliance validation through compatibility testing
1040
- and comparison with external SVG validation tools.
571
+ ==== Basic remediation
1041
572
 
1042
- SvgConform provides validation report comparison capabilities that enable
1043
- assessment of compatibility with external SVG validation tools. This supports
1044
- migration workflows and quality assurance processes.
1045
-
1046
- === svgcheck
1047
-
1048
- IETF provides the `svgcheck` tool, a Python-based SVG validator and fixer
1049
- that checks SVG files against the SVG 1.2 RFC profile defined in RFC 7996.
1050
-
1051
- SvgConform supports validation compatibility testing against the IETF Python
1052
- svgcheck tool for SVG 1.2 RFC validation.
1053
-
1054
- SvgConform includes a compatibility analysis feature that compares its
1055
- validation results with those of `svgcheck`, helping users identify any
1056
- discrepancies or issues.
1057
-
1058
- IMPORTANT: As of version 2025-10-12, SvgConform's SVG 1.2 RFC profile provides a
1059
- 100% match in check and repair modes of svgcheck for all test files, except for
1060
- the `full-tiny.svg` file, which svgcheck marks as invalid and fails to repair.
1061
-
1062
-
1063
- === svgcheck testing workflow
1064
-
1065
- The external compliance testing workflow involves generating reference outputs
1066
- from external tools and comparing validation results:
1067
-
1068
- [source,bash]
573
+ [source,ruby]
1069
574
  ----
1070
- # 1. Generate external tool outputs for reference
1071
- svg_conform svgcheck generate SVGCHECK_REPO_LOCAL_PATH --mode both
1072
-
1073
- # 2. Generate comparison reports
1074
- svg_conform svgcheck compatibility --output comparison_report.json
1075
- ----
1076
-
1077
-
1078
- === svgcheck compatibility architecture
1079
-
1080
- SvgConform provides compatibility with the IETF Python svgcheck tool through a
1081
- sophisticated mapping and comparison system that enables validation against the
1082
- SVG 1.2 RFC profile.
1083
-
1084
- .Architecture of svgcheck compatibility checks
1085
- [source]
1086
- ----
1087
- ╭────────────────────────────────────────────────────────────────╮
1088
- │ svgcheck Compatibility System │
1089
- │ (SvgConform ↔ svgcheck Python tool) │
1090
- ├────────────────────────────────────────────────────────────────┤
1091
- │ │
1092
- │ ╭─────────────╮ ╭─────────────────────────────────────╮ │
1093
- │ │ svgcheck │ │ YAML Mapping │ │
1094
- │ │ Raw Errors │───▶│ config/svgcheck_mapping.yml │ │
1095
- │ │ (Python) │ │ │ │
1096
- │ ╰─────────────╯ │ • Pattern matching with regex │ │
1097
- │ │ • Requirement categorization │ │
1098
- │ │ • Semantic meaning extraction │ │
1099
- │ │ • Unmapped error detection │ │
1100
- │ ╰─────────────┬───────────────────────╯ │
1101
- │ │ │
1102
- │ ╭────────────────────────────────▼────────────────────────╮ │
1103
- │ │ SvgcheckParser │ │
1104
- │ │ │ │
1105
- │ │ • Applies YAML mapping during parsing │ │
1106
- │ │ • Categorizes errors by requirement │ │
1107
- │ │ • Marks unmapped errors for RED display │ │
1108
- │ │ • Creates properly structured ConformanceReport │ │
1109
- │ ╰─────────────────────────┬───────────────────────────────╯ │
1110
- │ │ │
1111
- │ ▼ │
1112
- │ ╭─────────────────────────────────────────────────────────╮ │
1113
- │ │ Parallel Processing │ │
1114
- │ │ │ │
1115
- │ │ ╭─────────────────────╮ ╭─────────────────────────╮ │ │
1116
- │ │ │ SvgConform │ │ svgcheck │ │ │
1117
- │ │ │ Validation │ │ ConformanceReport │ │ │
1118
- │ │ │ │ │ (mapped) │ │ │
1119
- │ │ │ • Native Ruby │ │ • Parsed from YAML │ │ │
1120
- │ │ │ • Direct profile │ │ • Requirement-mapped │ │ │
1121
- │ │ │ • ConformanceReport │ │ • Compatible structure │ │ │
1122
- │ │ ╰─────────────────────╯ ╰─────────────────────────╯ │ │
1123
- │ ╰─────────────┬───────────────────────┬───────────────────╯ │
1124
- │ │ │ │
1125
- │ └───────────┬───────────┘ │
1126
- │ │ │
1127
- │ ╭─────────────────────────▼─────────────────────────╮ │
1128
- │ │ ReportComparator │ │
1129
- │ │ │ │
1130
- │ │ • Direct ConformanceReport comparison │ │
1131
- │ │ • Unified requirement-based display │ │
1132
- │ │ • Side-by-side error mapping │ │
1133
- │ │ • 🚨 RED highlighting for unmapped errors │ │
1134
- │ │ • Compatibility metrics and analysis │ │
1135
- │ ╰───────────────────────────────────────────────────╯ │
1136
- │ │
1137
- ╰────────────────────────────────────────────────────────────────╯
1138
- ----
1139
-
1140
-
1141
- === svgcheck compatibility commands
1142
-
1143
- ==== General
1144
-
1145
- In order to run the compatibility commands, you need to have the `svgcheck` tool
1146
- installed and accessible in your PATH.
1147
-
1148
- NOTE: The `svgcheck` tool can be installed via `pip install svgcheck`.
1149
-
1150
- The commands in this section provide functionality to generate svgcheck outputs
1151
- for test files and perform compatibility analysis between SvgConform and svgcheck
1152
- results.
1153
-
1154
- The test files from svgcheck are included in the SvgConform repository under
1155
- `spec/fixtures/svgcheck` to ensure consistent testing.
1156
-
1157
- The mapping configuration file `config/svgcheck_mapping.yml` defines how
1158
- svgcheck error messages are interpreted and mapped to SvgConform requirements.
1159
-
1160
- The data flow steps for compatibility analysis is as follows:
1161
-
1162
- . svgcheck outputs are generated for test files using the `svgcheck generate` command.
1163
-
1164
- . For each test file, svgcheck outputs are generated in both check-only and
1165
- repair modes through the `svgcheck generate` command, and are then parsed by the
1166
- `Svgcheck::Parser` class into the `ReportGenerator` class.
1167
-
1168
- . SvgConform validates the same test files using the SVG 1.2 RFC profile, which provides
1169
- a `ConformanceReport` object.
1170
-
1171
- . The `ReportComparator` class compares the `ConformanceReport` from SvgConform
1172
- with the svgcheck `ReportGenerator` results. The `ReportComparator` handles
1173
- both check-only and repair mode outputs, and maps svgcheck messages to SvgConform
1174
- requirements and remediations outcomes.
1175
-
1176
- . A detailed comparison report is generated, highlighting matches and discrepancies.
1177
-
1178
-
1179
-
1180
- ==== `svg_conform svgcheck compatibility`
1181
-
1182
- The `svgcheck compatibility` command performs a comprehensive compatibility analysis
1183
- between SvgConform validation results and the IETF `svgcheck` tool output.
575
+ profile = SvgConform::Profiles.get(:metanorma)
576
+ document = SvgConform::Document.from_file('input.svg')
1184
577
 
1185
- [source,bash]
1186
- ----
1187
- svg_conform svgcheck compatibility [OPTIONS] [FILE]
578
+ # Apply all remediations defined in the profile
579
+ changes = profile.apply_remediations(document)
1188
580
 
1189
- Options:
1190
- -p, --profile PROFILE Profile to use (default: svg_1_2_rfc)
1191
- -f, --file FILE Analyze specific file instead of all test files
1192
- -o, --output FILE Output clean report to file (no color codes)
1193
- -v, --verbose Verbose output
1194
- ----
581
+ puts "Applied #{changes.length} remediations"
1195
582
 
1196
- [example]
1197
- ====
1198
- [source,bash]
583
+ # Save the remediated SVG
584
+ File.write('output.svg', document.to_xml)
1199
585
  ----
1200
- # Run comprehensive compatibility analysis
1201
- svg_conform svgcheck compatibility
1202
586
 
1203
- # Analyze specific file
1204
- svg_conform svgcheck compatibility --file example.svg
587
+ ==== Using the remediation runner
1205
588
 
1206
- # Generate clean report for documentation
1207
- svg_conform svgcheck compatibility --output compatibility-report.md
589
+ For more control over the remediation process:
1208
590
 
1209
- # Analyze specific file and save to file
1210
- svg_conform svgcheck compatibility --file example.svg --output analysis.md
591
+ [source,ruby]
1211
592
  ----
1212
- ====
593
+ profile = SvgConform::Profiles.get(:metanorma)
594
+ runner = SvgConform::RemediationRunner.new(profile: profile)
1213
595
 
596
+ # Run remediation on a file
597
+ result = runner.run_remediation_file('input.svg')
1214
598
 
1215
- ==== `svg_conform svgcheck generate`
599
+ if result.success?
600
+ File.write('output.svg', result.remediated_content)
601
+ puts "Fixed #{result.issues_fixed} issues"
602
+ puts "Final validation: #{result.final_validation.valid?}"
603
+ else
604
+ puts "Remediation failed: #{result.error.message}"
605
+ end
606
+ ----
1216
607
 
1217
- The `svgcheck generate` command generates svgcheck outputs for test files to
1218
- facilitate compatibility analysis.
608
+ ==== Checking available remediations
1219
609
 
1220
- These files are generated in a structured output directory, with separate subdirectories
1221
- for check-only and repair modes.
610
+ [source,ruby]
611
+ ----
612
+ profile = SvgConform::Profiles.get(:metanorma)
1222
613
 
614
+ puts "Profile has #{profile.remediation_count} remediations available"
1223
615
 
1224
- [source,bash]
616
+ profile.remediations.each do |remediation|
617
+ puts "- #{remediation.class.name}"
618
+ end
1225
619
  ----
1226
- Usage:
1227
- svg_conform svgcheck generate SVGCHECK_REPO_PATH
1228
-
1229
- Options:
1230
- -m, [--mode=MODE] # Generation mode: check, repair, or both
1231
- # Default: both
1232
- # Possible values: check, repair, both
1233
- [--svgcheck-exec=SVGCHECK_EXEC] # Path to svgcheck executable
1234
- [--fixtures-path=FIXTURES_PATH] # Output directory (default: spec/fixtures/svgcheck)
1235
- -f, [--single-file=SINGLE_FILE] # Process single file only
1236
- [--force] # Overwrite existing outputs
1237
- # Default: false
1238
- -v, [--verbose], [--no-verbose], [--skip-verbose] # Verbose output
1239
- # Default: false
1240
620
 
1241
- Description:
1242
- Generate svgcheck outputs for test files by running svgcheck on them.
621
+ === Working with documents
1243
622
 
1244
- SVGCHECK_REPO_PATH: Path to the svgcheck repository (e.g., svgcheck-reference)
623
+ ==== Creating documents
1245
624
 
1246
- By default, processes all test files in SVGCHECK_REPO_PATH/svgcheck/Tests/ and generates BOTH check and repair
1247
- outputs in separate subdirectories.
625
+ From a string:
1248
626
 
1249
- Examples: svg_conform svgcheck generate svgcheck-reference svg_conform svgcheck generate svgcheck-reference --mode
1250
- check svg_conform svgcheck generate svgcheck-reference --single-file example.svg
627
+ [source,ruby]
628
+ ----
629
+ document = SvgConform::Document.new(svg_string)
1251
630
  ----
1252
631
 
1253
- This command provides a bridge between SvgConform and the Python svgcheck tool,
1254
- enabling comprehensive compatibility testing and analysis. By default, it
1255
- generates both check and repair outputs in separate subdirectories.
1256
-
1257
- The command creates a structured output directory with separate subdirectories
1258
- for different svgcheck modes:
632
+ From a file:
1259
633
 
1260
- [source]
634
+ [source,ruby]
1261
635
  ----
1262
- spec/fixtures/svgcheck/
1263
- ├── check/ # Check-only outputs (validation without remediation)
1264
- │ ├── file1.svg.out # Validation messages from svgcheck
1265
- │ ├── file1.svg.err # Error messages from svgcheck
1266
- │ └── file1.svg.code # Exit status from svgcheck
1267
- └── repair/ # Repair outputs (validation + remediation)
1268
- ├── file1.svg.out # Validation messages from svgcheck
1269
- ├── file1.svg.err # Error messages from svgcheck
1270
- ├── file1.svg.code # Exit status from svgcheck
1271
- └── file1.svg.file # Remediated SVG content
636
+ document = SvgConform::Document.from_file('path/to/file.svg')
1272
637
  ----
1273
638
 
1274
- Some svgcheck test files are renamed to indicate their actual type of content,
1275
- which is defined in `svgcheck_generate.rb`:
1276
-
1277
- * svgcheck `full-tiny.xml` is renamed to `full-tiny.svg`
1278
- * svgcheck `rfc-svg.xml` is renamed to `rfc-svg.svg`
1279
-
1280
- The generated outputs are used by the `compatibility` command to perform
1281
- detailed comparisons between SvgConform and svgcheck validation results. The
1282
- structured directory layout enables:
1283
-
1284
- - **Targeted analysis**: Compare check-only vs repair mode behaviors
1285
- - **Comprehensive testing**: Validate against both validation and remediation workflows
1286
- - **Regression testing**: Track changes in svgcheck behavior over time
1287
- - **Profile development**: Use svgcheck outputs as reference for profile refinement
639
+ From a DOM node (Nokogiri or Moxml):
1288
640
 
641
+ [source,ruby]
642
+ ----
643
+ nokogiri_element = Nokogiri::XML(svg_string).root
644
+ document = SvgConform::Document.from_node(nokogiri_element)
645
+ ----
1289
646
 
1290
- There are three modes of operation for generating svgcheck outputs:
647
+ ==== Document operations
1291
648
 
1292
- **Check Mode** (`--mode check`):
649
+ [source,ruby]
650
+ ----
651
+ # Access the underlying DOM
652
+ root = document.root
653
+ elements = document.find_all('//svg:rect')
1293
654
 
1294
- - Runs svgcheck without the `--repair` flag
1295
- - Only validates SVG files and reports errors
1296
- - Generates `.out`, `.err`, and `.code` files
1297
- - No remediated content is produced
655
+ # Check for specific elements
656
+ has_viewbox = document.root.attribute?('viewBox')
1298
657
 
1299
- **Repair Mode** (`--mode repair`):
658
+ # Modify the document
659
+ document.root.set_attribute('width', '500')
1300
660
 
1301
- - Runs svgcheck with the `--repair` flag
1302
- - Validates SVG files and generates remediated content
1303
- - Generates `.out`, `.err`, `.code`, and `.file` files
1304
- - The `.file` contains the remediated SVG content
661
+ # Serialize to XML
662
+ xml_string = document.to_xml
663
+ ----
1305
664
 
1306
- **Both Mode** (`--mode both`, default):
665
+ === Reference manifest
1307
666
 
1308
- - Runs both check and repair modes for each file
1309
- - Generates complete output sets in both subdirectories
1310
- - Provides comprehensive data for compatibility analysis
667
+ ==== Accessing the manifest
1311
668
 
1312
- [source,bash]
669
+ [source,ruby]
1313
670
  ----
1314
- # Generate both check and repair outputs for all test files
1315
- svg_conform svgcheck generate /path/to/svgcheck-reference
671
+ result = validator.validate(svg_content, profile: :metanorma)
672
+ manifest = result.reference_manifest
1316
673
 
1317
- # Generate only check outputs
1318
- svg_conform svgcheck generate /path/to/svgcheck-reference --mode check
1319
-
1320
- # Generate only repair outputs
1321
- svg_conform svgcheck generate /path/to/svgcheck-reference --mode repair
1322
-
1323
- # Process a single file with verbose output
1324
- svg_conform svgcheck generate /path/to/svgcheck-reference --single-file example.svg --verbose
674
+ # Get all defined IDs
675
+ manifest.available_ids.each do |id_def|
676
+ puts "ID: #{id_def.id_value}"
677
+ puts " Element: #{id_def.element_name}"
678
+ puts " Line: #{id_def.line_number}"
679
+ end
680
+ ----
1325
681
 
1326
- # Force regeneration of existing outputs
1327
- svg_conform svgcheck generate /path/to/svgcheck-reference --force
682
+ ==== Checking references
1328
683
 
1329
- # Use custom output directory
1330
- svg_conform svgcheck generate /path/to/svgcheck-reference --fixtures-path /path/to/custom/output
684
+ [source,ruby]
1331
685
  ----
686
+ # Check for unresolved internal references
687
+ if result.has_unresolved_references?
688
+ puts "Unresolved references found:"
689
+ result.unresolved_internal_references.each do |ref|
690
+ puts " #{ref.value} at line #{ref.line_number}"
691
+ end
692
+ end
1332
693
 
694
+ # Check for external references
695
+ if result.has_external_references?
696
+ puts "External references:"
697
+ result.external_references.each do |ref|
698
+ puts " #{ref.value} (#{ref.reference_type})"
699
+ end
700
+ end
701
+ ----
1333
702
 
703
+ ==== Reference types
1334
704
 
1335
- ==== `svg_conform svgcheck compare`
705
+ The manifest classifies references by type:
1336
706
 
1337
- The `svgcheck compare` command compares SvgConform validation results with existing
1338
- svgcheck reports to assess compatibility.
707
+ [source,ruby]
708
+ ----
709
+ manifest.internal_references.each do |ref|
710
+ case ref.reference_type
711
+ when 'url'
712
+ puts "URL reference: #{ref.value}"
713
+ when 'fragment'
714
+ puts "Fragment reference: #{ref.value}"
715
+ when 'fill'
716
+ puts "Fill attribute: #{ref.value}"
717
+ when 'href'
718
+ puts "Href attribute: #{ref.value}"
719
+ end
720
+ end
721
+ ----
1339
722
 
1340
- This command is useful for verifying that SvgConform produces equivalent results
1341
- to the IETF svgcheck tool.
723
+ === Advanced usage
1342
724
 
1343
- Syntax:
725
+ ==== Custom validation context
1344
726
 
1345
- [source,bash]
727
+ [source,ruby]
1346
728
  ----
1347
- svg_conform svgcheck compare FILE [OPTIONS]
729
+ context = SvgConform::ValidationContext.new(
730
+ document: document,
731
+ profile: profile
732
+ )
1348
733
 
1349
- Options:
1350
- -p, --profile PROFILE Profile to use (default: svg_1_2_rfc)
1351
- --svgcheck-report FILE Path to svgcheck report (default: auto-detect)
734
+ # Run specific requirements
735
+ requirement = SvgConform::Requirements::ViewboxRequiredRequirement.new
736
+ errors = requirement.check(context)
1352
737
  ----
1353
738
 
1354
- [example]
1355
- ====
1356
- [source,bash]
1357
- ----
1358
- # Compare with auto-detected svgcheck report
1359
- $ svg_conform svgcheck compare diagram.svg -p svg_1_2_rfc
739
+ ==== Batch processing
1360
740
 
1361
- # Specify svgcheck report explicitly
1362
- $ svg_conform svgcheck compare diagram.svg --svgcheck-report diagram.svg.svgcheck.yaml
741
+ [source,ruby]
1363
742
  ----
1364
- ====
1365
-
743
+ validator = SvgConform::Validator.new
744
+ results = {}
1366
745
 
746
+ Dir.glob('images/**/*.svg').each do |file|
747
+ result = validator.validate_file(file, profile: :metanorma)
748
+ results[file] = result
749
+ end
1367
750
 
1368
- == Performance
751
+ # Summary
752
+ valid_count = results.count { |_, r| r.valid? }
753
+ puts "#{valid_count}/#{results.size} files are valid"
754
+ ----
1369
755
 
1370
- === SAX streaming validation
756
+ ==== Report generation
1371
757
 
1372
- SvgConform implements SAX (Simple API for XML) streaming validation for
1373
- high-performance processing of large SVG files.
758
+ [source,ruby]
759
+ ----
760
+ # Create a conformance report
761
+ report = SvgConform::ConformanceReport.from_svg_conform_result(
762
+ "file.svg",
763
+ result,
764
+ profile: :metanorma
765
+ )
1374
766
 
1375
- Performance characteristics:
767
+ # Export as JSON
768
+ json_output = report.to_json
769
+ File.write('report.json', json_output)
1376
770
 
1377
- * Small files (<1 MB): ~0.5s validation time
1378
- * Medium files (1-5 MB): ~1s validation time (vs 60-80s with DOM)
1379
- * Large files (>5 MB): ~2s validation time (vs minutes-hours with DOM)
771
+ # Export as YAML
772
+ yaml_output = report.to_yaml
773
+ File.write('report.yaml', yaml_output)
774
+ ----
1380
775
 
1381
- Real-world samples results:
776
+ === API classes
1382
777
 
1383
- * 5.93 MB file: >` 60s → 1.89s (30x faster)
1384
- * 4.57 MB file: >60s → 1.37s (40x faster)
1385
- * 3.44 MB file: >60s → 0.29s (200x faster)
778
+ ==== Core classes
1386
779
 
1387
- How it works:
780
+ * `SvgConform::Validator` - Main validation interface
781
+ * `SvgConform::Profile` - Profile definition and management
782
+ * `SvgConform::Document` - SVG document wrapper
783
+ * `SvgConform::ValidationResult` - Validation result container
784
+ * `SvgConform::RemediationRunner` - Remediation execution
1388
785
 
1389
- SAX streaming validation processes XML events without building a full DOM tree
1390
- in memory. This provides:
786
+ ==== Requirement classes
1391
787
 
1392
- * Forward-only processing: Single pass through XML stream
1393
- * Constant memory: No full DOM tree in memory
1394
- * Predictable performance: O(n) complexity guaranteed
1395
- * No object identity issues: Path-based node identification
788
+ Located in `SvgConform::Requirements`:
1396
789
 
1397
- Mode selection:
790
+ * `AllowedElementsRequirement` - Element whitelist validation
791
+ * `ColorRestrictionsRequirement` - Color format restrictions
792
+ * `FontFamilyRequirement` - Font family restrictions
793
+ * `ForbiddenContentRequirement` - Forbidden element/attribute check
794
+ * `IdReferenceRequirement` - ID reference validation
795
+ * `InvalidIdReferencesRequirement` - Invalid reference detection
796
+ * `LinkValidationRequirement` - Link validation
797
+ * `NamespaceRequirement` - Namespace validation
798
+ * `NamespaceAttributesRequirement` - Namespace attribute check
799
+ * `NoExternalCssRequirement` - External CSS prohibition
800
+ * `NoExternalFontsRequirement` - External font prohibition
801
+ * `NoExternalImagesRequirement` - External image prohibition
802
+ * `StylePromotionRequirement` - Presentation attribute check
803
+ * `StyleRequirement` - Style attribute validation
804
+ * `ViewboxRequiredRequirement` - ViewBox requirement
1398
805
 
1399
- By default, SAX mode is used for all validation operations. DOM mode is
1400
- automatically used when remediation is requested (`fix: true`).
806
+ ==== Remediation classes
1401
807
 
1402
- [source,ruby]
1403
- ----
1404
- # Default: SAX mode (best performance)
1405
- validator = SvgConform::Validator.new
1406
- result = validator.validate_file('large.svg', profile: :metanorma)
808
+ Located in `SvgConform::Remediations`:
1407
809
 
1408
- # Explicit mode selection
1409
- validator_sax = SvgConform::Validator.new(mode: :sax) # Force SAX
1410
- validator_dom = SvgConform::Validator.new(mode: :dom) # Force DOM
1411
- validator_auto = SvgConform::Validator.new(mode: :auto) # File size based (>1MB uses SAX)
1412
- ----
810
+ * `ColorRemediation` - Fix color format issues
811
+ * `FontRemediation` - Fix font family issues
812
+ * `FontEmbeddingRemediation` - Embed external fonts
813
+ * `ImageEmbeddingRemediation` - Embed external images
814
+ * `InvalidIdReferencesRemediation` - Fix invalid references
815
+ * `NamespaceRemediation` - Fix namespace issues
816
+ * `NamespaceAttributeRemediation` - Remove namespace attributes
817
+ * `NoExternalCssRemediation` - Convert external CSS
818
+ * `StylePromotionRemediation` - Promote presentation attributes
819
+ * `ViewboxRemediation` - Add missing ViewBox
1413
820
 
1414
- Validation parity:
821
+ === Complete reference
1415
822
 
1416
- SAX mode produces identical validation results to DOM mode on 18/19 test files
1417
- (94.7% parity). The one exception is `full-tiny.svg`, a comprehensive test file
1418
- with known architectural differences.
823
+ See link:docs/api_reference.adoc[API Reference] for comprehensive documentation including:
1419
824
 
825
+ * Complete class hierarchy
826
+ * Detailed method signatures
827
+ * Parameter descriptions
828
+ * Return value specifications
829
+ * Integration patterns
830
+ * Advanced examples
1420
831
 
1421
832
 
1422
- == Testing
833
+ [[external_compliance]]
834
+ == External compliance
1423
835
 
1424
- Run the test suite:
836
+ SvgConform provides compatibility with existing SVG validation tools:
1425
837
 
1426
- [source,bash]
1427
- ----
1428
- bundle exec rspec
1429
- ----
838
+ * **SVGCheck**: 100% error report matching with Python svgcheck tool
839
+ * Profile compatibility modes for different validation tools
1430
840
 
1431
- Run specific test categories:
841
+ See link:docs/compatibility.adoc[Compatibility Documentation] for details.
1432
842
 
1433
- [source,bash]
1434
- ----
1435
- # Unit tests
1436
- bundle exec rspec spec/unit/
1437
843
 
1438
- # Integration tests
1439
- bundle exec rspec spec/integration/
844
+ == Development
1440
845
 
1441
- # SVGCheck compatibility tests
1442
- bundle exec rspec spec/svgcheck_compatibility_spec.rb
1443
- ----
846
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests.
1444
847
 
848
+ To install this gem onto your local machine, run `bundle exec rake install`.
1445
849
 
1446
- == Changelog
1447
850
 
1448
- See link:CHANGELOG.md[CHANGELOG.md] for version history and changes.
851
+ == Contributing
1449
852
 
853
+ Bug reports and pull requests are welcome on GitHub at https://github.com/metanorma/svg_conform.
1450
854
 
1451
- == Copyright and license
1452
855
 
1453
- Copyright Ribose.
856
+ == License
1454
857
 
1455
- This gem is available as open source under the terms of the Ribose 2-clause BSD
1456
- license.
858
+ The gem is available as open source under the terms of the BSD 2-Clause License.