dcc 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +16 -0
- data/.rspec +3 -0
- data/.rubocop.yml +16 -0
- data/.rubocop_todo.yml +10 -0
- data/CHANGELOG.adoc +54 -0
- data/CONTRIBUTING.adoc +64 -0
- data/Gemfile +25 -0
- data/LICENSE +21 -0
- data/README.adoc +69 -0
- data/Rakefile +13 -0
- data/dcc.gemspec +41 -0
- data/docs/cli-reference.adoc +67 -0
- data/docs/getting-started.adoc +117 -0
- data/docs/schema-versions.adoc +65 -0
- data/examples/build_minimal_dcc.rb +23 -0
- data/examples/convert_all_formats.rb +19 -0
- data/examples/parse_and_inspect.rb +19 -0
- data/examples/quantity_math_demo.rb +32 -0
- data/examples/validate_full.rb +27 -0
- data/exe/dcc +7 -0
- data/lib/dcc/base/administrative_data.rb +43 -0
- data/lib/dcc/base/byte_data.rb +36 -0
- data/lib/dcc/base/calibration_laboratory.rb +29 -0
- data/lib/dcc/base/comment.rb +23 -0
- data/lib/dcc/base/condition.rb +34 -0
- data/lib/dcc/base/contact.rb +38 -0
- data/lib/dcc/base/contact_not_strict.rb +38 -0
- data/lib/dcc/base/core_data.rb +44 -0
- data/lib/dcc/base/data.rb +42 -0
- data/lib/dcc/base/digital_calibration_certificate.rb +32 -0
- data/lib/dcc/base/equipment_class.rb +24 -0
- data/lib/dcc/base/formula.rb +33 -0
- data/lib/dcc/base/hash_type.rb +34 -0
- data/lib/dcc/base/identification.rb +27 -0
- data/lib/dcc/base/identifications.rb +27 -0
- data/lib/dcc/base/influence_condition.rb +16 -0
- data/lib/dcc/base/influence_condition_list.rb +40 -0
- data/lib/dcc/base/item.rb +38 -0
- data/lib/dcc/base/item_list.rb +38 -0
- data/lib/dcc/base/list.rb +44 -0
- data/lib/dcc/base/location.rb +36 -0
- data/lib/dcc/base/measurement_meta_data.rb +15 -0
- data/lib/dcc/base/measurement_meta_data_list.rb +27 -0
- data/lib/dcc/base/measurement_result.rb +41 -0
- data/lib/dcc/base/measurement_result_list.rb +28 -0
- data/lib/dcc/base/measuring_equipment.rb +41 -0
- data/lib/dcc/base/measuring_equipment_list.rb +38 -0
- data/lib/dcc/base/quantity.rb +61 -0
- data/lib/dcc/base/ref_type_definition.rb +36 -0
- data/lib/dcc/base/ref_type_definition_list.rb +21 -0
- data/lib/dcc/base/resp_person.rb +38 -0
- data/lib/dcc/base/resp_person_list.rb +27 -0
- data/lib/dcc/base/result.rb +31 -0
- data/lib/dcc/base/result_list.rb +27 -0
- data/lib/dcc/base/rich_content.rb +34 -0
- data/lib/dcc/base/software.rb +35 -0
- data/lib/dcc/base/software_list.rb +27 -0
- data/lib/dcc/base/statement.rb +50 -0
- data/lib/dcc/base/statement_list.rb +27 -0
- data/lib/dcc/base/string_with_lang.rb +24 -0
- data/lib/dcc/base/text.rb +33 -0
- data/lib/dcc/base/used_method.rb +31 -0
- data/lib/dcc/base/used_method_list.rb +27 -0
- data/lib/dcc/base/xml_blob.rb +20 -0
- data/lib/dcc/base.rb +58 -0
- data/lib/dcc/builder/dsl.rb +10 -0
- data/lib/dcc/builder/session.rb +170 -0
- data/lib/dcc/builder.rb +34 -0
- data/lib/dcc/cli/cli.rb +149 -0
- data/lib/dcc/cli/formatters.rb +77 -0
- data/lib/dcc/cli.rb +7 -0
- data/lib/dcc/common_elements.rb +20 -0
- data/lib/dcc/context_configuration.rb +167 -0
- data/lib/dcc/context_options.rb +47 -0
- data/lib/dcc/convert/csv.rb +129 -0
- data/lib/dcc/convert/html.rb +127 -0
- data/lib/dcc/convert/json.rb +62 -0
- data/lib/dcc/convert/result.rb +51 -0
- data/lib/dcc/convert/yaml.rb +21 -0
- data/lib/dcc/convert.rb +14 -0
- data/lib/dcc/diff/change.rb +21 -0
- data/lib/dcc/diff/result.rb +58 -0
- data/lib/dcc/diff.rb +83 -0
- data/lib/dcc/error.rb +54 -0
- data/lib/dcc/extract/file.rb +143 -0
- data/lib/dcc/extract/ring.rb +28 -0
- data/lib/dcc/extract.rb +9 -0
- data/lib/dcc/i18n/text_lookup.rb +67 -0
- data/lib/dcc/i18n.rb +12 -0
- data/lib/dcc/inspect/report.rb +139 -0
- data/lib/dcc/inspect.rb +9 -0
- data/lib/dcc/migrate.rb +41 -0
- data/lib/dcc/namespace/dcc.rb +30 -0
- data/lib/dcc/namespace/dsig.rb +15 -0
- data/lib/dcc/namespace/math_ml.rb +14 -0
- data/lib/dcc/namespace/qudt.rb +15 -0
- data/lib/dcc/namespace/si.rb +26 -0
- data/lib/dcc/namespace.rb +18 -0
- data/lib/dcc/plugin/registry.rb +45 -0
- data/lib/dcc/plugin.rb +42 -0
- data/lib/dcc/quantity_format/formatter.rb +90 -0
- data/lib/dcc/quantity_format.rb +10 -0
- data/lib/dcc/quantity_math/quantity.rb +46 -0
- data/lib/dcc/quantity_math/real.rb +116 -0
- data/lib/dcc/quantity_math.rb +14 -0
- data/lib/dcc/schema/resources/dcc/dsi/v1.0.1.xsd +415 -0
- data/lib/dcc/schema/resources/dcc/dsi/v1.3.0.xsd +814 -0
- data/lib/dcc/schema/resources/dcc/dsi/v1.3.1.xsd +814 -0
- data/lib/dcc/schema/resources/dcc/dsi/v2.0.0.xsd +869 -0
- data/lib/dcc/schema/resources/dcc/dsi/v2.1.0.xsd +1031 -0
- data/lib/dcc/schema/resources/dcc/dsi/v2.2.1.xsd +1574 -0
- data/lib/dcc/schema/resources/dcc/qudt/v2.2.1.xsd +44 -0
- data/lib/dcc/schema/resources/dcc/v2.1.0/dcc.xsd +650 -0
- data/lib/dcc/schema/resources/dcc/v2.1.1/dcc.xsd +669 -0
- data/lib/dcc/schema/resources/dcc/v2.2.0/dcc.xsd +730 -0
- data/lib/dcc/schema/resources/dcc/v2.3.0/dcc.xsd +708 -0
- data/lib/dcc/schema/resources/dcc/v2.4.0/dcc.xsd +725 -0
- data/lib/dcc/schema/resources/dcc/v3.0.0/dcc.xsd +749 -0
- data/lib/dcc/schema/resources/dcc/v3.1.0/dcc.xsd +843 -0
- data/lib/dcc/schema/resources/dcc/v3.1.1/dcc.xsd +843 -0
- data/lib/dcc/schema/resources/dcc/v3.1.2/dcc.xsd +844 -0
- data/lib/dcc/schema/resources/dcc/v3.2.0/dcc.xsd +940 -0
- data/lib/dcc/schema/resources/dcc/v3.2.1/dcc.xsd +963 -0
- data/lib/dcc/schema/resources/dcc/v3.3.0/dcc.xsd +1008 -0
- data/lib/dcc/schema/resources/dcc/xmldsig-core-schema.xsd +312 -0
- data/lib/dcc/schema/resources/dsi/qudt/v2.2.1.xsd +44 -0
- data/lib/dcc/schema/resources/dsi/v1.0.1/SI_Format.xsd +415 -0
- data/lib/dcc/schema/resources/dsi/v1.3.0/SI_Format.xsd +814 -0
- data/lib/dcc/schema/resources/dsi/v1.3.1/SI_Format.xsd +814 -0
- data/lib/dcc/schema/resources/dsi/v2.0.0/SI_Format.xsd +869 -0
- data/lib/dcc/schema/resources/dsi/v2.1.0/SI_Format.xsd +1031 -0
- data/lib/dcc/schema/resources/dsi/v2.2.1/SI_Format.xsd +1574 -0
- data/lib/dcc/schema/resources/qudt/qudt.xsd +44 -0
- data/lib/dcc/schema/resources/schematron/dcc.sch +523 -0
- data/lib/dcc/schema/resources/schematron/dcc.svrl +2302 -0
- data/lib/dcc/schema/resources/xmldsig/xmldsig-core-schema.xsd +312 -0
- data/lib/dcc/schema/version.rb +94 -0
- data/lib/dcc/schema.rb +35 -0
- data/lib/dcc/server/app.rb +133 -0
- data/lib/dcc/server/storage/entry.rb +15 -0
- data/lib/dcc/server/storage/memory.rb +57 -0
- data/lib/dcc/server/storage.rb +13 -0
- data/lib/dcc/server.rb +33 -0
- data/lib/dcc/si/base/complex.rb +43 -0
- data/lib/dcc/si/base/complex_list_xml_list.rb +39 -0
- data/lib/dcc/si/base/constant.rb +39 -0
- data/lib/dcc/si/base/coverage_interval_mu.rb +31 -0
- data/lib/dcc/si/base/expanded_mu.rb +29 -0
- data/lib/dcc/si/base/expanded_unc_xml_list.rb +30 -0
- data/lib/dcc/si/base/hybrid.rb +42 -0
- data/lib/dcc/si/base/measurement_uncertainty_univariate.rb +28 -0
- data/lib/dcc/si/base/real.rb +48 -0
- data/lib/dcc/si/base/real_list_xml_list.rb +45 -0
- data/lib/dcc/si/base/si_list.rb +37 -0
- data/lib/dcc/si/base/standard_mu.rb +25 -0
- data/lib/dcc/si/base.rb +24 -0
- data/lib/dcc/si/common_elements.rb +13 -0
- data/lib/dcc/si/namespace.rb +7 -0
- data/lib/dcc/si/v1/common_elements.rb +13 -0
- data/lib/dcc/si/v1/complex.rb +8 -0
- data/lib/dcc/si/v1/complex_list_xml_list.rb +8 -0
- data/lib/dcc/si/v1/configuration.rb +13 -0
- data/lib/dcc/si/v1/constant.rb +8 -0
- data/lib/dcc/si/v1/coverage_interval_mu.rb +8 -0
- data/lib/dcc/si/v1/expanded_mu.rb +8 -0
- data/lib/dcc/si/v1/expanded_unc.rb +23 -0
- data/lib/dcc/si/v1/expanded_unc_xml_list.rb +8 -0
- data/lib/dcc/si/v1/hybrid.rb +8 -0
- data/lib/dcc/si/v1/measurement_uncertainty_univariate.rb +8 -0
- data/lib/dcc/si/v1/namespace.rb +9 -0
- data/lib/dcc/si/v1/real.rb +8 -0
- data/lib/dcc/si/v1/real_list_xml_list.rb +8 -0
- data/lib/dcc/si/v1/si_list.rb +8 -0
- data/lib/dcc/si/v1/standard_mu.rb +8 -0
- data/lib/dcc/si/v1.rb +46 -0
- data/lib/dcc/si/v2/common_elements.rb +13 -0
- data/lib/dcc/si/v2/complex.rb +8 -0
- data/lib/dcc/si/v2/complex_list_xml_list.rb +8 -0
- data/lib/dcc/si/v2/configuration.rb +13 -0
- data/lib/dcc/si/v2/constant.rb +8 -0
- data/lib/dcc/si/v2/coverage_interval_mu.rb +8 -0
- data/lib/dcc/si/v2/coverage_interval_mu_xml_list.rb +24 -0
- data/lib/dcc/si/v2/expanded_mu.rb +8 -0
- data/lib/dcc/si/v2/expanded_mu_xml_list.rb +22 -0
- data/lib/dcc/si/v2/expanded_unc_xml_list.rb +8 -0
- data/lib/dcc/si/v2/hybrid.rb +8 -0
- data/lib/dcc/si/v2/measurement_uncertainty_univariate.rb +8 -0
- data/lib/dcc/si/v2/namespace.rb +9 -0
- data/lib/dcc/si/v2/real.rb +8 -0
- data/lib/dcc/si/v2/real_list_xml_list.rb +8 -0
- data/lib/dcc/si/v2/si_list.rb +8 -0
- data/lib/dcc/si/v2/standard_mu.rb +8 -0
- data/lib/dcc/si/v2/standard_mu_xml_list.rb +18 -0
- data/lib/dcc/si/v2.rb +49 -0
- data/lib/dcc/si.rb +34 -0
- data/lib/dcc/signature/result.rb +43 -0
- data/lib/dcc/signature/signer.rb +36 -0
- data/lib/dcc/signature/verifier.rb +41 -0
- data/lib/dcc/signature.rb +13 -0
- data/lib/dcc/transform/result.rb +24 -0
- data/lib/dcc/transform/xslt.rb +72 -0
- data/lib/dcc/transform.rb +12 -0
- data/lib/dcc/type/base64_binary.rb +55 -0
- data/lib/dcc/type/decimal_xml_list.rb +47 -0
- data/lib/dcc/type/iso_country_code.rb +23 -0
- data/lib/dcc/type/iso_language_code.rb +23 -0
- data/lib/dcc/type/schema_version.rb +37 -0
- data/lib/dcc/type/si_unit.rb +26 -0
- data/lib/dcc/type.rb +16 -0
- data/lib/dcc/type_guards.rb +140 -0
- data/lib/dcc/v2/administrative_data.rb +8 -0
- data/lib/dcc/v2/byte_data.rb +8 -0
- data/lib/dcc/v2/calibration_laboratory.rb +8 -0
- data/lib/dcc/v2/comment.rb +8 -0
- data/lib/dcc/v2/common_elements.rb +13 -0
- data/lib/dcc/v2/condition.rb +8 -0
- data/lib/dcc/v2/configuration.rb +17 -0
- data/lib/dcc/v2/contact.rb +8 -0
- data/lib/dcc/v2/contact_not_strict.rb +8 -0
- data/lib/dcc/v2/core_data.rb +8 -0
- data/lib/dcc/v2/data.rb +8 -0
- data/lib/dcc/v2/digital_calibration_certificate.rb +8 -0
- data/lib/dcc/v2/equipment_class.rb +8 -0
- data/lib/dcc/v2/formula.rb +8 -0
- data/lib/dcc/v2/hash_type.rb +8 -0
- data/lib/dcc/v2/identification.rb +8 -0
- data/lib/dcc/v2/identifications.rb +8 -0
- data/lib/dcc/v2/influence_condition.rb +7 -0
- data/lib/dcc/v2/influence_condition_list.rb +8 -0
- data/lib/dcc/v2/item.rb +8 -0
- data/lib/dcc/v2/item_list.rb +8 -0
- data/lib/dcc/v2/list.rb +8 -0
- data/lib/dcc/v2/location.rb +8 -0
- data/lib/dcc/v2/measurement_meta_data.rb +8 -0
- data/lib/dcc/v2/measurement_meta_data_list.rb +8 -0
- data/lib/dcc/v2/measurement_result.rb +8 -0
- data/lib/dcc/v2/measurement_result_list.rb +8 -0
- data/lib/dcc/v2/measuring_equipment.rb +8 -0
- data/lib/dcc/v2/measuring_equipment_list.rb +8 -0
- data/lib/dcc/v2/namespace.rb +8 -0
- data/lib/dcc/v2/quantity.rb +49 -0
- data/lib/dcc/v2/ref_type_definition.rb +11 -0
- data/lib/dcc/v2/ref_type_definition_list.rb +15 -0
- data/lib/dcc/v2/resp_person.rb +8 -0
- data/lib/dcc/v2/resp_person_list.rb +8 -0
- data/lib/dcc/v2/result.rb +8 -0
- data/lib/dcc/v2/result_list.rb +8 -0
- data/lib/dcc/v2/rich_content.rb +12 -0
- data/lib/dcc/v2/software.rb +8 -0
- data/lib/dcc/v2/software_list.rb +8 -0
- data/lib/dcc/v2/statement.rb +8 -0
- data/lib/dcc/v2/statement_list.rb +8 -0
- data/lib/dcc/v2/string_with_lang.rb +8 -0
- data/lib/dcc/v2/text.rb +8 -0
- data/lib/dcc/v2/used_method.rb +8 -0
- data/lib/dcc/v2/used_method_list.rb +8 -0
- data/lib/dcc/v2/xml_blob.rb +8 -0
- data/lib/dcc/v2.rb +84 -0
- data/lib/dcc/v3/administrative_data.rb +8 -0
- data/lib/dcc/v3/byte_data.rb +8 -0
- data/lib/dcc/v3/calibration_laboratory.rb +8 -0
- data/lib/dcc/v3/comment.rb +8 -0
- data/lib/dcc/v3/common_elements.rb +11 -0
- data/lib/dcc/v3/condition.rb +8 -0
- data/lib/dcc/v3/configuration.rb +17 -0
- data/lib/dcc/v3/contact.rb +8 -0
- data/lib/dcc/v3/contact_not_strict.rb +8 -0
- data/lib/dcc/v3/core_data.rb +8 -0
- data/lib/dcc/v3/data.rb +8 -0
- data/lib/dcc/v3/digital_calibration_certificate.rb +8 -0
- data/lib/dcc/v3/equipment_class.rb +8 -0
- data/lib/dcc/v3/formula.rb +8 -0
- data/lib/dcc/v3/hash_type.rb +8 -0
- data/lib/dcc/v3/identification.rb +8 -0
- data/lib/dcc/v3/identifications.rb +8 -0
- data/lib/dcc/v3/influence_condition.rb +7 -0
- data/lib/dcc/v3/influence_condition_list.rb +8 -0
- data/lib/dcc/v3/item.rb +8 -0
- data/lib/dcc/v3/item_list.rb +8 -0
- data/lib/dcc/v3/list.rb +8 -0
- data/lib/dcc/v3/location.rb +8 -0
- data/lib/dcc/v3/measurement_meta_data.rb +8 -0
- data/lib/dcc/v3/measurement_meta_data_list.rb +8 -0
- data/lib/dcc/v3/measurement_result.rb +8 -0
- data/lib/dcc/v3/measurement_result_list.rb +8 -0
- data/lib/dcc/v3/measuring_equipment.rb +8 -0
- data/lib/dcc/v3/measuring_equipment_list.rb +8 -0
- data/lib/dcc/v3/namespace.rb +7 -0
- data/lib/dcc/v3/quantity.rb +49 -0
- data/lib/dcc/v3/ref_type_definition.rb +8 -0
- data/lib/dcc/v3/ref_type_definition_list.rb +8 -0
- data/lib/dcc/v3/resp_person.rb +8 -0
- data/lib/dcc/v3/resp_person_list.rb +8 -0
- data/lib/dcc/v3/result.rb +8 -0
- data/lib/dcc/v3/result_list.rb +8 -0
- data/lib/dcc/v3/rich_content.rb +8 -0
- data/lib/dcc/v3/software.rb +8 -0
- data/lib/dcc/v3/software_list.rb +8 -0
- data/lib/dcc/v3/statement.rb +8 -0
- data/lib/dcc/v3/statement_list.rb +8 -0
- data/lib/dcc/v3/string_with_lang.rb +8 -0
- data/lib/dcc/v3/text.rb +8 -0
- data/lib/dcc/v3/used_method.rb +8 -0
- data/lib/dcc/v3/used_method_list.rb +8 -0
- data/lib/dcc/v3/xml_blob.rb +8 -0
- data/lib/dcc/v3.rb +111 -0
- data/lib/dcc/validate/business_rules.rb +121 -0
- data/lib/dcc/validate/issue.rb +56 -0
- data/lib/dcc/validate/result.rb +105 -0
- data/lib/dcc/validate/schematron/profile.rb +64 -0
- data/lib/dcc/validate/schematron/rule.rb +49 -0
- data/lib/dcc/validate/schematron/rules/administrative_data_completeness.rb +42 -0
- data/lib/dcc/validate/schematron/rules/base.rb +15 -0
- data/lib/dcc/validate/schematron/rules/date_range_check.rb +41 -0
- data/lib/dcc/validate/schematron/rules/id_refid_linking.rb +61 -0
- data/lib/dcc/validate/schematron/rules/influence_conditions_placement.rb +58 -0
- data/lib/dcc/validate/schematron/rules/iso_code_validation.rb +53 -0
- data/lib/dcc/validate/schematron/rules/language_code_dedup.rb +39 -0
- data/lib/dcc/validate/schematron/rules/non_si_declaration.rb +82 -0
- data/lib/dcc/validate/schematron/rules/release_format_check.rb +44 -0
- data/lib/dcc/validate/schematron/rules/schema_version_check.rb +31 -0
- data/lib/dcc/validate/schematron/rules/uncertainty_consistency.rb +58 -0
- data/lib/dcc/validate/schematron/rules/unit_format_check.rb +74 -0
- data/lib/dcc/validate/schematron/rules/used_methods_placement.rb +65 -0
- data/lib/dcc/validate/schematron/rules/used_software_placement.rb +43 -0
- data/lib/dcc/validate/schematron/rules/xml_list_spacing.rb +42 -0
- data/lib/dcc/validate/schematron/rules.rb +30 -0
- data/lib/dcc/validate/schematron.rb +22 -0
- data/lib/dcc/validate/severity.rb +39 -0
- data/lib/dcc/validate/xsd.rb +97 -0
- data/lib/dcc/validate.rb +15 -0
- data/lib/dcc/version.rb +5 -0
- data/lib/dcc/versioned_parser.rb +48 -0
- data/lib/dcc.rb +141 -0
- metadata +425 -0
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "lutaml/model"
|
|
4
|
+
|
|
5
|
+
module Dcc
|
|
6
|
+
module Validate
|
|
7
|
+
module Schematron
|
|
8
|
+
# Base class for Schematron rules. Subclasses implement `#check_on(dcc)`
|
|
9
|
+
# returning an array of `Dcc::Validate::Issue` records.
|
|
10
|
+
class Rule
|
|
11
|
+
# @return [Symbol] severity for issues this rule produces.
|
|
12
|
+
def severity
|
|
13
|
+
::Dcc::Validate::Severity::ERROR
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# @return [String] rule code used in `Issue#code`.
|
|
17
|
+
def code
|
|
18
|
+
"dcc.schematron.#{self.class.name.split('::').last.gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2').gsub(/([a-z\d])([A-Z])/, '\1_\2').downcase}"
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# @param dcc [Lutaml::Model::Serializable]
|
|
22
|
+
# @return [Array<Dcc::Validate::Issue>]
|
|
23
|
+
def check_on(dcc)
|
|
24
|
+
issues = []
|
|
25
|
+
walk(dcc, issues)
|
|
26
|
+
issues
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
protected
|
|
30
|
+
|
|
31
|
+
def walk(_node, _issues)
|
|
32
|
+
# Override in subclasses to traverse the model tree.
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def issue(severity:, message:, line: nil, column: nil, path: nil, source: "schematron")
|
|
36
|
+
::Dcc::Validate::Issue.build(
|
|
37
|
+
severity: severity,
|
|
38
|
+
message: message,
|
|
39
|
+
code: code,
|
|
40
|
+
line: line,
|
|
41
|
+
column: column,
|
|
42
|
+
path: path,
|
|
43
|
+
source: source,
|
|
44
|
+
)
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Dcc
|
|
4
|
+
module Validate
|
|
5
|
+
module Schematron
|
|
6
|
+
module Rules
|
|
7
|
+
# Validates that all required sections are present in
|
|
8
|
+
# `dcc:administrativeData`: dccSoftware, coreData, items,
|
|
9
|
+
# calibrationLaboratory, respPersons, customer.
|
|
10
|
+
class AdministrativeDataCompleteness < Base
|
|
11
|
+
REQUIRED_SECTIONS = {
|
|
12
|
+
dcc_software: "dccSoftware",
|
|
13
|
+
core_data: "coreData",
|
|
14
|
+
items: "items",
|
|
15
|
+
calibration_laboratory: "calibrationLaboratory",
|
|
16
|
+
resp_persons: "respPersons",
|
|
17
|
+
customer: "customer",
|
|
18
|
+
}.freeze
|
|
19
|
+
|
|
20
|
+
def check_on(dcc)
|
|
21
|
+
issues = []
|
|
22
|
+
return issues unless Dcc::TypeGuards.has_attribute?(dcc, :administrative_data)
|
|
23
|
+
|
|
24
|
+
admin = dcc.administrative_data
|
|
25
|
+
return [issue(severity: :error, message: "administrativeData is missing")] unless admin
|
|
26
|
+
|
|
27
|
+
REQUIRED_SECTIONS.each do |attr, label|
|
|
28
|
+
value = Dcc::TypeGuards.has_attribute?(admin, attr) ? admin.public_send(attr) : nil
|
|
29
|
+
next unless value.nil? || ((value.is_a?(::String) || value.is_a?(::Array)) && value.empty?)
|
|
30
|
+
|
|
31
|
+
issues << issue(
|
|
32
|
+
severity: :error,
|
|
33
|
+
message: "dcc:administrativeData/#{label} is missing",
|
|
34
|
+
)
|
|
35
|
+
end
|
|
36
|
+
issues
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
module Dcc
|
|
5
|
+
module Validate
|
|
6
|
+
module Schematron
|
|
7
|
+
module Rules
|
|
8
|
+
# Schematron rule base. Concrete rules subclass this and implement
|
|
9
|
+
# `#check_on(dcc)`. Each subclass declares its `severity`.
|
|
10
|
+
class Base < ::Dcc::Validate::Schematron::Rule
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
module Dcc
|
|
5
|
+
module Validate
|
|
6
|
+
module Schematron
|
|
7
|
+
module Rules
|
|
8
|
+
# Errors if `endPerformanceDate` precedes `beginPerformanceDate`.
|
|
9
|
+
class DateRangeCheck < Base
|
|
10
|
+
def check_on(dcc)
|
|
11
|
+
return [] unless Dcc::TypeGuards.has_attribute?(dcc, :administrative_data)
|
|
12
|
+
|
|
13
|
+
core = safe_attr(dcc.administrative_data, :core_data)
|
|
14
|
+
return [] if core.nil?
|
|
15
|
+
|
|
16
|
+
begin_d = Dcc::TypeGuards.has_attribute?(core, :begin_performance_date) ? core.begin_performance_date : nil
|
|
17
|
+
end_d = Dcc::TypeGuards.has_attribute?(core, :end_performance_date) ? core.end_performance_date : nil
|
|
18
|
+
|
|
19
|
+
return [] if begin_d.nil? || end_d.nil?
|
|
20
|
+
return [] unless end_d < begin_d
|
|
21
|
+
|
|
22
|
+
[
|
|
23
|
+
issue(
|
|
24
|
+
severity: :error,
|
|
25
|
+
message: "endPerformanceDate (#{end_d}) precedes beginPerformanceDate (#{begin_d})",
|
|
26
|
+
),
|
|
27
|
+
]
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
private
|
|
31
|
+
|
|
32
|
+
def safe_attr(parent, attr)
|
|
33
|
+
return nil unless parent && parent.is_a?(::Lutaml::Model::Serializable) && parent.class.attributes.key?(attr)
|
|
34
|
+
|
|
35
|
+
parent.public_send(attr)
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
module Dcc
|
|
5
|
+
module Validate
|
|
6
|
+
module Schematron
|
|
7
|
+
module Rules
|
|
8
|
+
# Validates that every `@id` on a DCC element has a matching `@refId`
|
|
9
|
+
# reference and vice versa.
|
|
10
|
+
class IdRefIdLinking < Base
|
|
11
|
+
def check_on(dcc)
|
|
12
|
+
issues = []
|
|
13
|
+
ids = ::Set.new
|
|
14
|
+
ref_ids = ::Set.new
|
|
15
|
+
|
|
16
|
+
collect(dcc, ids, ref_ids)
|
|
17
|
+
|
|
18
|
+
unused_ids = ids - ref_ids
|
|
19
|
+
unused_ids.each do |id|
|
|
20
|
+
issues << issue(
|
|
21
|
+
severity: :warning,
|
|
22
|
+
message: "@id '#{id}' is never referenced by any @refId",
|
|
23
|
+
)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
dangling = ref_ids - ids
|
|
27
|
+
dangling.each do |rid|
|
|
28
|
+
issues << issue(
|
|
29
|
+
severity: :error,
|
|
30
|
+
message: "@refId '#{rid}' does not match any @id",
|
|
31
|
+
)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
issues
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
private
|
|
38
|
+
|
|
39
|
+
def collect(node, ids, ref_ids)
|
|
40
|
+
return unless node.is_a?(::Lutaml::Model::Serializable)
|
|
41
|
+
|
|
42
|
+
id = node.respond_to?(:id) ? node.id : nil
|
|
43
|
+
ids << id if id && !id.empty?
|
|
44
|
+
|
|
45
|
+
ref_id = node.respond_to?(:ref_id) ? node.ref_id : nil
|
|
46
|
+
if ref_id && !ref_id.empty?
|
|
47
|
+
ref_id.split(/\s+/).each { |r| ref_ids << r }
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
node.class.attributes.each_key do |attr|
|
|
51
|
+
value = node.public_send(attr)
|
|
52
|
+
Array(value).each { |c| collect(c, ids, ref_ids) }
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
require "set"
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
module Dcc
|
|
5
|
+
module Validate
|
|
6
|
+
module Schematron
|
|
7
|
+
module Rules
|
|
8
|
+
# `dcc:influenceConditions` must appear somewhere (global, list, or
|
|
9
|
+
# quantity level). Error if missing.
|
|
10
|
+
class InfluenceConditionsPlacement < Base
|
|
11
|
+
def check_on(dcc)
|
|
12
|
+
return [] unless Dcc::TypeGuards.has_attribute?(dcc, :measurement_results)
|
|
13
|
+
|
|
14
|
+
mr_list = safe_attr(dcc.measurement_results, :measurement_result)
|
|
15
|
+
return [] if mr_list.empty?
|
|
16
|
+
|
|
17
|
+
any_present = mr_list.any? do |mr|
|
|
18
|
+
next false unless Dcc::TypeGuards.has_attribute?(mr, :influence_conditions)
|
|
19
|
+
next true unless mr.influence_conditions.nil?
|
|
20
|
+
|
|
21
|
+
Dcc::TypeGuards.has_attribute?(mr, :results) && mr.results &&
|
|
22
|
+
has_in_descendants?(mr.results)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
any_present ? [] : [
|
|
26
|
+
issue(
|
|
27
|
+
severity: :error,
|
|
28
|
+
message: "dcc:influenceConditions is missing everywhere",
|
|
29
|
+
),
|
|
30
|
+
]
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
private
|
|
34
|
+
|
|
35
|
+
def has_in_descendants?(node)
|
|
36
|
+
return false unless node.is_a?(::Lutaml::Model::Serializable)
|
|
37
|
+
|
|
38
|
+
if Dcc::TypeGuards.has_attribute?(node, :influence_conditions) && !node.influence_conditions.nil?
|
|
39
|
+
return true
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
node.class.attributes.each_key do |attr|
|
|
43
|
+
value = node.public_send(attr)
|
|
44
|
+
Array(value).any? { |c| has_in_descendants?(c) } if value.is_a?(::Array) || value.is_a?(::Lutaml::Model::Serializable)
|
|
45
|
+
end
|
|
46
|
+
false
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def safe_attr(parent, attr)
|
|
50
|
+
return [] unless parent && parent.is_a?(::Lutaml::Model::Serializable) && parent.class.attributes.key?(attr)
|
|
51
|
+
|
|
52
|
+
Array(parent.public_send(attr))
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
module Dcc
|
|
5
|
+
module Validate
|
|
6
|
+
module Schematron
|
|
7
|
+
module Rules
|
|
8
|
+
# Validates ISO 3166-1 (country) and ISO 639-1 (language) codes used
|
|
9
|
+
# in coreData. Custom type casts already enforce format; here we only
|
|
10
|
+
# flag empties that escaped earlier casts.
|
|
11
|
+
class IsoCodeValidation < Base
|
|
12
|
+
def check_on(dcc)
|
|
13
|
+
return [] unless Dcc::TypeGuards.has_attribute?(dcc, :administrative_data)
|
|
14
|
+
|
|
15
|
+
core = safe_attr(dcc.administrative_data, :core_data)
|
|
16
|
+
return [] if core.nil?
|
|
17
|
+
|
|
18
|
+
issues = []
|
|
19
|
+
country = Dcc::TypeGuards.has_attribute?(core, :country_code_iso_3166_1) ? core.country_code_iso_3166_1 : nil
|
|
20
|
+
if country.nil? || country.to_s.empty?
|
|
21
|
+
issues << issue(
|
|
22
|
+
severity: :error,
|
|
23
|
+
message: "dcc:countryCodeISO3166_1 is missing",
|
|
24
|
+
)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
used = Dcc::TypeGuards.has_attribute?(core, :used_lang_code_iso_639_1) ? Array(core.used_lang_code_iso_639_1) : []
|
|
28
|
+
issues << issue(
|
|
29
|
+
severity: :error,
|
|
30
|
+
message: "dcc:usedLangCodeISO639_1 must have at least one entry",
|
|
31
|
+
) if used.empty?
|
|
32
|
+
|
|
33
|
+
mandatory = Dcc::TypeGuards.has_attribute?(core, :mandatory_lang_code_iso_639_1) ? Array(core.mandatory_lang_code_iso_639_1) : []
|
|
34
|
+
issues << issue(
|
|
35
|
+
severity: :error,
|
|
36
|
+
message: "dcc:mandatoryLangCodeISO639_1 must have at least one entry",
|
|
37
|
+
) if mandatory.empty?
|
|
38
|
+
|
|
39
|
+
issues
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
private
|
|
43
|
+
|
|
44
|
+
def safe_attr(parent, attr)
|
|
45
|
+
return nil unless parent && parent.is_a?(::Lutaml::Model::Serializable) && parent.class.attributes.key?(attr)
|
|
46
|
+
|
|
47
|
+
parent.public_send(attr)
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
module Dcc
|
|
5
|
+
module Validate
|
|
6
|
+
module Schematron
|
|
7
|
+
module Rules
|
|
8
|
+
# Errors on duplicate language codes in `dcc:usedLangCodeISO639_1`.
|
|
9
|
+
class LanguageCodeDedup < Base
|
|
10
|
+
def check_on(dcc)
|
|
11
|
+
return [] unless Dcc::TypeGuards.has_attribute?(dcc, :administrative_data)
|
|
12
|
+
|
|
13
|
+
core = safe_attr(dcc.administrative_data, :core_data)
|
|
14
|
+
return [] if core.nil?
|
|
15
|
+
|
|
16
|
+
used = Dcc::TypeGuards.has_attribute?(core, :used_lang_code_iso_639_1) ? Array(core.used_lang_code_iso_639_1) : []
|
|
17
|
+
used_strings = used.map(&:to_s)
|
|
18
|
+
duplicates = used_strings.group_by(&:itself).select { |_k, v| v.size > 1 }.keys
|
|
19
|
+
|
|
20
|
+
duplicates.map do |dup|
|
|
21
|
+
issue(
|
|
22
|
+
severity: :error,
|
|
23
|
+
message: "dcc:usedLangCodeISO639_1 contains duplicate '#{dup}'",
|
|
24
|
+
)
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
private
|
|
29
|
+
|
|
30
|
+
def safe_attr(parent, attr)
|
|
31
|
+
return nil unless parent && parent.is_a?(::Lutaml::Model::Serializable) && parent.class.attributes.key?(attr)
|
|
32
|
+
|
|
33
|
+
parent.public_send(attr)
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Dcc
|
|
4
|
+
module Validate
|
|
5
|
+
module Schematron
|
|
6
|
+
module Rules
|
|
7
|
+
# Validates that non-SI units (prefixed with `|`) are declared
|
|
8
|
+
# somewhere in the DCC via `dcc:nonSIUnit` and `dcc:nonSIDefinition`
|
|
9
|
+
# elements inside `dcc:statement`.
|
|
10
|
+
class NonSiDeclaration < Base
|
|
11
|
+
def check_on(dcc)
|
|
12
|
+
issues = []
|
|
13
|
+
return issues unless dcc.is_a?(::Lutaml::Model::Serializable)
|
|
14
|
+
|
|
15
|
+
declared_units = collect_declared_non_si_units(dcc, ::Set.new)
|
|
16
|
+
used_units = ::Set.new
|
|
17
|
+
walk_for_used_units(dcc, used_units, ::Set.new)
|
|
18
|
+
|
|
19
|
+
(used_units - declared_units).each do |unit|
|
|
20
|
+
issues << issue(
|
|
21
|
+
severity: :error,
|
|
22
|
+
message: "non-SI unit '#{unit}' is used but not declared in dcc:nonSIUnit",
|
|
23
|
+
)
|
|
24
|
+
end
|
|
25
|
+
issues
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
private
|
|
29
|
+
|
|
30
|
+
def collect_declared_non_si_units(node, visited)
|
|
31
|
+
return [].to_set unless node.is_a?(::Lutaml::Model::Serializable)
|
|
32
|
+
return [].to_set if visited.include?(node.object_id)
|
|
33
|
+
|
|
34
|
+
visited << node.object_id
|
|
35
|
+
declared = collect_from_node(node)
|
|
36
|
+
node.class.attributes.each_key do |attr_name|
|
|
37
|
+
value = node.public_send(attr_name)
|
|
38
|
+
Array(value).each do |child|
|
|
39
|
+
declared += collect_declared_non_si_units(child, visited) if child.is_a?(::Lutaml::Model::Serializable)
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
declared
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def collect_from_node(node)
|
|
46
|
+
return [].to_set unless node.respond_to?(:non_si_unit)
|
|
47
|
+
|
|
48
|
+
u = node.non_si_unit
|
|
49
|
+
u.to_s.empty? ? [].to_set : ::Set.new([u.to_s])
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def walk_for_used_units(node, accumulator, visited)
|
|
53
|
+
return unless node.is_a?(::Lutaml::Model::Serializable)
|
|
54
|
+
return if visited.include?(node.object_id)
|
|
55
|
+
|
|
56
|
+
visited << node.object_id
|
|
57
|
+
extract_non_si_unit(node, accumulator)
|
|
58
|
+
node.class.attributes.each_key do |attr_name|
|
|
59
|
+
value = node.public_send(attr_name)
|
|
60
|
+
Array(value).each { |child| walk_for_used_units(child, accumulator, visited) }
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def extract_non_si_unit(node, accumulator)
|
|
65
|
+
%i[unit unit_xml_list].each do |attr|
|
|
66
|
+
next unless Dcc::TypeGuards.has_attribute?(node, attr)
|
|
67
|
+
|
|
68
|
+
v = node.public_send(attr)
|
|
69
|
+
next if v.nil? || v.to_s.empty?
|
|
70
|
+
|
|
71
|
+
v.to_s.split(/\s+/).each do |tok|
|
|
72
|
+
accumulator << tok if tok.start_with?("|")
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
require "set"
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
module Dcc
|
|
5
|
+
module Validate
|
|
6
|
+
module Schematron
|
|
7
|
+
module Rules
|
|
8
|
+
# Validates `dcc:release` format: `^[a-zA-Z]{1}(\s)?([0-9]{1,3}\.){0,3}([0-9]{1,3})$`
|
|
9
|
+
class ReleaseFormatCheck < Base
|
|
10
|
+
PATTERN = /\A[a-zA-Z]{1} ?([0-9]{1,3}\.){0,3}[0-9]{1,3}\z/
|
|
11
|
+
|
|
12
|
+
def check_on(dcc)
|
|
13
|
+
issues = []
|
|
14
|
+
return issues unless Dcc::TypeGuards.has_attribute?(dcc, :administrative_data)
|
|
15
|
+
|
|
16
|
+
software_list = safe_attr(dcc.administrative_data, :dcc_software)
|
|
17
|
+
return issues if software_list.nil?
|
|
18
|
+
|
|
19
|
+
Array(safe_attr(software_list, :software)).each do |sw|
|
|
20
|
+
release = Dcc::TypeGuards.has_attribute?(sw, :release) ? sw.release : nil
|
|
21
|
+
next if release.nil? || release.empty?
|
|
22
|
+
next if release.match?(PATTERN)
|
|
23
|
+
|
|
24
|
+
issues << issue(
|
|
25
|
+
severity: :error,
|
|
26
|
+
message: "dcc:release '#{release}' does not match the expected format",
|
|
27
|
+
)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
issues
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
private
|
|
34
|
+
|
|
35
|
+
def safe_attr(parent, attr)
|
|
36
|
+
return nil unless parent && parent.is_a?(::Lutaml::Model::Serializable) && parent.class.attributes.key?(attr)
|
|
37
|
+
|
|
38
|
+
parent.public_send(attr)
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
module Dcc
|
|
5
|
+
module Validate
|
|
6
|
+
module Schematron
|
|
7
|
+
module Rules
|
|
8
|
+
# Warn when the schemaVersion is not the latest known release.
|
|
9
|
+
class SchemaVersionCheck < Base
|
|
10
|
+
def severity
|
|
11
|
+
::Dcc::Validate::Severity::WARNING
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def check_on(dcc)
|
|
15
|
+
return [] unless Dcc::TypeGuards.has_attribute?(dcc, :schema_version)
|
|
16
|
+
|
|
17
|
+
current = dcc.schema_version.to_s
|
|
18
|
+
latest = ::Dcc::Schema::Version::DCC_LATEST
|
|
19
|
+
|
|
20
|
+
current == latest ? [] : [
|
|
21
|
+
issue(
|
|
22
|
+
severity: :warning,
|
|
23
|
+
message: "schemaVersion '#{current}' is not the latest release (#{latest})",
|
|
24
|
+
),
|
|
25
|
+
]
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Dcc
|
|
4
|
+
module Validate
|
|
5
|
+
module Schematron
|
|
6
|
+
module Rules
|
|
7
|
+
# Validates that for every `si:realListXMLList` paired with an
|
|
8
|
+
# `si:expandedUncXMLList`, the count of values matches the count
|
|
9
|
+
# of uncertainty entries.
|
|
10
|
+
class UncertaintyConsistency < Base
|
|
11
|
+
def check_on(dcc)
|
|
12
|
+
issues = []
|
|
13
|
+
return issues unless dcc.is_a?(::Lutaml::Model::Serializable)
|
|
14
|
+
|
|
15
|
+
walk(dcc, issues, ::Set.new)
|
|
16
|
+
issues
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
private
|
|
20
|
+
|
|
21
|
+
def walk(node, issues, visited)
|
|
22
|
+
return unless node.is_a?(::Lutaml::Model::Serializable)
|
|
23
|
+
return if visited.include?(node.object_id)
|
|
24
|
+
|
|
25
|
+
visited << node.object_id
|
|
26
|
+
|
|
27
|
+
check_node(node, issues) if node.class.name.end_with?("::RealListXmlList")
|
|
28
|
+
descend(node, issues, visited)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def check_node(list_node, issues)
|
|
32
|
+
values = list_node.value_xml_list
|
|
33
|
+
unc = list_node.expanded_unc_xml_list
|
|
34
|
+
return unless unc && values
|
|
35
|
+
|
|
36
|
+
unc_count = Array(unc.uncertainty_xml_list).size
|
|
37
|
+
value_count = Array(values).size
|
|
38
|
+
return if unc_count == value_count || unc_count.zero?
|
|
39
|
+
|
|
40
|
+
issues << issue(
|
|
41
|
+
severity: :error,
|
|
42
|
+
message: "valueXMLList count (#{value_count}) does not match expandedUncertaintyXMLList count (#{unc_count})",
|
|
43
|
+
)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def descend(node, issues, visited)
|
|
47
|
+
node.class.attributes.each_key do |attr_name|
|
|
48
|
+
value = node.public_send(attr_name)
|
|
49
|
+
Array(value).each { |child| walk(child, issues, visited) }
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
require "set"
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Dcc
|
|
4
|
+
module Validate
|
|
5
|
+
module Schematron
|
|
6
|
+
module Rules
|
|
7
|
+
# Validates that SI unit expressions contain no whitespace and
|
|
8
|
+
# that `unitXMLList` element count matches `valueXMLList` count.
|
|
9
|
+
class UnitFormatCheck < Base
|
|
10
|
+
def check_on(dcc)
|
|
11
|
+
issues = []
|
|
12
|
+
return issues unless dcc.is_a?(::Lutaml::Model::Serializable)
|
|
13
|
+
|
|
14
|
+
walk(dcc, issues, ::Set.new)
|
|
15
|
+
issues
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
private
|
|
19
|
+
|
|
20
|
+
def walk(node, issues, visited)
|
|
21
|
+
return unless node.is_a?(::Lutaml::Model::Serializable)
|
|
22
|
+
return if visited.include?(node.object_id)
|
|
23
|
+
|
|
24
|
+
visited << node.object_id
|
|
25
|
+
|
|
26
|
+
check_single_unit(node, issues)
|
|
27
|
+
check_list_unit(node, issues)
|
|
28
|
+
descend(node, issues, visited)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def check_single_unit(node, issues)
|
|
32
|
+
return unless node.class.name.end_with?("::Real", "::Complex", "::Constant")
|
|
33
|
+
return unless node.respond_to?(:unit)
|
|
34
|
+
|
|
35
|
+
unit = node.unit
|
|
36
|
+
return unless unit && unit.to_s.match?(/\s/)
|
|
37
|
+
|
|
38
|
+
issues << issue(
|
|
39
|
+
severity: :error,
|
|
40
|
+
message: "si:unit '#{unit}' must not contain whitespace",
|
|
41
|
+
)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def check_list_unit(node, issues)
|
|
45
|
+
return unless node.class.name.end_with?("::RealListXmlList")
|
|
46
|
+
return unless node.respond_to?(:unit_xml_list)
|
|
47
|
+
|
|
48
|
+
unit_list = node.unit_xml_list
|
|
49
|
+
value_list = node.respond_to?(:value_xml_list) ? node.value_xml_list : nil
|
|
50
|
+
return unless unit_list && value_list
|
|
51
|
+
|
|
52
|
+
unit_count = unit_list.to_s.split(/\s+/).length
|
|
53
|
+
value_count = Array(value_list).length
|
|
54
|
+
return if unit_count == value_count || unit_count == 1
|
|
55
|
+
|
|
56
|
+
issues << issue(
|
|
57
|
+
severity: :error,
|
|
58
|
+
message: "unitXMLList count (#{unit_count}) does not match valueXMLList count (#{value_count})",
|
|
59
|
+
)
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def descend(node, issues, visited)
|
|
63
|
+
node.class.attributes.each_key do |attr_name|
|
|
64
|
+
value = node.public_send(attr_name)
|
|
65
|
+
Array(value).each { |child| walk(child, issues, visited) }
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
require "set"
|