From 45c3a9331572018147da57ac6f82b7f60b00edb6 Mon Sep 17 00:00:00 2001 From: Suleman Uzair <96812483+suleman-uzair@users.noreply.github.com> Date: Wed, 20 Nov 2024 18:46:13 +0500 Subject: [PATCH] XSD parser using LutaML-Model (#2) * XSD parsing LutaML-Model classes * chore: removed zeitwerk default logger * Added round-trip xml specs, classes, and attributes * fix: failing specs * chore: updated dir path string * chore: changed matcher gem and moved adapter from method to base file --------- Co-authored-by: suleman-uzair --- .rubocop.yml | 3 + Gemfile | 6 + lib/lutaml/xsd.rb | 16 +- lib/lutaml/xsd/annotation.rb | 16 + lib/lutaml/xsd/any.rb | 18 + lib/lutaml/xsd/attribute.rb | 26 + lib/lutaml/xsd/attribute_group.rb | 22 + lib/lutaml/xsd/choice.rb | 28 + lib/lutaml/xsd/complex_content.rb | 16 + lib/lutaml/xsd/complex_type.rb | 34 + lib/lutaml/xsd/documentation.rb | 16 + lib/lutaml/xsd/element.rb | 34 + lib/lutaml/xsd/enumeration.rb | 18 + lib/lutaml/xsd/extension.rb | 24 + lib/lutaml/xsd/field.rb | 16 + lib/lutaml/xsd/group.rb | 31 + lib/lutaml/xsd/import.rb | 18 + lib/lutaml/xsd/include.rb | 16 + lib/lutaml/xsd/key.rb | 20 + lib/lutaml/xsd/max_inclusive.rb | 16 + lib/lutaml/xsd/max_length.rb | 16 + lib/lutaml/xsd/min_inclusive.rb | 16 + lib/lutaml/xsd/pattern.rb | 18 + lib/lutaml/xsd/restriction.rb | 29 + lib/lutaml/xsd/schema.rb | 38 + lib/lutaml/xsd/selector.rb | 16 + lib/lutaml/xsd/sequence.rb | 22 + lib/lutaml/xsd/simple_content.rb | 18 + lib/lutaml/xsd/simple_type.rb | 24 + lib/lutaml/xsd/union.rb | 18 + lib/lutaml/xsd/unique.rb | 20 + lib/lutaml/xsd/white_space.rb | 16 + lib/lutaml/xsd/xsd.rb | 13 + lutaml-xsd.gemspec | 3 + .../fixtures/metaschema-markup-multiline.xsd | 135 ++ .../fixtures/metaschema-meta-constraints.xsd | 43 + .../lutaml/fixtures/metaschema-prose-base.xsd | 82 + .../fixtures/metaschema-prose-module.xsd | 5 + spec/lutaml/fixtures/metaschema.xsd | 1344 +++++++++++++++ .../fixtures/metaschema_markup_line.xsd | 9 + .../fixtures/nist_metaschema_datatypes.xsd | 263 +++ spec/lutaml/fixtures/omml_schema.xsd | 1528 +++++++++++++++++ spec/lutaml/xsd_spec.rb | 28 +- spec/spec_helper.rb | 7 + 44 files changed, 4096 insertions(+), 9 deletions(-) create mode 100644 lib/lutaml/xsd/annotation.rb create mode 100644 lib/lutaml/xsd/any.rb create mode 100644 lib/lutaml/xsd/attribute.rb create mode 100644 lib/lutaml/xsd/attribute_group.rb create mode 100644 lib/lutaml/xsd/choice.rb create mode 100644 lib/lutaml/xsd/complex_content.rb create mode 100644 lib/lutaml/xsd/complex_type.rb create mode 100644 lib/lutaml/xsd/documentation.rb create mode 100644 lib/lutaml/xsd/element.rb create mode 100644 lib/lutaml/xsd/enumeration.rb create mode 100644 lib/lutaml/xsd/extension.rb create mode 100644 lib/lutaml/xsd/field.rb create mode 100644 lib/lutaml/xsd/group.rb create mode 100644 lib/lutaml/xsd/import.rb create mode 100644 lib/lutaml/xsd/include.rb create mode 100644 lib/lutaml/xsd/key.rb create mode 100644 lib/lutaml/xsd/max_inclusive.rb create mode 100644 lib/lutaml/xsd/max_length.rb create mode 100644 lib/lutaml/xsd/min_inclusive.rb create mode 100644 lib/lutaml/xsd/pattern.rb create mode 100644 lib/lutaml/xsd/restriction.rb create mode 100644 lib/lutaml/xsd/schema.rb create mode 100644 lib/lutaml/xsd/selector.rb create mode 100644 lib/lutaml/xsd/sequence.rb create mode 100644 lib/lutaml/xsd/simple_content.rb create mode 100644 lib/lutaml/xsd/simple_type.rb create mode 100644 lib/lutaml/xsd/union.rb create mode 100644 lib/lutaml/xsd/unique.rb create mode 100644 lib/lutaml/xsd/white_space.rb create mode 100644 lib/lutaml/xsd/xsd.rb create mode 100644 spec/lutaml/fixtures/metaschema-markup-multiline.xsd create mode 100644 spec/lutaml/fixtures/metaschema-meta-constraints.xsd create mode 100644 spec/lutaml/fixtures/metaschema-prose-base.xsd create mode 100644 spec/lutaml/fixtures/metaschema-prose-module.xsd create mode 100644 spec/lutaml/fixtures/metaschema.xsd create mode 100644 spec/lutaml/fixtures/metaschema_markup_line.xsd create mode 100644 spec/lutaml/fixtures/nist_metaschema_datatypes.xsd create mode 100644 spec/lutaml/fixtures/omml_schema.xsd diff --git a/.rubocop.yml b/.rubocop.yml index 762eebb..fddf597 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -6,3 +6,6 @@ Style/StringLiterals: Style/StringLiteralsInInterpolation: EnforcedStyle: double_quotes + +Documentation: + Enabled: false diff --git a/Gemfile b/Gemfile index 2025e52..a18829f 100644 --- a/Gemfile +++ b/Gemfile @@ -5,8 +5,14 @@ source "https://rubygems.org" # Specify your gem's dependencies in lutaml-xsd.gemspec gemspec +gem "equivalent-xml" + gem "rake", "~> 13.0" gem "rspec", "~> 3.0" gem "rubocop", "~> 1.21" + +gem "nokogiri" + +gem "xml-c14n" diff --git a/lib/lutaml/xsd.rb b/lib/lutaml/xsd.rb index e3f9fcc..a5987fd 100644 --- a/lib/lutaml/xsd.rb +++ b/lib/lutaml/xsd.rb @@ -1,10 +1,12 @@ # frozen_string_literal: true -require_relative "xsd/version" +require "zeitwerk" +require "lutaml/model" +require_relative "xsd/xsd" -module Lutaml - module Xsd - class Error < StandardError; end - # Your code goes here... - end -end +Lutaml::Model::Config.xml_adapter_type = :nokogiri + +loader = Zeitwerk::Loader.for_gem(warn_on_extra_files: true) +loader.push_dir("#{__dir__}/xsd", namespace: Lutaml::Xsd) +loader.ignore("#{__dir__}/lib/lutaml/xsd.rb") +loader.setup diff --git a/lib/lutaml/xsd/annotation.rb b/lib/lutaml/xsd/annotation.rb new file mode 100644 index 0000000..de2763e --- /dev/null +++ b/lib/lutaml/xsd/annotation.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true + +module Lutaml + module Xsd + class Annotation < Lutaml::Model::Serializable + attribute :documentation, Documentation, collection: true + + xml do + root "annotation", mixed: true + namespace "http://www.w3.org/2001/XMLSchema", "xsd" + + map_element :documentation, to: :documentation + end + end + end +end diff --git a/lib/lutaml/xsd/any.rb b/lib/lutaml/xsd/any.rb new file mode 100644 index 0000000..1ce1bec --- /dev/null +++ b/lib/lutaml/xsd/any.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +module Lutaml + module Xsd + class Any < Lutaml::Model::Serializable + attribute :namespace, :string + attribute :process_contents, :string + + xml do + root "any", mixed: true + namespace "http://www.w3.org/2001/XMLSchema", "xsd" + + map_attribute :namespace, to: :namespace + map_attribute :processContents, to: :process_contents + end + end + end +end diff --git a/lib/lutaml/xsd/attribute.rb b/lib/lutaml/xsd/attribute.rb new file mode 100644 index 0000000..8f5b58d --- /dev/null +++ b/lib/lutaml/xsd/attribute.rb @@ -0,0 +1,26 @@ +# frozen_string_literal: true + +module Lutaml + module Xsd + class Attribute < Lutaml::Model::Serializable + attribute :use, :string + attribute :name, :string + attribute :type, :string + attribute :default, :string + attribute :annotation, Annotation, collection: true + attribute :simple_type, SimpleType, collection: true + + xml do + root "attribute", mixed: true + namespace "http://www.w3.org/2001/XMLSchema", "xsd" + + map_attribute :use, to: :use + map_attribute :name, to: :name + map_attribute :type, to: :type + map_attribute :default, to: :default + map_element :annotation, to: :annotation + map_element :simpleType, to: :simple_type + end + end + end +end diff --git a/lib/lutaml/xsd/attribute_group.rb b/lib/lutaml/xsd/attribute_group.rb new file mode 100644 index 0000000..7e94e9d --- /dev/null +++ b/lib/lutaml/xsd/attribute_group.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true + +module Lutaml + module Xsd + class AttributeGroup < Lutaml::Model::Serializable + attribute :name, :string + attribute :ref, :string + attribute :annotation, Annotation, collection: true + attribute :attribute, Attribute, collection: true + + xml do + root "attributeGroup", mixed: true + namespace "http://www.w3.org/2001/XMLSchema", "xsd" + + map_attribute :ref, to: :ref + map_attribute :name, to: :name + map_element :annotation, to: :annotation + map_element :attribute, to: :attribute + end + end + end +end diff --git a/lib/lutaml/xsd/choice.rb b/lib/lutaml/xsd/choice.rb new file mode 100644 index 0000000..dcdeb80 --- /dev/null +++ b/lib/lutaml/xsd/choice.rb @@ -0,0 +1,28 @@ +# frozen_string_literal: true + +module Lutaml + module Xsd + class Sequence < Lutaml::Model::Serializable; end + + class Choice < Lutaml::Model::Serializable + attribute :any, Any, collection: true + attribute :min_occurs, :string + attribute :max_occurs, :string + attribute :element, Element, collection: true + attribute :sequence, Sequence, collection: true + attribute :group, Group, collection: true + + xml do + root "choice", mixed: true + namespace "http://www.w3.org/2001/XMLSchema", "xsd" + + map_attribute :minOccurs, to: :min_occurs + map_attribute :maxOccurs, to: :max_occurs + map_element :element, to: :element + map_element :sequence, to: :sequence + map_element :group, to: :group + map_element :any, to: :any + end + end + end +end diff --git a/lib/lutaml/xsd/complex_content.rb b/lib/lutaml/xsd/complex_content.rb new file mode 100644 index 0000000..3ba6c57 --- /dev/null +++ b/lib/lutaml/xsd/complex_content.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true + +module Lutaml + module Xsd + class ComplexContent < Lutaml::Model::Serializable + attribute :extension, Extension, collection: true + + xml do + root "complexContent", mixed: true + namespace "http://www.w3.org/2001/XMLSchema", "xsd" + + map_element :extension, to: :extension + end + end + end +end diff --git a/lib/lutaml/xsd/complex_type.rb b/lib/lutaml/xsd/complex_type.rb new file mode 100644 index 0000000..c3b84cf --- /dev/null +++ b/lib/lutaml/xsd/complex_type.rb @@ -0,0 +1,34 @@ +# frozen_string_literal: true + +module Lutaml + module Xsd + class ComplexType < Lutaml::Model::Serializable + attribute :name, :string + attribute :mixed, :string + attribute :abstract, :string + attribute :choice, Choice, collection: true + attribute :sequence, Sequence, collection: true + attribute :attribute, Attribute, collection: true + attribute :annotation, Annotation, collection: true + attribute :attribute_group, AttributeGroup, collection: true + attribute :simple_content, SimpleContent, collection: true + attribute :complex_content, ComplexContent, collection: true + + xml do + root "complexType", mixed: true + namespace "http://www.w3.org/2001/XMLSchema", "xsd" + + map_attribute :name, to: :name + map_attribute :mixed, to: :mixed + map_attribute :abstract, to: :abstract + map_element :choice, to: :choice + map_element :sequence, to: :sequence + map_element :attribute, to: :attribute + map_element :annotation, to: :annotation + map_element :attributeGroup, to: :attribute_group + map_element :simpleContent, to: :simple_content + map_element :complexContent, to: :complex_content + end + end + end +end diff --git a/lib/lutaml/xsd/documentation.rb b/lib/lutaml/xsd/documentation.rb new file mode 100644 index 0000000..2c1b798 --- /dev/null +++ b/lib/lutaml/xsd/documentation.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true + +module Lutaml + module Xsd + class Documentation < Lutaml::Model::Serializable + attribute :content, :string + + xml do + root "documentation" + namespace "http://www.w3.org/2001/XMLSchema", "xsd" + + map_all to: :content + end + end + end +end diff --git a/lib/lutaml/xsd/element.rb b/lib/lutaml/xsd/element.rb new file mode 100644 index 0000000..0e5c246 --- /dev/null +++ b/lib/lutaml/xsd/element.rb @@ -0,0 +1,34 @@ +# frozen_string_literal: true + +module Lutaml + module Xsd + class Element < Lutaml::Model::Serializable + attribute :name, :string + attribute :type, :string + attribute :default, :string + attribute :min_occurs, :string + attribute :max_occurs, :string + attribute :key, Key, collection: true + attribute :unique, Unique, collection: true + attribute :complex_type, ComplexType, collection: true + attribute :simple_type, SimpleType, collection: true + attribute :annotation, Annotation, collection: true + + xml do + root "element", mixed: true + namespace "http://www.w3.org/2001/XMLSchema", "xsd" + + map_attribute :name, to: :name + map_attribute :type, to: :type + map_attribute :default, to: :default + map_attribute :minOccurs, to: :min_occurs + map_attribute :maxOccurs, to: :max_occurs + map_element :complexType, to: :complex_type + map_element :simpleType, to: :simple_type + map_element :annotation, to: :annotation + map_element :unique, to: :unique + map_element :key, to: :key + end + end + end +end diff --git a/lib/lutaml/xsd/enumeration.rb b/lib/lutaml/xsd/enumeration.rb new file mode 100644 index 0000000..ed14f3c --- /dev/null +++ b/lib/lutaml/xsd/enumeration.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +module Lutaml + module Xsd + class Enumeration < Lutaml::Model::Serializable + attribute :value, :string + attribute :annotation, Annotation, collection: true + + xml do + root "enumeration", mixed: true + namespace "http://www.w3.org/2001/XMLSchema", "xsd" + + map_attribute :value, to: :value + map_element :annotation, to: :annotation + end + end + end +end diff --git a/lib/lutaml/xsd/extension.rb b/lib/lutaml/xsd/extension.rb new file mode 100644 index 0000000..2897733 --- /dev/null +++ b/lib/lutaml/xsd/extension.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true + +module Lutaml + module Xsd + class Extension < Lutaml::Model::Serializable + attribute :base, :string + attribute :sequence, Sequence, collection: true + attribute :attribute, Attribute, collection: true + attribute :annotation, Annotation, collection: true + attribute :attribute_group, AttributeGroup, collection: true + + xml do + root "extension", mixed: true + namespace "http://www.w3.org/2001/XMLSchema", "xsd" + + map_attribute :base, to: :base + map_element :sequence, to: :sequence + map_element :attribute, to: :attribute + map_element :annotation, to: :annotation + map_element :attributeGroup, to: :attribute_group + end + end + end +end diff --git a/lib/lutaml/xsd/field.rb b/lib/lutaml/xsd/field.rb new file mode 100644 index 0000000..9dd6ef2 --- /dev/null +++ b/lib/lutaml/xsd/field.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true + +module Lutaml + module Xsd + class Field < Lutaml::Model::Serializable + attribute :xpath, :string + + xml do + root "field", mixed: true + namespace "http://www.w3.org/2001/XMLSchema", "xsd" + + map_attribute :xpath, to: :xpath + end + end + end +end diff --git a/lib/lutaml/xsd/group.rb b/lib/lutaml/xsd/group.rb new file mode 100644 index 0000000..731baaf --- /dev/null +++ b/lib/lutaml/xsd/group.rb @@ -0,0 +1,31 @@ +# frozen_string_literal: true + +module Lutaml + module Xsd + class Sequence < Lutaml::Model::Serializable; end + class Choice < Lutaml::Model::Serializable; end + + class Group < Lutaml::Model::Serializable + attribute :ref, :string + attribute :name, :string + attribute :min_occurs, :string + attribute :max_occurs, :string + attribute :choice, Choice, collection: true + attribute :sequence, Sequence, collection: true + attribute :annotation, Annotation, collection: true + + xml do + root "group", mixed: true + namespace "http://www.w3.org/2001/XMLSchema", "xsd" + + map_attribute :ref, to: :ref + map_attribute :name, to: :name + map_attribute :minOccurs, to: :min_occurs + map_attribute :maxOccurs, to: :max_occurs + map_element :annotation, to: :annotation + map_element :sequence, to: :sequence + map_element :choice, to: :choice + end + end + end +end diff --git a/lib/lutaml/xsd/import.rb b/lib/lutaml/xsd/import.rb new file mode 100644 index 0000000..ab5d50e --- /dev/null +++ b/lib/lutaml/xsd/import.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +module Lutaml + module Xsd + class Import < Lutaml::Model::Serializable + attribute :id, :string + attribute :namespace, :string + + xml do + root "import", mixed: true + namespace "http://www.w3.org/2001/XMLSchema", "xsd" + + map_attribute :id, to: :id + map_attribute :namespace, to: :namespace + end + end + end +end diff --git a/lib/lutaml/xsd/include.rb b/lib/lutaml/xsd/include.rb new file mode 100644 index 0000000..0284b19 --- /dev/null +++ b/lib/lutaml/xsd/include.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true + +module Lutaml + module Xsd + class Include < Lutaml::Model::Serializable + attribute :annotation, Annotation, collection: true + + xml do + root "include", mixed: true + namespace "http://www.w3.org/2001/XMLSchema", "xsd" + + map_element :annotation, to: :annotation + end + end + end +end diff --git a/lib/lutaml/xsd/key.rb b/lib/lutaml/xsd/key.rb new file mode 100644 index 0000000..1016bf3 --- /dev/null +++ b/lib/lutaml/xsd/key.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true + +module Lutaml + module Xsd + class Key < Lutaml::Model::Serializable + attribute :name, :string + attribute :selector, Selector + attribute :field, Field + + xml do + root "key", mixed: true + namespace "http://www.w3.org/2001/XMLSchema", "xsd" + + map_attribute :name, to: :name + map_element :selector, to: :selector + map_element :field, to: :field + end + end + end +end diff --git a/lib/lutaml/xsd/max_inclusive.rb b/lib/lutaml/xsd/max_inclusive.rb new file mode 100644 index 0000000..b291d52 --- /dev/null +++ b/lib/lutaml/xsd/max_inclusive.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true + +module Lutaml + module Xsd + class MaxInclusive < Lutaml::Model::Serializable + attribute :value, :string + + xml do + root "maxInclusive", mixed: true + namespace "http://www.w3.org/2001/XMLSchema", "xsd" + + map_attribute :value, to: :value + end + end + end +end diff --git a/lib/lutaml/xsd/max_length.rb b/lib/lutaml/xsd/max_length.rb new file mode 100644 index 0000000..a341fd3 --- /dev/null +++ b/lib/lutaml/xsd/max_length.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true + +module Lutaml + module Xsd + class MaxLength < Lutaml::Model::Serializable + attribute :value, :integer + + xml do + root "maxLength", mixed: true + namespace "http://www.w3.org/2001/XMLSchema", "xsd" + + map_attribute :value, to: :value + end + end + end +end diff --git a/lib/lutaml/xsd/min_inclusive.rb b/lib/lutaml/xsd/min_inclusive.rb new file mode 100644 index 0000000..0ba9fb1 --- /dev/null +++ b/lib/lutaml/xsd/min_inclusive.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true + +module Lutaml + module Xsd + class MinInclusive < Lutaml::Model::Serializable + attribute :value, :string + + xml do + root "minInclusive", mixed: true + namespace "http://www.w3.org/2001/XMLSchema", "xsd" + + map_attribute :value, to: :value + end + end + end +end diff --git a/lib/lutaml/xsd/pattern.rb b/lib/lutaml/xsd/pattern.rb new file mode 100644 index 0000000..d01f9cc --- /dev/null +++ b/lib/lutaml/xsd/pattern.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +module Lutaml + module Xsd + class Pattern < Lutaml::Model::Serializable + attribute :value, :string + attribute :annotation, Annotation, collection: true + + xml do + root "pattern", mixed: true + namespace "http://www.w3.org/2001/XMLSchema", "xsd" + + map_attribute :value, to: :value + map_element :annotation, to: :annotation + end + end + end +end diff --git a/lib/lutaml/xsd/restriction.rb b/lib/lutaml/xsd/restriction.rb new file mode 100644 index 0000000..e71dc37 --- /dev/null +++ b/lib/lutaml/xsd/restriction.rb @@ -0,0 +1,29 @@ +# frozen_string_literal: true + +module Lutaml + module Xsd + class Restriction < Lutaml::Model::Serializable + attribute :base, :string + attribute :min_inclusive, MinInclusive, collection: true + attribute :max_inclusive, MaxInclusive, collection: true + attribute :enumeration, Enumeration, collection: true + attribute :white_space, WhiteSpace, collection: true + attribute :annotation, Annotation, collection: true + attribute :max_length, MaxLength, collection: true + attribute :pattern, Pattern, collection: true + xml do + root "restriction", mixed: true + namespace "http://www.w3.org/2001/XMLSchema", "xsd" + + map_attribute :base, to: :base + map_element :minInclusive, to: :min_inclusive + map_element :maxInclusive, to: :max_inclusive + map_element :enumeration, to: :enumeration + map_element :whiteSpace, to: :white_space + map_element :annotation, to: :annotation + map_element :maxLength, to: :max_length + map_element :pattern, to: :pattern + end + end + end +end diff --git a/lib/lutaml/xsd/schema.rb b/lib/lutaml/xsd/schema.rb new file mode 100644 index 0000000..2dc1d8d --- /dev/null +++ b/lib/lutaml/xsd/schema.rb @@ -0,0 +1,38 @@ +# frozen_string_literal: true + +module Lutaml + module Xsd + class Schema < Lutaml::Model::Serializable + attribute :xmlns, :string + attribute :import, Import, collection: true + attribute :include, Include, collection: true + attribute :element, Element, collection: true + attribute :complex_type, ComplexType, collection: true + attribute :simple_type, SimpleType, collection: true + attribute :group, Group, collection: true + attribute :attribute_group, AttributeGroup, collection: true + attribute :element_form_default, :string + attribute :attribute_form_default, :string + attribute :block_default, :string + attribute :target_namespace, :string + + xml do + root "schema", mixed: true + namespace "http://www.w3.org/2001/XMLSchema", "xsd" + + map_attribute :xmlns, to: :xmlns, namespace: "http://csrc.nist.gov/ns/oscal/metaschema/1.0", prefix: nil + map_element :import, to: :import + map_element :include, to: :include + map_element :element, to: :element + map_element :complexType, to: :complex_type + map_element :simpleType, to: :simple_type + map_element :group, to: :group + map_element :attributeGroup, to: :attribute_group + map_attribute :elementFormDefault, to: :element_form_default + map_attribute :attributeFormDefault, to: :attribute_form_default + map_attribute :blockDefault, to: :block_default + map_attribute :targetNamespace, to: :target_namespace + end + end + end +end diff --git a/lib/lutaml/xsd/selector.rb b/lib/lutaml/xsd/selector.rb new file mode 100644 index 0000000..de3764e --- /dev/null +++ b/lib/lutaml/xsd/selector.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true + +module Lutaml + module Xsd + class Selector < Lutaml::Model::Serializable + attribute :xpath, :string + + xml do + root "selector", mixed: true + namespace "http://www.w3.org/2001/XMLSchema", "xsd" + + map_attribute :xpath, to: :xpath + end + end + end +end diff --git a/lib/lutaml/xsd/sequence.rb b/lib/lutaml/xsd/sequence.rb new file mode 100644 index 0000000..8c5214c --- /dev/null +++ b/lib/lutaml/xsd/sequence.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true + +module Lutaml + module Xsd + class Choice < Lutaml::Model::Serializable; end + + class Sequence < Lutaml::Model::Serializable + attribute :element, Element, collection: true + attribute :choice, Choice, collection: true + attribute :group, Group, collection: true + + xml do + root "sequence", mixed: true + namespace "http://www.w3.org/2001/XMLSchema", "xsd" + + map_element :element, to: :element + map_element :choice, to: :choice + map_element :group, to: :group + end + end + end +end diff --git a/lib/lutaml/xsd/simple_content.rb b/lib/lutaml/xsd/simple_content.rb new file mode 100644 index 0000000..960bfd9 --- /dev/null +++ b/lib/lutaml/xsd/simple_content.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +module Lutaml + module Xsd + class SimpleContent < Lutaml::Model::Serializable + attribute :base, :string + attribute :extension, Extension, collection: true + + xml do + root "simpleContent", mixed: true + namespace "http://www.w3.org/2001/XMLSchema", "xsd" + + map_attribute :base, to: :base + map_element :extension, to: :extension + end + end + end +end diff --git a/lib/lutaml/xsd/simple_type.rb b/lib/lutaml/xsd/simple_type.rb new file mode 100644 index 0000000..d97eb57 --- /dev/null +++ b/lib/lutaml/xsd/simple_type.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true + +module Lutaml + module Xsd + class SimpleType < Lutaml::Model::Serializable + attribute :name, :string + attribute :union, Union, collection: true + attribute :annotation, Annotation, collection: true + attribute :enumeration, Enumeration, collection: true + attribute :restriction, Restriction, collection: true + + xml do + root "simpleType", mixed: true + namespace "http://www.w3.org/2001/XMLSchema", "xsd" + + map_attribute :name, to: :name + map_element :union, to: :union + map_element :annotation, to: :annotation + map_element :restriction, to: :restriction + map_element :enumeration, to: :enumeration + end + end + end +end diff --git a/lib/lutaml/xsd/union.rb b/lib/lutaml/xsd/union.rb new file mode 100644 index 0000000..35f0d33 --- /dev/null +++ b/lib/lutaml/xsd/union.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +module Lutaml + module Xsd + class Union < Lutaml::Model::Serializable + attribute :member_types, :string + attribute :simple_type, SimpleType, collection: true + + xml do + root "union", mixed: true + namespace "http://www.w3.org/2001/XMLSchema", "xsd" + + map_attribute :memberTypes, to: :member_types + map_element :simpleType, to: :simple_type + end + end + end +end diff --git a/lib/lutaml/xsd/unique.rb b/lib/lutaml/xsd/unique.rb new file mode 100644 index 0000000..665bb18 --- /dev/null +++ b/lib/lutaml/xsd/unique.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true + +module Lutaml + module Xsd + class Unique < Lutaml::Model::Serializable + attribute :name, :string + attribute :selector, Selector, collection: true + attribute :field, Field, collection: true + + xml do + root "unique", mixed: true + namespace "http://www.w3.org/2001/XMLSchema", "xsd" + + map_attribute :name, to: :name + map_element :selector, to: :selector + map_element :field, to: :field + end + end + end +end diff --git a/lib/lutaml/xsd/white_space.rb b/lib/lutaml/xsd/white_space.rb new file mode 100644 index 0000000..1914a81 --- /dev/null +++ b/lib/lutaml/xsd/white_space.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true + +module Lutaml + module Xsd + class WhiteSpace < Lutaml::Model::Serializable + attribute :value, :string + + xml do + root "whiteSpace", mixed: true + namespace "http://www.w3.org/2001/XMLSchema", "xsd" + + map_attribute :value, to: :value + end + end + end +end diff --git a/lib/lutaml/xsd/xsd.rb b/lib/lutaml/xsd/xsd.rb new file mode 100644 index 0000000..863cba6 --- /dev/null +++ b/lib/lutaml/xsd/xsd.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +module Lutaml + module Xsd + class Error < StandardError; end + + module_function + + def parse(xsd) + Schema.from_xml(xsd) + end + end +end diff --git a/lutaml-xsd.gemspec b/lutaml-xsd.gemspec index b12fef5..02322cd 100644 --- a/lutaml-xsd.gemspec +++ b/lutaml-xsd.gemspec @@ -31,4 +31,7 @@ Gem::Specification.new do |spec| end spec.test_files = `git ls-files -- {spec}/*`.split("\n") + + spec.add_dependency "lutaml-model", "~> 0.3" + spec.add_dependency "zeitwerk" end diff --git a/spec/lutaml/fixtures/metaschema-markup-multiline.xsd b/spec/lutaml/fixtures/metaschema-markup-multiline.xsd new file mode 100644 index 0000000..794901d --- /dev/null +++ b/spec/lutaml/fixtures/metaschema-markup-multiline.xsd @@ -0,0 +1,135 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + The content model is the same as inlineMarkupType, but line endings need + to be preserved, since this is pre-formatted. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/spec/lutaml/fixtures/metaschema-meta-constraints.xsd b/spec/lutaml/fixtures/metaschema-meta-constraints.xsd new file mode 100644 index 0000000..30cb54c --- /dev/null +++ b/spec/lutaml/fixtures/metaschema-meta-constraints.xsd @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/spec/lutaml/fixtures/metaschema-prose-base.xsd b/spec/lutaml/fixtures/metaschema-prose-base.xsd new file mode 100644 index 0000000..9a4cb34 --- /dev/null +++ b/spec/lutaml/fixtures/metaschema-prose-base.xsd @@ -0,0 +1,82 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + An insert can be used to identify a placeholder for dynamically inserting text related to a specific object, which is referenced by the object's identifier using an id-ref. This insert mechanism allows the selection of which text value from the object to dynamically include based on the application's display requirements. + + + + The type of object to include from (e.g., parameter, control, component, role, etc.) + + + + + The identity of the object to insert a value for. The identity will be selected from the index of objects of the specified type. The specific value to include is based on the application's display requirements, which will likely use a specific data element associated with the type (e.g., title, identifier, value, etc.) that is appropriate for the application. + + + + + + + \ No newline at end of file diff --git a/spec/lutaml/fixtures/metaschema-prose-module.xsd b/spec/lutaml/fixtures/metaschema-prose-module.xsd new file mode 100644 index 0000000..ef155ea --- /dev/null +++ b/spec/lutaml/fixtures/metaschema-prose-module.xsd @@ -0,0 +1,5 @@ + + + + diff --git a/spec/lutaml/fixtures/metaschema.xsd b/spec/lutaml/fixtures/metaschema.xsd new file mode 100644 index 0000000..af136ab --- /dev/null +++ b/spec/lutaml/fixtures/metaschema.xsd @@ -0,0 +1,1344 @@ + + + + + + + Root element of a Metaschema definition. Defines a family of data + structures representing a model. + + + + + + The name of the information model represented by this Metaschema definition. + + + + + + + The namespace for the collection of Metaschema models this Metaschema module + belongs to. Also the XML namespace governing the names of elements in XML documents, which + expect to be conformant to the schemas expressed by this Metaschema module. By using this + namespace, documents and document fragments used in mixed-format environments may be + distinguished from neighbor XML formats using other namespaces. This value is not reflected in + Metaschema JSON. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Imports a set of Metaschema modules containing exported definitions from an out-of-line resource, supporting reuse of common information structures. + + + + A relative or absolute URI for retrieving an out-of-line Metaschema definition. + + + + + + + + + + A formal name for the data construct for use in documentation. + + + + + + + A short semantic description of the data construct's purpose. + + + + + + + + + + + + + + + + + The human-oriented naming type for all definitions and instances for use in textual data. + + + + + + + The machine-oriented naming type of all definitions and instances for use in binary data. + + + + + + + Common definition attributes that support definition naming. + + + + + + + + Common definition attributes that support definition referencing. + + + + + + + + Common definition attributes that support root definition naming. + + + + + + + + + + + + + + + + + + + + + + + + + Common definition attributes that support instance naming. + + + + + + + + + An element with structured element content in XML; in JSON, an object with + properties. Defined globally, an assembly can be assigned to appear in the model of any assembly (another assembly type, or itself), by assembly reference. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Used inside a field definition, designates a name (key) for the property in JSON containing the field's value. Use of a 'json-value-key' is mutually exclusive with a 'json-value-key-flag'. + + + + + + Used inside a field definition, designates a flag whose value is to be used as the name (key) for the property in JSON containing the field's value. Use of a 'json-value-key-flag' is mutually exclusive with a 'json-value-key'. + + + + + + + In JSON, an object with a nominal string value (potentially with internal + inline - not fully structured - markup). In XML, an element with string or markup + content. Defined globally, a field can be assigned to appear in the model of any assembly by field reference. + + + + + + + + + + + + + + + + + + + + + + + A data point to be expressed as an attribute in the XML or a name/value pair + in the JSON. A flag may also be defined implicitly with the assembly or field to which it + applies. Defined globally, a flag can be assigned to any field or assembly by flag reference. + + + + + + + + + + + + + + + + + In JSON, an object with a nominal string value (potentially with internal + inline - not fully structured - markup). In XML, an element with string or markup + content. A local definition describes and constrains the appearance of the field only in this (assembly) context. + + + + + + + + + + + + + + + + + + + + + + + In JSON, an object with a nominal string value (potentially with internal + inline - not fully structured - markup). In XML, an element with string or markup + content. + + + + + + + + + + + + + + + + + + + + + A field with assigned data type 'markup-multiline' may be designated for representation with or without a containing (wrapper) element in XML. + + + + + + + + A data point to be expressed as an attribute in the XML or a name/value pair in the JSON. A local definition describes and constrains the appearance of the flag only in its parent (assembly or field) context. + + + + + + + + + + + + + + + + The JSON Base URI is nominal base URI assigned to a JSON Schema instance expressing the model defined by this Metaschema module. + + + + + + + Any explanatory or helpful information to be provided in the + documentation of an assembly, field or flag. + + + + + + Mark as 'XML' for XML-only or 'JSON' for JSON-only remarks. + + + + + + The remark applies to only XML representations. + + + + + The remark applies to only JSON and YAML representations. + + + + + + + + + + + + A version string used to distinguish between multiple revisions of the same resource. + + + + + + + A short (code) name to be used for the Metaschema module, for example as a constituent of names assigned to + derived artifacts such as schemas and conversion utilities. + + + + + + + Referencing an assembly definition to include an assembly or assemblies of a given type in a model. + + + + + + + + + + + + + + + Referencing a field definition to include a field or fields of a given type in a model. + + + + + + + + + + + + A field with assigned data type 'markup-multiline' may be designated for representation with or without a containing (wrapper) element + in XML. + + + + + + + + + + + Any paragraph or block contents of a markup-multiline field will be represented with a containing (wrapper) element in the XML. + + + + + (deprecated)Alias for WRAPPED. + + + + + With in-xml='UNWRAPPED', a field contents will be represented in the XML with no wrapper, so the field will be implicit. Among sibling fields in a given model, only one of them may be designated as UNWRAPPED. + + + + + + + + + Minimum occurrence of assemblies or fields within a valid model. The default value is 0, for an optional occurrence. + + + + + Maximum occurrence of assemblies or fields within a valid model. The default value is 1, for a single occurrence. 'unbounded' permits any number of assemblies of the designated type. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + The associated construct has been deprecated at the specified version. Its use should be avoided if possible. + + + + + + + + + + + + + + + + + + + Within a model, indicates that only one of a set of fields or assemblies, referenced in the choice, may occur in valid instances. + + + + + + + + + + + + Within a model, indicates that only one of a set of fields or assemblies, referenced in the choice, may occur in valid instances. + + + + + + + + + + + + + + + Minimum occurrence of assemblies or fields within a valid model. The default value is 0, for an optional occurrence. + + + + + Maximum occurrence of assemblies or fields within a valid model. The default value is 1, for a single occurrence. 'unbounded' permits any number of assemblies of the designated type. + + + + + + + Referencing an assembly definition to include an assembly or assemblies of a given type in a model. + + + + + + + + + + + + + Referencing a field definition to include a field or fields of a given type in a model. + + + + + + + + + + + + + In JSON, an object with a nominal string value (potentially with internal + inline - not fully structured - markup). In XML, an element with string or markup + content. A local definition describes and constrains the appearance of the field only in this (assembly) context. + + + + + + + + + + + + + + + + + + + + In JSON, an object with a nominal string value (potentially with internal + inline - not fully structured - markup). In XML, an element with string or markup + content. A local definition describes and constrains the appearance of the field only in this (assembly) context. + + + + + + + + + + + + + + + + + + + A field with assigned datatype 'markup-multiline' may be designated for representation with or without a containing (wrapper) element + in XML. + + + + + + + Common definition attributes that support instance naming. + + + + + + + + + + Within a model, a foreign element may be permitted here. + + + + + + + + A short description providing basic documentation about the example's purpose. + + + + + + + + + + + + + + In the XML, produces an attribute with the given name, whose value is used as a key value (aka object property name) in the JSON, enabling objects to be 'lifted' out of arrays when such values are distinct. Implies that siblings will never share values. + + + + + + + When a given referenced field or assembly must be wrapped in an outer grouping, these settings apply, including a name for the group, and how to express the grouping in the respective formats. Not necessary when a field or assembly has max-occurs='1' + + + + + + How to represent a grouping in JSON + + + + + Whether to represent a grouping explicitly in XML + + + + + + + + + Always use an array + + + + + Produce a singleton for a single member (field or assembly) or an array for multiple members + + + + + For any group (one or more members) produce an object with properties for each member, using a designated flag for their key (label) values, which must be distinct + + + + + + + + + Use a wrapper element + + + + + Do not use a wrapper element + + + + + + + + + + + + + + + + + + + + + + + + + + + + A string with no leading or trailing whitespace. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + This definition is only available in the context of the current Metaschema module. + + + + + This definition will be made available to any Metaschema module that includes this one either directly or indirectly through a chain of imported Metaschema modules. + + + + + + + + + + + + + + + + + + + + + + + + + A violation of the constraint represents a serious fault in the content + that will prevent typical use of the content. + + + + + A violation of the constraint represents a fault in the content. This + may include issues around compatibility, integrity, consistency, etc. + + + + + A violation of the constraint represents a potential issue + with the content. + + + + + A violation of the constraint represents a point of interest. + + + + + A violation of the constraint represents a fault in the content that may + warrant review by a developer when performing model or tool development. + + + + + + + + + + + + + + Indicates an enumeration of a set values to be recognized for a flag or field. + + + + + + + + + + The given enumerated value or values are inclusive of other values ('yes') or not ('no', the default) + + + + + Determines if the given enumerated values may be extended by other allowed value constraints. + + + + + + + + + + + Can be extended by constraints within the same module. + + + + + Can be extended by external constraints. + + + + + Cannot be extended. + + + + + + + + An enumerated value for a flag or field. The value is indicated by the 'value' attribute while the element contents describe the intended semantics for documentation. + + + + + + A value recognized for a flag or field. + + + + + + + + + + A regular expression subset that conforms to both https://www.w3.org/TR/xmlschema11-2/#regexes and https://www.ecma-international.org/ecma-262/11.0/index.html#sec-patterns. + + + + + + + + + + + + + + + Specifies the datatype for which the value identified by the scope + attribute must conform to. + + + + + + + + + + + + Specifies the target of the constraint as a Metaschema Metapath. If the value is "." and the containing Metaschema object is a field, the constraint applies to the field's value. Otherwise, the scope value "." is not allowed to be used. + + + + + + + + + + + + Specifies the target of the constraint as a Metaschema Metapath. If the value is "." and the containing Metaschema object is a field, the constraint applies to the field's value. + + + + + + + + + + + + + Specifies the field or flag value that is used to generate the key for a given object that is a member of this index. If more than one key-field is provided, then the key is a composition of the specified key-field objects. The ordering of the key-field objects establish the relative order of the index's key. The field or flag values pointed to are a field or flag value, which can be an empty value if not provided. Note: Multiple empty values can result in key conflicts. + + + + + + + Defines an unique key constraint. + + + + + + + Specifies a value, relative to the provided target, + that is to be used as part of the key. More than one key-field can be used to create + a composite key. + + + + + + + The first captured group in the regular expression is used + as the key value for lookup. The regular expression must not match a + zero-length string. + + + + + + + + + + + + + + + + + + Specifies a Metapath that can be evaluated to get the value objects to be included in the key constraint, or the object that contains a reference to an item in an index. If the value is ".", then the key is targeting the current Metaschema object. + + + + + + + + + Defines an index, a check against an index, or a uniqueness constraint. + + + + + + Specifies the name of the index, a reference to an index, or the name of a uniqueness constraint. + + + + + + + + + Defines an index, a check against an index, or a uniqueness constraint. + + + + + + Specifies a Metapath that can be evaluated to get the value objects to be included in the index constraint, or the object that contains a reference to an item in an index. If the value is ".", then the key is targeting the current Metaschema object. + + + + + + + + + Defines an index, a check against an index, or a uniqueness constraint. + + + + + + Specifies the value objects to be included in the index constraint, or the object that contains a reference to an item in an index. If the value is ".", then the key is targeting the current Metaschema object. + + + + + Specifies the name of the index, a reference to an index, or the name of a uniqueness constraint. + + + + + + + + + + + + + + + + A Metapath test that is expected to pass in this context. + + + + + + + + + + + + Specifies the target of the constraint as a Metaschema Metapath. If the value is "." and the containing Metaschema object is a field or flag, the constraint applies to the value of the field or flag. Otherwise, the scope value "." is not allowed to be used. + + + + + + + + + + + + + + + Specifies the target of the constraint as a Metaschema Metapath. If the + value is "." and the containing Metaschema object is a field, the constraint applies + to the field's value. Otherwise, the scope value "." is not allowed to be + used. + + + + + Minimum occurrence of assemblies or fields within the set of objects + identified by the target. This value cannot be less than the + corresponding value defined on the target. + + + + + Maximum occurrence of assemblies or fields within the set of objects + identified by the target. This value must be less than the corresponding + value defined on the target. + + + + + + + + + + + + + + + + + + + Declares a variable whose name is bound to the result of the Metapath expression. These variables can be used in target and other Metapath expressions used in constrains that are declared in the same context or in constraints declared in a child assembly, field, or flag. + + + + + + + + + + + + Constrains the allowed values for the flag. + + + + + Constrains the allowed values based on the provided regex pattern. + + + + + Checks that the specified key-field values match a key in the index with the specified name. + + + + + Checks that the specified test returns true in this evaluation context. + + + + + + + + + + + + Constrains the allowed values for the flag or field referenced by the scope attribute. + + + + + Constrains the allowed values based on the provided regex pattern or checks that the value conforms to the specified datatype. + + + + + Checks that the specified key-field values match a key in the index with the specified name. + + + + + Checks that the specified test returns true in this evaluation context. + + + + + + + + + + Defines a new named index. Each entry in the index will have a unique key, based on the key-field elements, and an associated object value, based on the target selection.. + + + + + Checks that the specified set of target entries have a key, based on the key-field entries that is unique. The name identifies the name of the uniqueness constraint, which can be used for error reporting, etc. + + + + + Checks that the specified set of target entries match the provided cardinality. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Root element of a Metaschema external constraints definition. Defines rules to be applied to an existing set of Metaschema models. + + + + + + The name of this constraint set. + + + + + The version of this constraint set. + + + + + To import a set of Metaschema constraints from an out-of-line resource, supporting composition of constraint sets. + + + + + A relative or absolute URI for retrieving an out-of-line Metaschema definition. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/spec/lutaml/fixtures/metaschema_markup_line.xsd b/spec/lutaml/fixtures/metaschema_markup_line.xsd new file mode 100644 index 0000000..0bfd34e --- /dev/null +++ b/spec/lutaml/fixtures/metaschema_markup_line.xsd @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/spec/lutaml/fixtures/nist_metaschema_datatypes.xsd b/spec/lutaml/fixtures/nist_metaschema_datatypes.xsd new file mode 100644 index 0000000..6576bd1 --- /dev/null +++ b/spec/lutaml/fixtures/nist_metaschema_datatypes.xsd @@ -0,0 +1,263 @@ + + + + + + Binary data encoded using the Base64 encoding algorithm + as defined by RFC4648. + + + + + + + + + A binary value that is either: true (or 1) or false (or 0). + + + + + + + + + A string representing a 24-hour period with an optional timezone. + + + + + + + + + A string representing a 24-hour period with a required timezone. + + + + + + + + + A string representing a point in time with an optional timezone. + + + + + + + + + A string representing a point in time with a required timezone. + + + + + + + + + An amount of time quantified in days, hours, minutes, and seconds. + + + + + + + + + A real number expressed using a whole and optional fractional part + separated by a period. + + + + + This pattern ensures that leading and trailing whitespace is + disallowed. This helps to even the user experience between implementations + related to whitespace. + + + + + + + + An email address string formatted according to RFC 6531. + + + + + + + + + + + A host name + + + + + + + + + A whole number value. + + + + + This pattern ensures that leading and trailing whitespace is + disallowed. This helps to even the user experience between implementations + related to whitespace. + + + + + + + + An Internet Protocol version 4 address represented using + dotted-quad syntax as defined in section 3.2 of RFC2673. + + + + + + + + + An Internet Protocol version 6 address represented using + the syntax defined in section 2.2 of RFC3513. + This is based on the pattern provided here: + https://stackoverflow.com/questions/53497/regular-expression-that-matches-valid-ipv6-addresses + with some customizations. + + + + + + + + + An integer value that is equal to or greater than 0. + + + + + This pattern ensures that leading and trailing whitespace is + disallowed. This helps to even the user experience between implementations + related to whitespace. + + + + + + + + An integer value that is greater than 0. + + + + + This pattern ensures that leading and trailing whitespace is + disallowed. This helps to even the user experience between implementations + related to whitespace. + + + + + + + + A non-empty string of Unicode characters with leading and trailing whitespace + disallowed. Whitespace is: U+9, U+10, U+32 or [ \n\t]+ + + + + The 'string' datatype restricts the XSD type by prohibiting leading + and trailing whitespace, and something (not only whitespace) is required. + + + + + This pattern ensures that leading and trailing whitespace is + disallowed. This helps to even the user experience between implementations + related to whitespace. + + + + + + + + + A non-empty, non-colonized name as defined by XML Schema Part 2: Datatypes + Second Edition (https://www.w3.org/TR/xmlschema11-2/#NCName), with leading and trailing + whitespace disallowed. + + + + + + A single token may not contain whitespace. + + + + + + + + + A universal resource identifier (URI) formatted according to RFC3986. + + + + + Requires a scheme with colon per RFC 3986. + + + + + + + + A URI Reference, either a URI or a relative-reference, formatted according to section 4.1 of RFC3986. + + + + + This pattern ensures that leading and trailing whitespace is + disallowed. This helps to even the user experience between implementations + related to whitespace. + + + + + + + + A type 4 ('random' or 'pseudorandom') or type 5 UUID per RFC + 4122. + + + + + A sequence of 8-4-4-4-12 hex digits, with extra + constraints in the 13th and 17-18th places for version 4 and 5 + + + + + + + + + + + + \ No newline at end of file diff --git a/spec/lutaml/fixtures/omml_schema.xsd b/spec/lutaml/fixtures/omml_schema.xsd new file mode 100644 index 0000000..b1770a2 --- /dev/null +++ b/spec/lutaml/fixtures/omml_schema.xsd @@ -0,0 +1,1528 @@ + + + + + + Integer value (1 to 255) + + + + + + + + + + Value + + + + + + Integer value (-2 to 2) + + + + + + + + + + Value + + + + + + Spacing Rule + + + + + + + + + + Value + + + + + + Unsigned integer. + + + + + + + Value + + + + + + Character + + + + + + + + + value + + + + + + On Off + + + + + On + + + + + Off + + + + + + + + value + + + + + + String + + + + + + + value + + + + + + Horizontal Alignment + + + + + Left Justification + + + + + Center + + + + + Right + + + + + + + + Value + + + + + + Vertical Alignment + + + + + Top + + + + + Center (Function) + + + + + Bottom Alignment + + + + + + + + Value + + + + + + Shape (Delimiters) + + + + + Centered (Delimiters) + + + + + Match + + + + + + + + Value + + + + + + Fraction Type + + + + + Bar Fraction + + + + + Skewed + + + + + Linear Fraction + + + + + No-Bar Fraction (Stack) + + + + + + + + Value + + + + + + Limit Location + + + + + Under-Over location + + + + + Subscript-Superscript location + + + + + + + + Value + + + + + + Top-Bottom + + + + + Top + + + + + Bottom Alignment + + + + + + + + Value + + + + + + Script + + + + + Roman + + + + + Script + + + + + Fraktur + + + + + double-struck + + + + + Sans-Serif + + + + + Monospace + + + + + + + + Value + + + + + + Style + + + + + Plain + + + + + Bold + + + + + Italic + + + + + Bold-Italic + + + + + + + + Value + + + + + + + Index of Operator to Align To + + + + + + + + Script + + + + + style + + + + + + + + + Literal + + + + + + Normal Text + + + + + + + + + Break + + + + + Align + + + + + + + + + + Content Contains Significant Whitespace + + + + + + + + + + Run Properties + + + + + + + + Text + + + + + + + + + + + + + + + Accent Character + + + + + Control Properties + + + + + + + + + Accent Properties + + + + + Base + + + + + + + + + Position (Bar) + + + + + + + + + + Bar Properties + + + + + Base + + + + + + + + + Operator Emulator + + + + + No Break + + + + + Differential + + + + + Break + + + + + Alignment + + + + + + + + + + Box Properties + + + + + Base + + + + + + + + + Hide Top Edge + + + + + Hide Bottom Edge + + + + + Hide Left Edge + + + + + Hide Right Edge + + + + + Border Box Strikethrough Horizontal + + + + + Border Box Strikethrough Vertical + + + + + Border Box Strikethrough Bottom-Left to Top-Right + + + + + Border Box Strikethrough Top-Left to Bottom-Right + + + + + + + + + + Border Box Properties + + + + + Base + + + + + + + + + Delimiter Beginning Character + + + + + Delimiter Separator Character + + + + + Delimiter Ending Character + + + + + Delimiter Grow + + + + + Shape (Delimiters) + + + + + + + + + + Delimiter Properties + + + + + Base + + + + + + + + + Equation Array Base Justification + + + + + Maximum Distribution + + + + + Object Distribution + + + + + Row Spacing Rule + + + + + Row Spacing (Equation Array) + + + + + + + + + + Equation Array Properties + + + + + Element + + + + + + + + + Fraction type + + + + + + + + + + Fraction Properties + + + + + Numerator + + + + + Denominator + + + + + + + + + + + + + + Function Properties + + + + + Function Name + + + + + Base (Argument) + + + + + + + + + Group Character (Grouping Character) + + + + + Position (Group Character) + + + + + Vertical Justification + + + + + + + + + + Group-Character Properties + + + + + Base + + + + + + + + + + + + + + Lower Limit Properties + + + + + Base + + + + + Limit (Lower) + + + + + + + + + + + + + + Upper Limit Properties + + + + + Base + + + + + Limit (Upper) + + + + + + + + + Matrix Column Count + + + + + Matrix Column Justification + + + + + + + + + Matrix Column Properties + + + + + + + + + Matrix Column + + + + + + + + + Matrix Base Justification + + + + + Hide Placeholders (Matrix) + + + + + Row Spacing Rule + + + + + Matrix Column Gap Rule + + + + + Row Spacing (Matrix) + + + + + Matrix Column Spacing + + + + + Matrix Column Gap + + + + + Matrix Columns + + + + + + + + + + Element + + + + + + + + + Matrix Properties + + + + + Matrix Row + + + + + + + + + n-ary Operator Character + + + + + n-ary Limit Location + + + + + n-ary Grow + + + + + Hide Subscript (n-ary) + + + + + Hide Superscript (n-ary) + + + + + + + + + + n-ary Properties + + + + + Lower limit (n-ary) + + + + + Upper limit (n-ary) + + + + + Base (Argument) + + + + + + + + + Phantom Show + + + + + Phantom Zero Width + + + + + Phantom Zero Ascent + + + + + Phantom Zero Descent + + + + + Transparent (Phantom) + + + + + + + + + + Phantom Properties + + + + + Base + + + + + + + + + Hide Degree + + + + + + + + + + Radical Properties + + + + + Degree + + + + + Base + + + + + + + + + + + + + + Pre-Sub-Superscript Properties + + + + + Subscript (Pre-Sub-Superscript) + + + + + Superscript(Pre-Sub-Superscript function) + + + + + Base + + + + + + + + + + + + + + Subscript Properties + + + + + Base + + + + + Subscript (Subscript function) + + + + + + + + + Align Scripts + + + + + + + + + + Sub-Superscript Properties + + + + + Base + + + + + Subscript (Sub-Superscript) + + + + + Superscript (Sub-Superscript function) + + + + + + + + + + + + + + Superscript Properties + + + + + Base + + + + + Superscript (Superscript function) + + + + + + + + + Accent + + + + + Bar + + + + + Box Function + + + + + Border-Box Function + + + + + Delimiter Function + + + + + Equation-Array Function + + + + + Fraction Function + + + + + Function Apply Function + + + + + Group-Character Function + + + + + Lower-Limit Function + + + + + Upper-Limit Function + + + + + Matrix Function + + + + + n-ary Operator Function + + + + + Phantom Function + + + + + Radical Function + + + + + Pre-Sub-Superscript Function + + + + + Subscript Function + + + + + Sub-Superscript Function + + + + + Superscript Function + + + + + Run + + + + + + + + + + + + + + + Argument Size + + + + + + + + + Argument Properties + + + + + + + + + Justification + + + + + Left Justification + + + + + Right + + + + + Center (Equation) + + + + + Centered as Group (Equations) + + + + + + + + Value + + + + + + + + Justification + + + + + + + Twips measurement + + + + + + + Value + + + + + + Break Binary Operators + + + + + Before + + + + + After + + + + + Repeat + + + + + + + + Value + + + + + + Break on Binary Subtraction + + + + + Minus Minus + + + + + Minus Plus + + + + + Plus Minus + + + + + + + + Value + + + + + + + + Math Font + + + + + Break on Binary Operators + + + + + Break on Binary Subtraction + + + + + Small Fraction + + + + + Use Display Math Defaults + + + + + Left Margin + + + + + Right Margin + + + + + Default Justification + + + + + Pre-Equation Spacing + + + + + Post-Equation Spacing + + + + + Inter-Equation Spacing + + + + + Intra-Equation Spacing + + + + + + Wrap Indent + + + + + Wrap Right + + + + + + Integral Limit Locations + + + + + n-ary Limit Location + + + + + + + Math Properties + + + + + + + Office Math Paragraph Properties + + + + + Office Math + + + + + + + + + + + + + + + + + + + + Math Paragraph + + + + diff --git a/spec/lutaml/xsd_spec.rb b/spec/lutaml/xsd_spec.rb index 0096ade..19a90f7 100644 --- a/spec/lutaml/xsd_spec.rb +++ b/spec/lutaml/xsd_spec.rb @@ -1,11 +1,35 @@ # frozen_string_literal: true +require "spec_helper" + RSpec.describe Lutaml::Xsd do + subject(:parsed_schema) { described_class.parse(schema) } + it "has a version number" do expect(Lutaml::Xsd::VERSION).not_to be nil end - it "does something useful" do - # expect(false).to eq(true) + Dir.glob(File.expand_path("fixtures/*.xsd", __dir__)).each do |input_file| + context "when parsing #{input_file}" do + let(:schema) { File.read(input_file) } + + it "matches a Lutaml::Model::Schema object" do + expect(parsed_schema).to be_a(Lutaml::Xsd::Schema) + end + + it "matches count of direct child elements of the root" do + # TODO: uncomment once we have a way to process imports + # expect(parsed_schema.import.count).to eql(schema.scan(/<\w+:import /).count) + expect(parsed_schema.group.count).to eql(schema.scan(/<\w+:group name=/).count) + expect(parsed_schema.simple_type.count).to eql(schema.scan(/<\w+:simpleType /).count) + expect(parsed_schema.element.count).to eql(schema.scan(/^\s{0,2}<\w+:element /).count) + expect(parsed_schema.complex_type.count).to eql(schema.scan(/<\w+:complexType /).count) + end + + it "matches count of attributes" do + processed_xml = schema_to_xml(parsed_schema.to_xml, escape_content_tags: true) + expect(processed_xml).to be_analogous_with(schema_to_xml(schema)) + end + end end end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 466b3c3..1db06e4 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -1,6 +1,7 @@ # frozen_string_literal: true require "lutaml/xsd" +require "xml/c14n" RSpec.configure do |config| # Enable flags like --only-failures and --next-failure @@ -13,3 +14,9 @@ c.syntax = :expect end end + +def schema_to_xml(xml, escape_content_tags: false) + xml = Xml::C14n.format(xml) + xml.gsub!(/<([^&]+)&\gt;/, '<\1>') if escape_content_tags + xml +end