Gem Version License

Purpose

XSDVI (XML Schema Definition Visualizer) is a Ruby gem that transforms W3C XML Schema (XSD) files into interactive, hierarchical SVG diagrams. It provides a visual representation of complex XML Schema structures, making it easier to understand schema relationships, element hierarchies, attribute requirements, and data type definitions.

The tool parses XSD files and generates SVG diagrams that display:

  • Element structures with their types, cardinality, and attributes

  • Compositor relationships (sequence, choice, all)

  • Type hierarchies and inheritance

  • Identity constraints (key, keyref, unique)

  • Namespace information

  • Documentation annotations from the schema

  • Recursive references with loop detection

This is a pure Ruby port of the original Java XsdVi tool, providing the same functionality with modern Ruby idioms and gemification for easy integration into Ruby projects.

Features

XSD component visualization

  • Elements and Attributes: Visual boxes showing element names, types, cardinality (min..max occurrences), required/optional status, and namespace information

  • Compositors: Graphical representation of sequence (ordered), choice (alternatives), and all (unordered) element groups

  • Wildcards: Display of <any> and <anyAttribute> with namespace constraints and processing modes

  • Identity Constraints: Visualization of key, keyref, unique constraints with their selectors and fields

  • Type Information: Display of simple and complex type definitions, base types, and anonymous types

Interactive SVG output

  • Hierarchical Layout: Tree-structure visualization with proper indentation and connections

  • Collapsible/Expandable: JavaScript-enabled expand/collapse functionality for complex schemas (optional)

  • Clickable Elements: Navigate between related schema components

  • Documentation Display: Inline display of <xs:documentation> annotations

  • Color-coded Symbols: Different visual styles for elements, attributes, compositors, and constraints

Flexible output options

  • Single Diagram: Generate one SVG showing the entire schema or a specific root element

  • Per-Element Diagrams: Generate separate SVG files for each top-level element

  • Custom Styling: Embed CSS in SVG files or use external stylesheets

  • Output Directory: Organize generated diagrams in custom folder structures

Processing capabilities

  • Multiple XSD Files: Process multiple schema files in a single run

  • Loop Detection: Automatically detects and marks recursive element references

  • Namespace Handling: Properly displays and distinguishes multiple namespaces

  • Documentation Extraction: Extracts and formats XSD documentation for display

  • Large Schema Support: Handles complex, real-world schemas with hundreds of elements

  • Type Resolution: Comprehensive resolution of named types, group references, attribute groups, element references, and type inheritance (extension/restriction)

Installation

Add this line to your application’s Gemfile:

gem 'xsdvi'

And then execute:

bundle install

Or install it yourself as:

gem install xsdvi

Usage

Basic usage

Generate an SVG diagram from an XSD file:

xsdvi generate schema.xsd

This creates schema.svg in the current directory, showing all top-level elements and their hierarchical structure.

Generate diagram for specific root element

xsdvi generate schema.xsd -r UnitsML

This generates a diagram starting from the UnitsML element, showing its complete structure and all nested elements.

Generate separate SVG for each element

xsdvi generate schema.xsd -r all -o -p output/diagrams

This creates individual SVG files for each top-level element in the output/diagrams directory.

Command-line options

-r, --root-node-name NAME

Specify the schema root element name to visualize. Use "all" to generate diagrams for all top-level elements. If omitted, generates a complete schema diagram showing all elements.

-o, --one-node-only

Generate diagram showing only the specified element without its children (single-level view). Automatically enabled when using -r all. This mode hides the expand/collapse control buttons.

-p, --output-path PATH

Specify output directory for generated SVG files. The tool automatically creates the directory if it doesn’t exist. If omitted, files are created in the current directory.

--embody-style

Embed CSS styling directly in each SVG file (default: true). This creates self-contained SVG files that display correctly without external dependencies.

--generate-style FILE

Generate an external CSS file with the specified name and reference it from SVG files. Useful when generating multiple diagrams that should share styling.

--use-style URL

Reference an existing external CSS file at the specified URL in generated SVG files. The CSS file must be accessible when the SVG is viewed.

Examples

Example 1. Generate full schema diagram with root element
xsdvi generate UnitsML-v1.0.xsd -r UnitsML

Creates UnitsML.svg showing the complete structure starting from the UnitsML root element, including all nested elements, attributes, and constraints.

Example 2. Generate diagram for single element only
xsdvi generate UnitsML-v1.0.xsd -r Quantity -o

Creates Quantity.svg showing only the Quantity element definition without expanding its children, useful for focused documentation.

Example 3. Generate separate diagrams for all top-level elements
xsdvi generate UnitsML-v1.0.xsd -r all -o -p images/SVG

Creates individual SVG files (Quantity.svg, Unit.svg, etc.) in the images/SVG directory, one for each top-level element in the schema.

Example 4. Generate diagram using external CSS
xsdvi generate schema.xsd --generate-style custom.css -p output

Creates output/schema.svg and output/custom.css, with the SVG referencing the external stylesheet. Useful for customizing diagram appearance.

Comparing Java and Ruby outputs

The compare command generates side-by-side visual comparisons of Java XsdVi v1.3 and Ruby XsdVi outputs. This is useful for validation, documentation, and visual quality assurance.

Basic comparison

xsdvi compare schema.xsd

This command:

  1. Automatically downloads Java XsdVi JAR v1.3 (first run only, cached in ~/.xsdvi/)

  2. Generates SVGs using both Java and Ruby implementations

  3. Extracts metadata and symbol counts from both outputs

  4. Creates an interactive HTML comparison page in comparisons/<schema>-<timestamp>/

Comparison command options

-r, --root-node-name NAME

Specify the schema root element to visualize (same as generate command). Use "all" to generate comparisons for all top-level elements.

-o, --output-path PATH

Specify output directory for comparison files. Default: comparisons/<schema>-<timestamp>/

--skip-java

Skip Java generation and use existing Java outputs. Useful when re-running comparison with updated Ruby code.

--skip-ruby

Skip Ruby generation and use existing Ruby outputs. Useful for comparing against manually generated Ruby outputs.

-O, --open

Automatically open the comparison HTML in your default browser after generation.

Comparison examples

Example 5. Basic comparison
xsdvi compare UnitsML-v1.0.xsd -r UnitsML

Downloads Java XsdVi (if needed), generates SVGs with both implementations, and creates an interactive comparison showing:

  • Side-by-side SVG iframes

  • Statistics table comparing file sizes and symbol counts

  • Generation time for each implementation

  • Visual diff highlighting any differences

Example 6. Compare all elements with auto-open
xsdvi compare schema.xsd -r all -O

Generates comparison for all top-level elements and automatically opens the comparison page in your browser. The HTML includes an element selector dropdown to switch between different element diagrams.

Example 7. Compare using existing Java output
xsdvi compare schema.xsd --skip-java -o my-comparison

Reuses existing Java output and generates fresh Ruby output, useful during Ruby development to quickly validate changes without regenerating Java outputs.

Comparison output structure

After running a comparison, you get:

comparisons/<schema>-<timestamp>/
├── java/
│   └── <schema>.svg         # Java XsdVi output
├── ruby/
│   └── <schema>.svg         # Ruby XsdVi output
└── comparison.html          # Interactive comparison page

The comparison HTML displays:

  • Statistics table: File counts, sizes, symbol counts by type, generation times

  • Visual indicators: Green checkmarks for matches, red X for mismatches

  • Split-screen view: Java output (left) and Ruby output (right) in synchronized iframes

  • Element selector: Dropdown to switch between elements (when using -r all)

Architecture

Core components

TreeElement and TreeBuilder

Manage the tree structure representing the XSD schema hierarchy. TreeElement provides parent-child relationships, traversal methods, and unique node identification.

XsdHandler

Parses XSD files using Nokogiri and builds the symbol tree structure. Handles all XSD constructs including elements, attributes, compositors, wildcards, and identity constraints. Performs loop detection for recursive schemas.

Symbol classes

14 specialized symbol types representing different XSD constructs:

  • Element, Attribute - schema components

  • Choice, Sequence, All - compositors

  • Any, AnyAttribute - wildcards

  • Key, Keyref, Unique - identity constraints

  • Selector, Field - constraint components

  • Loop - recursive reference indicator

  • Schema - root container

SVG::Generator

Generates SVG output files from the symbol tree. Manages layout, styling, resource loading, and recursive symbol drawing. Produces interactive diagrams with JavaScript-enabled expand/collapse functionality.

CLI

Thor-based command-line interface providing easy access to all generation options with built-in help and validation.

Data flow

XSD File → XsdHandler (Nokogiri parsing)
              ↓
         Type Registry Collection (complexTypes, simpleTypes, groups, etc.)
              ↓
         Symbol Tree Building (TreeBuilder with on-demand type resolution)
              ↓
  Symbol Processing (prepare_box, calculate dimensions)
              ↓
      SVG Generation (recursive drawing)
              ↓
         SVG File Output

Type resolution architecture

The type resolution system is the core feature that enables XSDVI to correctly process all XSD schema structures. It resolves references to named types, groups, and elements, and handles type inheritance patterns.

Resolution mechanisms

The system implements six resolution mechanisms:

Type Registry System

All named type and group definitions are collected during schema parsing into hash-based registries for O(1) lookup performance:

  • Complex types (<xs:complexType name="…​">)

  • Simple types (<xs:simpleType name="…​">)

  • Groups (<xs:group name="…​">)

  • Attribute groups (<xs:attributeGroup name="…​">)

  • Global elements (<xs:element name="…​">)

Named Type Resolution

Resolves type references in element declarations:

<xs:element name="Foo" type="BarType"/>

The system:

  1. Strips namespace prefixes from type names

  2. Checks if the type is a W3C builtin (string, boolean, decimal, etc.)

  3. Looks up custom types in the complex/simple type registries

  4. Processes the resolved type definition inline

Group Reference Resolution

Resolves group references in compositors:

<xs:sequence>
  <xs:group ref="CommonElements"/>
</xs:sequence>

The referenced group’s contents are expanded inline, maintaining proper tree hierarchy.

Attribute Group Reference Resolution

Resolves attribute group references:

<xs:complexType>
  <xs:attributeGroup ref="CommonAttributes"/>
</xs:complexType>

Supports nested attribute group references (recursive resolution).

Element Reference Resolution

Resolves element references with proper cardinality:

<xs:element ref="CommonElement" minOccurs="0" maxOccurs="unbounded"/>

The system preserves cardinality constraints while resolving to the element definition.

Extension and Restriction Processing

Handles type inheritance via complexContent and simpleContent:

<xs:complexType name="ExtendedType">
  <xs:complexContent>
    <xs:extension base="BaseType">
      <xs:sequence>
        <!-- Additional elements -->
      </xs:sequence>
    </xs:extension>
  </xs:complexContent>
</xs:complexType>

The system:

  1. Resolves the base type from registries

  2. Processes base type structure first (inherited elements/attributes)

  3. Processes extension-specific additions

  4. Maintains single inheritance hierarchy

Performance characteristics

  • Registry collection: O(n) where n = total XSD nodes

  • Type lookup: O(1) hash access

  • Recursive resolution: Bounded by schema depth

  • Loop detection prevents infinite recursion

  • On-demand resolution (lazy evaluation)

This architecture enables XSDVI to correctly process 100% of XSD schema structures, matching the Java version’s capabilities.

Differences from Java version

Text wrapping

The Ruby implementation uses a custom text wrapping algorithm that produces slightly different line breaks compared to Apache Commons Text WordUtils.wrap(). The Ruby version optimizes for keeping related content together when it fits within the line width, while maintaining valid XML structure.

Impact: Documentation text may wrap at different character positions, but the visual output and functionality remain identical. The Ruby version ensures HTML tags and entities in documentation are not broken across lines, improving SVG validity.

Example:

Java may break HTML tags mid-structure:

<text>See &lt;a</text>
<text>href="...">text&lt;/a>.</text>

Ruby keeps tags together for better validity:

<text>See &lt;a href="...">text&lt;/a>.</text>

Both outputs are functionally equivalent and render correctly in SVG viewers. The Ruby approach actually produces more semantically correct output by preserving the integrity of embedded HTML elements.

Development

After checking out the repo, run bundle install to install dependencies.

Run tests:

bundle exec rspec

Run rubocop:

bundle exec rubocop

Testing

Test suite overview

The XSDVI Ruby test suite provides comprehensive validation of all functionality with 46 tests across two categories:

  • Integration tests (14 tests): Validate complete end-to-end processing and compare outputs with Java version

  • Type resolution tests (32 tests): Validate all 7 type resolution mechanisms

Running tests

Run all tests

bundle exec rspec

Run specific test file

# Type resolution tests only
bundle exec rspec spec/xsdvi/type_resolution_spec.rb

# Output comparison tests only
bundle exec rspec spec/xsdvi/output_comparison_spec.rb

Run with documentation format

bundle exec rspec --format documentation

Run specific test group

bundle exec rspec spec/xsdvi/type_resolution_spec.rb -e "Named Type Resolution"

Type resolution test coverage

The type resolution test suite validates that XSDVI Ruby correctly processes all XSD schema constructs:

7 Resolution Mechanisms Tested:

  1. Named Type Resolution - Complex and simple type references

  2. Group Reference Resolution - Model group (<xs:group ref="…​">) expansion

  3. Attribute Group Reference Resolution - Attribute group references including nested

  4. Element Reference Resolution - Global element references with cardinality

  5. Extension/Restriction Resolution - Type inheritance via complexContent/simpleContent

  6. Identity Constraint Resolution - Key, keyref, unique, selector, field

  7. Circular Reference Resolution - Self-referencing and mutual circular references

Test Fixtures:

The test suite uses 7 XSD fixture files in spec/fixtures/type_resolution/:

  • named_types.xsd - Type reference resolution

  • group_refs.xsd - Group reference expansion

  • attribute_groups.xsd - Attribute group references

  • element_refs.xsd - Element references with cardinality

  • inheritance.xsd - Extension and restriction

  • identity_constraints.xsd - Key/keyref/unique constraints

  • circular.xsd - Circular reference handling

For detailed test documentation, see spec/xsdvi/TYPE_RESOLUTION_TESTING.md.

Generating comparison files

To validate that XSDVI Ruby produces output identical to the Java version:

Generate Ruby output for UnitsML schema

xsdvi generate spec/fixtures/UnitsML-v1.0-csd04.xsd -r UnitsML \
  -p spec/fixtures/ruby

Generate Ruby output for all elements

xsdvi generate spec/fixtures/UnitsML-v1.0-csd04.xsd -r all -o \
  -p spec/fixtures/ruby/all

Generate Ruby output for TestXMLEntities

xsdvi generate spec/fixtures/TestXMLEntities.xsd \
  -p spec/fixtures/ruby

Compare with Java version

The test suite automatically compares Ruby outputs with Java reference outputs in spec/fixtures/java/. The comparison normalizes known differences (text wrapping) and validates structural equivalence:

bundle exec rspec spec/xsdvi/output_comparison_spec.rb

Manual comparison

You can manually compare outputs using diff tools:

# Compare UnitsML outputs
diff spec/fixtures/java/UnitsML-v1.0-csd04.svg \
     spec/fixtures/ruby/UnitsML-v1.0-csd04.svg

# Compare specific element
diff spec/fixtures/java/all/Quantity.svg \
     spec/fixtures/ruby/all/Quantity.svg

Note: Direct diff will show text wrapping differences. Use the RSpec comparison tests for structural validation.

Generating fresh Java comparison files

If you need to regenerate Java version outputs (requires Java XsdVi):

# Assuming Java xsdvi.jar is available
java -jar xsdvi.jar --in spec/fixtures/UnitsML-v1.0-csd04.xsd \
     --root UnitsML --out spec/fixtures/java/UnitsML-v1.0-csd04.svg

# For all elements
java -jar xsdvi.jar --in spec/fixtures/UnitsML-v1.0-csd04.xsd \
     --root all --one-node-only --out spec/fixtures/java/all

Test validation approach

The test suite uses Canon gem for XML-aware comparison that:

  • Normalizes whitespace differences

  • Handles attribute ordering variations

  • Validates structural equivalence

  • Ignores text wrapping differences in data-desc-* attributes

  • Focuses on semantic correctness rather than byte-identical output

This ensures that XSDVI Ruby produces functionally identical diagrams to the Java version while allowing minor presentational differences.

Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/metanorma/xsdvi-ruby

Copyright Ribose Inc.

The gem is available as open source under the Ribose 3-Clause BSD License.

Acknowledgments

This is a Ruby port of the Metanorma version of the XsdVi tool, which is itself a fork of the original XsdVi Java tool created by Václav Slavìtínský. See the original project at https://sourceforge.net/projects/xsdvi/

The Ruby port maintains compatibility with the Java version’s output format while providing a pure Ruby implementation suitable for modern Ruby applications and workflows.