svg_conform 0.1.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/.github/workflows/rake.yml +15 -0
- data/.github/workflows/release.yml +23 -0
- data/.github/workflows/svgcheck-compatibility.yml +135 -0
- data/.gitignore +12 -0
- data/.rspec +3 -0
- data/.rubocop.yml +13 -0
- data/.rubocop_todo.yml +183 -0
- data/CODE_OF_CONDUCT.md +132 -0
- data/Gemfile +14 -0
- data/README.adoc +1384 -0
- data/Rakefile +15 -0
- data/config/profiles/base.yml +34 -0
- data/config/profiles/lucid_fix.yml +37 -0
- data/config/profiles/metanorma.yml +212 -0
- data/config/profiles/no_external_css.yml +20 -0
- data/config/profiles/svg_1_2_rfc.yml +284 -0
- data/config/profiles/svg_1_2_rfc_with_rdf.yml +145 -0
- data/config/svgcheck_mapping.yml +180 -0
- data/docs/profiles.adoc +547 -0
- data/docs/rdf_metadata_support.adoc +212 -0
- data/docs/remediation.adoc +732 -0
- data/docs/requirements.adoc +709 -0
- data/examples/demo.rb +116 -0
- data/examples/requirements_demo.rb +240 -0
- data/exe/svg_conform +7 -0
- data/lib/svg_conform/batch_report.rb +70 -0
- data/lib/svg_conform/cli.rb +107 -0
- data/lib/svg_conform/commands/check.rb +390 -0
- data/lib/svg_conform/commands/profiles.rb +118 -0
- data/lib/svg_conform/commands/svgcheck.rb +90 -0
- data/lib/svg_conform/commands/svgcheck_compare.rb +92 -0
- data/lib/svg_conform/commands/svgcheck_compatibility.rb +43 -0
- data/lib/svg_conform/commands/svgcheck_generate.rb +262 -0
- data/lib/svg_conform/compatibility/analysis_context.rb +68 -0
- data/lib/svg_conform/compatibility/comparison_result.rb +147 -0
- data/lib/svg_conform/compatibility/compatibility_analyzer.rb +85 -0
- data/lib/svg_conform/compatibility/file_processor.rb +109 -0
- data/lib/svg_conform/compatibility/pattern_discovery.rb +319 -0
- data/lib/svg_conform/compatibility/report_formatter.rb +359 -0
- data/lib/svg_conform/compatibility/svg_analysis_engine.rb +316 -0
- data/lib/svg_conform/compatibility/validity_analysis.rb +252 -0
- data/lib/svg_conform/compatibility/xml_analysis_engine.rb +198 -0
- data/lib/svg_conform/compatibility_analyzer.rb +285 -0
- data/lib/svg_conform/conformance_report.rb +267 -0
- data/lib/svg_conform/constants.rb +199 -0
- data/lib/svg_conform/css_color.rb +262 -0
- data/lib/svg_conform/document.rb +203 -0
- data/lib/svg_conform/external_checkers/svgcheck/compatibility_engine.rb +166 -0
- data/lib/svg_conform/external_checkers/svgcheck/output_generator.rb +101 -0
- data/lib/svg_conform/external_checkers/svgcheck/parser.rb +200 -0
- data/lib/svg_conform/external_checkers/svgcheck/report_comparator.rb +175 -0
- data/lib/svg_conform/external_checkers/svgcheck/report_generator.rb +82 -0
- data/lib/svg_conform/external_checkers/svgcheck/validation_pipeline.rb +249 -0
- data/lib/svg_conform/external_checkers/svgcheck.rb +56 -0
- data/lib/svg_conform/external_checkers.rb +34 -0
- data/lib/svg_conform/fixer.rb +56 -0
- data/lib/svg_conform/profile.rb +164 -0
- data/lib/svg_conform/profiles.rb +60 -0
- data/lib/svg_conform/remediation_engine.rb +92 -0
- data/lib/svg_conform/remediation_result.rb +36 -0
- data/lib/svg_conform/remediation_runner.rb +225 -0
- data/lib/svg_conform/remediations/base_remediation.rb +165 -0
- data/lib/svg_conform/remediations/color_remediation.rb +226 -0
- data/lib/svg_conform/remediations/font_embedding_remediation.rb +145 -0
- data/lib/svg_conform/remediations/font_remediation.rb +122 -0
- data/lib/svg_conform/remediations/image_embedding_remediation.rb +154 -0
- data/lib/svg_conform/remediations/invalid_id_references_remediation.rb +129 -0
- data/lib/svg_conform/remediations/namespace_attribute_remediation.rb +244 -0
- data/lib/svg_conform/remediations/namespace_remediation.rb +151 -0
- data/lib/svg_conform/remediations/no_external_css_remediation.rb +192 -0
- data/lib/svg_conform/remediations/style_promotion_remediation.rb +93 -0
- data/lib/svg_conform/remediations/viewbox_remediation.rb +127 -0
- data/lib/svg_conform/remediations.rb +40 -0
- data/lib/svg_conform/report_comparator.rb +772 -0
- data/lib/svg_conform/requirements/allowed_elements_requirement.rb +367 -0
- data/lib/svg_conform/requirements/base_requirement.rb +98 -0
- data/lib/svg_conform/requirements/color_restrictions_requirement.rb +126 -0
- data/lib/svg_conform/requirements/element_requirement_config.rb +75 -0
- data/lib/svg_conform/requirements/font_family_requirement.rb +133 -0
- data/lib/svg_conform/requirements/forbidden_content_requirement.rb +60 -0
- data/lib/svg_conform/requirements/id_reference_requirement.rb +133 -0
- data/lib/svg_conform/requirements/invalid_id_references_requirement.rb +132 -0
- data/lib/svg_conform/requirements/link_validation_requirement.rb +55 -0
- data/lib/svg_conform/requirements/namespace_attributes_requirement.rb +211 -0
- data/lib/svg_conform/requirements/namespace_requirement.rb +294 -0
- data/lib/svg_conform/requirements/no_external_css_requirement.rb +132 -0
- data/lib/svg_conform/requirements/no_external_fonts_requirement.rb +121 -0
- data/lib/svg_conform/requirements/no_external_images_requirement.rb +91 -0
- data/lib/svg_conform/requirements/style_promotion_requirement.rb +72 -0
- data/lib/svg_conform/requirements/style_requirement.rb +226 -0
- data/lib/svg_conform/requirements/viewbox_required_requirement.rb +96 -0
- data/lib/svg_conform/requirements.rb +49 -0
- data/lib/svg_conform/semantic_comparator.rb +829 -0
- data/lib/svg_conform/validation_context.rb +408 -0
- data/lib/svg_conform/validation_result.rb +146 -0
- data/lib/svg_conform/validator.rb +91 -0
- data/lib/svg_conform/version.rb +5 -0
- data/lib/svg_conform.rb +68 -0
- data/lib/tasks/fixtures.rake +321 -0
- data/lib/tasks/svgcheck.rake +111 -0
- data/reference-docs/SVG-1.2-RFC.rnc.txt +1676 -0
- data/reference-docs/Scalable Vector Graphics (SVG) 1.1 (Second Edition).html +40764 -0
- data/reference-docs/Scalable Vector Graphics (SVG) Tiny 1.2 Specification.html +44591 -0
- data/reference-docs/rfc7996.txt +2971 -0
- data/sig/svg_conform.rbs +4 -0
- data/spec/fixtures/allowed_elements/inputs/basic_violations.svg +21 -0
- data/spec/fixtures/allowed_elements/repair/basic_violations.svg +18 -0
- data/spec/fixtures/color_restrictions/inputs/basic_violations.svg +23 -0
- data/spec/fixtures/color_restrictions/repair/basic_violations.svg +23 -0
- data/spec/fixtures/comprehensive/inputs/multiple_violations.svg +21 -0
- data/spec/fixtures/comprehensive/repair/multiple_violations.svg +16 -0
- data/spec/fixtures/font_family/inputs/basic_violations.svg +17 -0
- data/spec/fixtures/font_family/repair/basic_violations.svg +17 -0
- data/spec/fixtures/forbidden_content/inputs/basic_violations.svg +27 -0
- data/spec/fixtures/forbidden_content/repair/basic_violations.svg +19 -0
- data/spec/fixtures/id_reference/inputs/basic_violations.svg +17 -0
- data/spec/fixtures/id_reference/repair/basic_violations.svg +15 -0
- data/spec/fixtures/link_validation/inputs/basic_violations.svg +20 -0
- data/spec/fixtures/link_validation/repair/basic_violations.svg +16 -0
- data/spec/fixtures/lucid/inputs/simple.svg +67 -0
- data/spec/fixtures/lucid/repair/simple.svg +63 -0
- data/spec/fixtures/namespace/inputs/basic_violations.svg +20 -0
- data/spec/fixtures/namespace/repair/basic_violations.svg +17 -0
- data/spec/fixtures/namespace_attributes/inputs/basic_violations.svg +16 -0
- data/spec/fixtures/namespace_attributes/repair/basic_violations.svg +15 -0
- data/spec/fixtures/no_external_css/inputs/basic_violations.svg +20 -0
- data/spec/fixtures/no_external_css/repair/basic_violations.svg +18 -0
- data/spec/fixtures/style/inputs/basic_violations.svg +22 -0
- data/spec/fixtures/style/repair/basic_violations.svg +22 -0
- data/spec/fixtures/style_promotion/inputs/basic_test.svg +15 -0
- data/spec/fixtures/style_promotion/repair/basic_test.svg +15 -0
- data/spec/fixtures/svg_1_2_rfc/inputs/allowed_elements_violations.svg +18 -0
- data/spec/fixtures/svg_1_2_rfc/inputs/color_restrictions_violations.svg +23 -0
- data/spec/fixtures/svgcheck/check/DrawBerry-sample-2.svg.code +1 -0
- data/spec/fixtures/svgcheck/check/DrawBerry-sample-2.svg.err +0 -0
- data/spec/fixtures/svgcheck/check/DrawBerry-sample-2.svg.out +23 -0
- data/spec/fixtures/svgcheck/check/IETF-test.svg.code +1 -0
- data/spec/fixtures/svgcheck/check/IETF-test.svg.err +0 -0
- data/spec/fixtures/svgcheck/check/IETF-test.svg.out +20 -0
- data/spec/fixtures/svgcheck/check/circle.svg.code +1 -0
- data/spec/fixtures/svgcheck/check/circle.svg.err +0 -0
- data/spec/fixtures/svgcheck/check/circle.svg.out +2 -0
- data/spec/fixtures/svgcheck/check/colors.svg.code +1 -0
- data/spec/fixtures/svgcheck/check/colors.svg.err +0 -0
- data/spec/fixtures/svgcheck/check/colors.svg.out +13 -0
- data/spec/fixtures/svgcheck/check/dia-sample-svg.svg.code +1 -0
- data/spec/fixtures/svgcheck/check/dia-sample-svg.svg.err +0 -0
- data/spec/fixtures/svgcheck/check/dia-sample-svg.svg.out +76 -0
- data/spec/fixtures/svgcheck/check/example-dot.svg.code +1 -0
- data/spec/fixtures/svgcheck/check/example-dot.svg.err +0 -0
- data/spec/fixtures/svgcheck/check/example-dot.svg.out +11 -0
- data/spec/fixtures/svgcheck/check/full-tiny.svg.code +1 -0
- data/spec/fixtures/svgcheck/check/full-tiny.svg.err +0 -0
- data/spec/fixtures/svgcheck/check/full-tiny.svg.out +5835 -0
- data/spec/fixtures/svgcheck/check/good.svg.code +1 -0
- data/spec/fixtures/svgcheck/check/good.svg.err +0 -0
- data/spec/fixtures/svgcheck/check/good.svg.out +1 -0
- data/spec/fixtures/svgcheck/check/httpbis-proxy20-fig6.svg.code +1 -0
- data/spec/fixtures/svgcheck/check/httpbis-proxy20-fig6.svg.err +0 -0
- data/spec/fixtures/svgcheck/check/httpbis-proxy20-fig6.svg.out +5 -0
- data/spec/fixtures/svgcheck/check/malformed.svg.code +1 -0
- data/spec/fixtures/svgcheck/check/malformed.svg.err +0 -0
- data/spec/fixtures/svgcheck/check/malformed.svg.out +8 -0
- data/spec/fixtures/svgcheck/check/rfc-svg.svg.code +1 -0
- data/spec/fixtures/svgcheck/check/rfc-svg.svg.err +0 -0
- data/spec/fixtures/svgcheck/check/rfc-svg.svg.out +1 -0
- data/spec/fixtures/svgcheck/check/rfc.xml.code +1 -0
- data/spec/fixtures/svgcheck/check/rfc.xml.err +0 -0
- data/spec/fixtures/svgcheck/check/rfc.xml.out +2 -0
- data/spec/fixtures/svgcheck/check/rgb.svg.code +1 -0
- data/spec/fixtures/svgcheck/check/rgb.svg.err +0 -0
- data/spec/fixtures/svgcheck/check/rgb.svg.out +9 -0
- data/spec/fixtures/svgcheck/check/svg-wordle.svg.code +1 -0
- data/spec/fixtures/svgcheck/check/svg-wordle.svg.err +0 -0
- data/spec/fixtures/svgcheck/check/svg-wordle.svg.out +508 -0
- data/spec/fixtures/svgcheck/check/threshold.svg.code +1 -0
- data/spec/fixtures/svgcheck/check/threshold.svg.err +0 -0
- data/spec/fixtures/svgcheck/check/threshold.svg.out +20 -0
- data/spec/fixtures/svgcheck/check/utf8.svg.code +1 -0
- data/spec/fixtures/svgcheck/check/utf8.svg.err +0 -0
- data/spec/fixtures/svgcheck/check/utf8.svg.out +162 -0
- data/spec/fixtures/svgcheck/check/viewBox-both.svg.code +1 -0
- data/spec/fixtures/svgcheck/check/viewBox-both.svg.err +0 -0
- data/spec/fixtures/svgcheck/check/viewBox-both.svg.out +4 -0
- data/spec/fixtures/svgcheck/check/viewBox-height.svg.code +1 -0
- data/spec/fixtures/svgcheck/check/viewBox-height.svg.err +0 -0
- data/spec/fixtures/svgcheck/check/viewBox-height.svg.out +3 -0
- data/spec/fixtures/svgcheck/check/viewBox-none.svg.code +1 -0
- data/spec/fixtures/svgcheck/check/viewBox-none.svg.err +0 -0
- data/spec/fixtures/svgcheck/check/viewBox-none.svg.out +3 -0
- data/spec/fixtures/svgcheck/check/viewBox-width.svg.code +1 -0
- data/spec/fixtures/svgcheck/check/viewBox-width.svg.err +0 -0
- data/spec/fixtures/svgcheck/check/viewBox-width.svg.out +3 -0
- data/spec/fixtures/svgcheck/inputs/DrawBerry-sample-2.svg +28 -0
- data/spec/fixtures/svgcheck/inputs/IETF-test.svg +28 -0
- data/spec/fixtures/svgcheck/inputs/circle.svg +3 -0
- data/spec/fixtures/svgcheck/inputs/colors.svg +18 -0
- data/spec/fixtures/svgcheck/inputs/dia-sample-svg.svg +47 -0
- data/spec/fixtures/svgcheck/inputs/example-dot.svg +75 -0
- data/spec/fixtures/svgcheck/inputs/full-tiny.svg +16194 -0
- data/spec/fixtures/svgcheck/inputs/good.svg +19 -0
- data/spec/fixtures/svgcheck/inputs/httpbis-proxy20-fig6.svg +2 -0
- data/spec/fixtures/svgcheck/inputs/malformed.svg +11 -0
- data/spec/fixtures/svgcheck/inputs/rfc-svg.svg +1028 -0
- data/spec/fixtures/svgcheck/inputs/rfc.xml +37 -0
- data/spec/fixtures/svgcheck/inputs/rgb.svg +9 -0
- data/spec/fixtures/svgcheck/inputs/svg-wordle.svg +330 -0
- data/spec/fixtures/svgcheck/inputs/threshold.svg +26 -0
- data/spec/fixtures/svgcheck/inputs/utf8.svg +448 -0
- data/spec/fixtures/svgcheck/inputs/viewBox-both.svg +3 -0
- data/spec/fixtures/svgcheck/inputs/viewBox-height.svg +3 -0
- data/spec/fixtures/svgcheck/inputs/viewBox-none.svg +3 -0
- data/spec/fixtures/svgcheck/inputs/viewBox-width.svg +3 -0
- data/spec/fixtures/svgcheck/repair/DrawBerry-sample-2.svg.code +1 -0
- data/spec/fixtures/svgcheck/repair/DrawBerry-sample-2.svg.err +0 -0
- data/spec/fixtures/svgcheck/repair/DrawBerry-sample-2.svg.file +0 -0
- data/spec/fixtures/svgcheck/repair/DrawBerry-sample-2.svg.out +23 -0
- data/spec/fixtures/svgcheck/repair/IETF-test.svg.code +1 -0
- data/spec/fixtures/svgcheck/repair/IETF-test.svg.err +0 -0
- data/spec/fixtures/svgcheck/repair/IETF-test.svg.file +29 -0
- data/spec/fixtures/svgcheck/repair/IETF-test.svg.out +20 -0
- data/spec/fixtures/svgcheck/repair/circle.svg.code +1 -0
- data/spec/fixtures/svgcheck/repair/circle.svg.err +0 -0
- data/spec/fixtures/svgcheck/repair/circle.svg.file +4 -0
- data/spec/fixtures/svgcheck/repair/circle.svg.out +2 -0
- data/spec/fixtures/svgcheck/repair/colors.svg.code +1 -0
- data/spec/fixtures/svgcheck/repair/colors.svg.err +0 -0
- data/spec/fixtures/svgcheck/repair/colors.svg.file +19 -0
- data/spec/fixtures/svgcheck/repair/colors.svg.out +13 -0
- data/spec/fixtures/svgcheck/repair/dia-sample-svg.svg.code +1 -0
- data/spec/fixtures/svgcheck/repair/dia-sample-svg.svg.err +0 -0
- data/spec/fixtures/svgcheck/repair/dia-sample-svg.svg.file +47 -0
- data/spec/fixtures/svgcheck/repair/dia-sample-svg.svg.out +76 -0
- data/spec/fixtures/svgcheck/repair/example-dot.svg.code +1 -0
- data/spec/fixtures/svgcheck/repair/example-dot.svg.err +0 -0
- data/spec/fixtures/svgcheck/repair/example-dot.svg.file +69 -0
- data/spec/fixtures/svgcheck/repair/example-dot.svg.out +11 -0
- data/spec/fixtures/svgcheck/repair/good.svg.code +1 -0
- data/spec/fixtures/svgcheck/repair/good.svg.err +0 -0
- data/spec/fixtures/svgcheck/repair/good.svg.file +0 -0
- data/spec/fixtures/svgcheck/repair/good.svg.out +1 -0
- data/spec/fixtures/svgcheck/repair/httpbis-proxy20-fig6.svg.code +1 -0
- data/spec/fixtures/svgcheck/repair/httpbis-proxy20-fig6.svg.err +0 -0
- data/spec/fixtures/svgcheck/repair/httpbis-proxy20-fig6.svg.file +73 -0
- data/spec/fixtures/svgcheck/repair/httpbis-proxy20-fig6.svg.out +5 -0
- data/spec/fixtures/svgcheck/repair/malformed.svg.code +1 -0
- data/spec/fixtures/svgcheck/repair/malformed.svg.err +0 -0
- data/spec/fixtures/svgcheck/repair/malformed.svg.file +9 -0
- data/spec/fixtures/svgcheck/repair/malformed.svg.out +8 -0
- data/spec/fixtures/svgcheck/repair/rfc-svg.svg.code +1 -0
- data/spec/fixtures/svgcheck/repair/rfc-svg.svg.err +0 -0
- data/spec/fixtures/svgcheck/repair/rfc-svg.svg.file +0 -0
- data/spec/fixtures/svgcheck/repair/rfc-svg.svg.out +1 -0
- data/spec/fixtures/svgcheck/repair/rfc.xml.code +1 -0
- data/spec/fixtures/svgcheck/repair/rfc.xml.err +0 -0
- data/spec/fixtures/svgcheck/repair/rfc.xml.file +37 -0
- data/spec/fixtures/svgcheck/repair/rfc.xml.out +2 -0
- data/spec/fixtures/svgcheck/repair/rgb.svg.code +1 -0
- data/spec/fixtures/svgcheck/repair/rgb.svg.err +0 -0
- data/spec/fixtures/svgcheck/repair/rgb.svg.file +10 -0
- data/spec/fixtures/svgcheck/repair/rgb.svg.out +9 -0
- data/spec/fixtures/svgcheck/repair/svg-wordle.svg.code +1 -0
- data/spec/fixtures/svgcheck/repair/svg-wordle.svg.err +0 -0
- data/spec/fixtures/svgcheck/repair/svg-wordle.svg.file +112 -0
- data/spec/fixtures/svgcheck/repair/svg-wordle.svg.out +508 -0
- data/spec/fixtures/svgcheck/repair/threshold.svg.code +1 -0
- data/spec/fixtures/svgcheck/repair/threshold.svg.err +0 -0
- data/spec/fixtures/svgcheck/repair/threshold.svg.file +27 -0
- data/spec/fixtures/svgcheck/repair/threshold.svg.out +20 -0
- data/spec/fixtures/svgcheck/repair/utf8.svg.code +1 -0
- data/spec/fixtures/svgcheck/repair/utf8.svg.err +0 -0
- data/spec/fixtures/svgcheck/repair/utf8.svg.file +381 -0
- data/spec/fixtures/svgcheck/repair/utf8.svg.out +162 -0
- data/spec/fixtures/svgcheck/repair/viewBox-both.svg.code +1 -0
- data/spec/fixtures/svgcheck/repair/viewBox-both.svg.err +0 -0
- data/spec/fixtures/svgcheck/repair/viewBox-both.svg.file +4 -0
- data/spec/fixtures/svgcheck/repair/viewBox-both.svg.out +4 -0
- data/spec/fixtures/svgcheck/repair/viewBox-height.svg.code +1 -0
- data/spec/fixtures/svgcheck/repair/viewBox-height.svg.err +0 -0
- data/spec/fixtures/svgcheck/repair/viewBox-height.svg.file +4 -0
- data/spec/fixtures/svgcheck/repair/viewBox-height.svg.out +3 -0
- data/spec/fixtures/svgcheck/repair/viewBox-none.svg.code +1 -0
- data/spec/fixtures/svgcheck/repair/viewBox-none.svg.err +0 -0
- data/spec/fixtures/svgcheck/repair/viewBox-none.svg.file +4 -0
- data/spec/fixtures/svgcheck/repair/viewBox-none.svg.out +3 -0
- data/spec/fixtures/svgcheck/repair/viewBox-width.svg.code +1 -0
- data/spec/fixtures/svgcheck/repair/viewBox-width.svg.err +0 -0
- data/spec/fixtures/svgcheck/repair/viewBox-width.svg.file +4 -0
- data/spec/fixtures/svgcheck/repair/viewBox-width.svg.out +3 -0
- data/spec/fixtures/viewbox_required/inputs/missing_viewbox.svg +10 -0
- data/spec/fixtures/viewbox_required/repair/missing_viewbox.svg +10 -0
- data/spec/spec_helper.rb +16 -0
- data/spec/svg_conform/batch_report_spec.rb +99 -0
- data/spec/svg_conform/commands/check_command_spec.rb +90 -0
- data/spec/svg_conform/commands/profiles_command_spec.rb +20 -0
- data/spec/svg_conform/commands/svgcheck_compare_command_spec.rb +13 -0
- data/spec/svg_conform/commands/svgcheck_compatibility_command_spec.rb +13 -0
- data/spec/svg_conform/commands/svgcheck_generate_command_spec.rb +14 -0
- data/spec/svg_conform/profiles/base_profile_spec.rb +42 -0
- data/spec/svg_conform/profiles/lucid_fix_profile_spec.rb +46 -0
- data/spec/svg_conform/profiles/lucid_profile_spec.rb +84 -0
- data/spec/svg_conform/profiles/metanorma_profile_spec.rb +62 -0
- data/spec/svg_conform/profiles/no_external_css_profile_spec.rb +66 -0
- data/spec/svg_conform/profiles/svg_1_2_rfc_profile_spec.rb +200 -0
- data/spec/svg_conform/profiles/svg_1_2_rfc_with_rdf_profile_spec.rb +81 -0
- data/spec/svg_conform/remediations/color_remediation_spec.rb +95 -0
- data/spec/svg_conform/remediations/font_embedding_remediation_spec.rb +20 -0
- data/spec/svg_conform/remediations/font_remediation_spec.rb +95 -0
- data/spec/svg_conform/remediations/image_embedding_remediation_spec.rb +20 -0
- data/spec/svg_conform/remediations/invalid_id_references_remediation_spec.rb +97 -0
- data/spec/svg_conform/remediations/namespace_attribute_remediation_spec.rb +97 -0
- data/spec/svg_conform/remediations/namespace_remediation_spec.rb +95 -0
- data/spec/svg_conform/remediations/no_external_css_remediation_spec.rb +97 -0
- data/spec/svg_conform/remediations/style_promotion_remediation_spec.rb +97 -0
- data/spec/svg_conform/remediations/viewbox_remediation_spec.rb +95 -0
- data/spec/svg_conform/requirements/allowed_elements_requirement_spec.rb +118 -0
- data/spec/svg_conform/requirements/color_restrictions_requirement_spec.rb +168 -0
- data/spec/svg_conform/requirements/font_family_requirement_spec.rb +188 -0
- data/spec/svg_conform/requirements/forbidden_content_requirement_spec.rb +195 -0
- data/spec/svg_conform/requirements/id_reference_requirement_spec.rb +78 -0
- data/spec/svg_conform/requirements/invalid_id_references_requirement_spec.rb +78 -0
- data/spec/svg_conform/requirements/link_validation_requirement_spec.rb +78 -0
- data/spec/svg_conform/requirements/namespace_attributes_requirement_spec.rb +86 -0
- data/spec/svg_conform/requirements/namespace_requirement_spec.rb +184 -0
- data/spec/svg_conform/requirements/no_external_css_requirement_spec.rb +78 -0
- data/spec/svg_conform/requirements/no_external_fonts_requirement_spec.rb +20 -0
- data/spec/svg_conform/requirements/no_external_images_requirement_spec.rb +20 -0
- data/spec/svg_conform/requirements/style_promotion_requirement_spec.rb +78 -0
- data/spec/svg_conform/requirements/style_requirement_spec.rb +76 -0
- data/spec/svg_conform/requirements/viewbox_required_requirement_spec.rb +165 -0
- data/spec/svg_conform_spec.rb +32 -0
- data/spec/svgcheck_compatibility_spec.rb +355 -0
- data/svg_conform.gemspec +35 -0
- metadata +436 -0
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "base_remediation"
|
|
4
|
+
|
|
5
|
+
module SvgConform
|
|
6
|
+
module Remediations
|
|
7
|
+
# Remediation action for fixing invalid ID references
|
|
8
|
+
# Based on the Lucid SVG fix script behavior
|
|
9
|
+
class InvalidIdReferencesRemediation < BaseRemediation
|
|
10
|
+
attribute :type, :string, default: -> { "InvalidIdReferencesRemediation" }
|
|
11
|
+
attribute :strategy, :string, default: "remove_invalid_use"
|
|
12
|
+
attribute :log_removed_elements, :boolean, default: false
|
|
13
|
+
attribute :create_placeholder_comment, :boolean, default: false
|
|
14
|
+
attribute :preserve_valid_attributes, :boolean, default: true
|
|
15
|
+
|
|
16
|
+
def apply(document, _context)
|
|
17
|
+
changes = []
|
|
18
|
+
|
|
19
|
+
# Find all use elements with invalid href references
|
|
20
|
+
document.traverse do |node|
|
|
21
|
+
next unless node.respond_to?(:name) && node.name == "use"
|
|
22
|
+
|
|
23
|
+
href = get_attribute(node,
|
|
24
|
+
"href") || get_attribute(node, "xlink:href")
|
|
25
|
+
next unless href&.start_with?("#")
|
|
26
|
+
|
|
27
|
+
referenced_id = href[1..] # Remove the #
|
|
28
|
+
next if document.xpath("//*[@id='#{referenced_id}']").any? # ID exists, skip
|
|
29
|
+
|
|
30
|
+
# Handle invalid ID reference
|
|
31
|
+
change = handle_use_element(node,
|
|
32
|
+
{ href: href, invalid_id: referenced_id })
|
|
33
|
+
changes << change if change
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
changes
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
private
|
|
40
|
+
|
|
41
|
+
def handle_use_element(node, data)
|
|
42
|
+
case @strategy
|
|
43
|
+
when "remove_invalid_use"
|
|
44
|
+
remove_use_element(node, data)
|
|
45
|
+
when "remove_invalid_href"
|
|
46
|
+
remove_href_attribute(node, data)
|
|
47
|
+
when "replace_with_placeholder"
|
|
48
|
+
replace_with_placeholder(node, data)
|
|
49
|
+
else
|
|
50
|
+
raise "Unknown strategy: #{@strategy}"
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def handle_other_id_reference(node, data)
|
|
55
|
+
case @strategy
|
|
56
|
+
when "remove_invalid_use", "remove_invalid_href"
|
|
57
|
+
remove_invalid_attribute(node, data)
|
|
58
|
+
when "replace_with_placeholder"
|
|
59
|
+
replace_attribute_with_placeholder(node, data)
|
|
60
|
+
else
|
|
61
|
+
raise "Unknown strategy: #{@strategy}"
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def remove_use_element(node, data)
|
|
66
|
+
if @create_placeholder_comment
|
|
67
|
+
comment_text = "Removed invalid use element: href=#{data[:href]}, invalid_id=#{data[:invalid_id]}"
|
|
68
|
+
comment = create_comment(node.document, comment_text)
|
|
69
|
+
replace_node(node, comment)
|
|
70
|
+
else
|
|
71
|
+
remove_node(node)
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
log_change(
|
|
75
|
+
:remove_element,
|
|
76
|
+
"Removed use element with invalid ID reference: #{data[:invalid_id]}",
|
|
77
|
+
node,
|
|
78
|
+
)
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def remove_href_attribute(node, data)
|
|
82
|
+
# Remove both possible href attributes
|
|
83
|
+
remove_attribute(node, "xlink:href")
|
|
84
|
+
remove_attribute(node, "href")
|
|
85
|
+
|
|
86
|
+
log_change(
|
|
87
|
+
:remove_attribute,
|
|
88
|
+
"Removed invalid href attribute referencing: #{data[:invalid_id]}",
|
|
89
|
+
node,
|
|
90
|
+
)
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def replace_with_placeholder(node, data)
|
|
94
|
+
comment_text = "Invalid use element removed: #{node.to_xml.strip}"
|
|
95
|
+
comment = create_comment(node.document, comment_text)
|
|
96
|
+
replace_node(node, comment)
|
|
97
|
+
|
|
98
|
+
log_change(
|
|
99
|
+
:replace_with_comment,
|
|
100
|
+
"Replaced use element with comment due to invalid ID reference: #{data[:invalid_id]}",
|
|
101
|
+
node,
|
|
102
|
+
)
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def remove_invalid_attribute(node, data)
|
|
106
|
+
attribute_name = data[:attribute]
|
|
107
|
+
remove_attribute(node, attribute_name)
|
|
108
|
+
|
|
109
|
+
log_change(
|
|
110
|
+
:remove_attribute,
|
|
111
|
+
"Removed #{attribute_name} attribute with invalid ID reference: #{data[:invalid_id]}",
|
|
112
|
+
node,
|
|
113
|
+
)
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def replace_attribute_with_placeholder(node, data)
|
|
117
|
+
attribute_name = data[:attribute]
|
|
118
|
+
placeholder_value = "none" # Safe fallback value
|
|
119
|
+
set_attribute(node, attribute_name, placeholder_value)
|
|
120
|
+
|
|
121
|
+
log_change(
|
|
122
|
+
:replace_attribute,
|
|
123
|
+
"Replaced #{attribute_name} attribute (invalid ID: #{data[:invalid_id]}) with placeholder: #{placeholder_value}",
|
|
124
|
+
node,
|
|
125
|
+
)
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
end
|
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "set"
|
|
4
|
+
require_relative "base_remediation"
|
|
5
|
+
|
|
6
|
+
module SvgConform
|
|
7
|
+
module Remediations
|
|
8
|
+
# Remediation for removing disallowed namespace attributes and declarations
|
|
9
|
+
class NamespaceAttributeRemediation < BaseRemediation
|
|
10
|
+
attribute :type, :string, default: -> { "NamespaceAttributeRemediation" }
|
|
11
|
+
attribute :disallowed_namespaces, :string, collection: true, default: -> {
|
|
12
|
+
[]
|
|
13
|
+
}
|
|
14
|
+
attribute :allowed_namespaces, :string, collection: true, default: -> {
|
|
15
|
+
[]
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
yaml do
|
|
19
|
+
map "disallowed_namespaces", to: :disallowed_namespaces
|
|
20
|
+
map "allowed_namespaces", to: :allowed_namespaces
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def apply(document, _context)
|
|
24
|
+
changes = []
|
|
25
|
+
removed_namespaces = Set.new
|
|
26
|
+
|
|
27
|
+
# First pass: remove disallowed namespace attributes
|
|
28
|
+
document.traverse do |node|
|
|
29
|
+
next unless element?(node)
|
|
30
|
+
|
|
31
|
+
changes.concat(remove_disallowed_attributes(node, removed_namespaces))
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Second pass: remove unused namespace declarations
|
|
35
|
+
document.traverse do |node|
|
|
36
|
+
next unless element?(node)
|
|
37
|
+
|
|
38
|
+
changes.concat(remove_unused_namespace_declarations(node,
|
|
39
|
+
removed_namespaces))
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
changes
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
private
|
|
46
|
+
|
|
47
|
+
def remove_disallowed_attributes(node, removed_namespaces)
|
|
48
|
+
changes = []
|
|
49
|
+
|
|
50
|
+
# Get all attributes that need to be checked
|
|
51
|
+
attributes_to_remove = []
|
|
52
|
+
|
|
53
|
+
if node.respond_to?(:attribute_nodes)
|
|
54
|
+
# Use attribute_nodes if available (Nokogiri style)
|
|
55
|
+
node.attribute_nodes.each do |attr|
|
|
56
|
+
namespace_uri = attr.namespace&.href
|
|
57
|
+
next unless namespace_uri
|
|
58
|
+
|
|
59
|
+
if namespace_disallowed?(namespace_uri)
|
|
60
|
+
attr_name = if attr.namespace&.prefix
|
|
61
|
+
"#{attr.namespace.prefix}:#{attr.name}"
|
|
62
|
+
else
|
|
63
|
+
attr.name
|
|
64
|
+
end
|
|
65
|
+
attributes_to_remove << attr_name
|
|
66
|
+
removed_namespaces.add(namespace_uri)
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
elsif node.respond_to?(:attributes)
|
|
70
|
+
# Fallback to attributes method
|
|
71
|
+
attributes = node.attributes
|
|
72
|
+
|
|
73
|
+
if attributes.respond_to?(:each_key)
|
|
74
|
+
# Hash case
|
|
75
|
+
attributes.each_key do |name|
|
|
76
|
+
if should_remove_attribute_by_name?(name.to_s, node,
|
|
77
|
+
removed_namespaces)
|
|
78
|
+
attributes_to_remove << name.to_s
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
elsif attributes.respond_to?(:each)
|
|
82
|
+
# Array case
|
|
83
|
+
attributes.each do |attr|
|
|
84
|
+
if should_remove_moxml_attribute?(attr, node, removed_namespaces)
|
|
85
|
+
attr_name = attr.respond_to?(:name) ? attr.name : attr.to_s
|
|
86
|
+
attributes_to_remove << attr_name
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
# Remove the identified attributes
|
|
93
|
+
attributes_to_remove.each do |attr_name|
|
|
94
|
+
if remove_attribute(node, attr_name)
|
|
95
|
+
changes << {
|
|
96
|
+
type: :attribute_removed,
|
|
97
|
+
description: "Removed disallowed namespace attribute '#{attr_name}'",
|
|
98
|
+
node_name: node.name,
|
|
99
|
+
attribute: attr_name,
|
|
100
|
+
}
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
changes
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def remove_unused_namespace_declarations(node, removed_namespaces)
|
|
108
|
+
changes = []
|
|
109
|
+
|
|
110
|
+
# Look for xmlns declarations that correspond to removed namespaces
|
|
111
|
+
attributes_to_remove = []
|
|
112
|
+
|
|
113
|
+
if node.respond_to?(:attribute_nodes)
|
|
114
|
+
node.attribute_nodes.each do |attr|
|
|
115
|
+
attr_name = attr.name
|
|
116
|
+
next unless attr_name.start_with?("xmlns:")
|
|
117
|
+
|
|
118
|
+
namespace_uri = attr.value
|
|
119
|
+
# Also check if the namespace prefix itself was in disallowed_namespaces
|
|
120
|
+
# since xmlns:lucid="lucid" means the URI is literally "lucid"
|
|
121
|
+
prefix = attr_name.sub("xmlns:", "")
|
|
122
|
+
if removed_namespaces.include?(namespace_uri) || disallowed_namespaces.include?(namespace_uri) || disallowed_namespaces.include?(prefix)
|
|
123
|
+
attributes_to_remove << attr_name
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
elsif node.respond_to?(:attributes)
|
|
127
|
+
attributes = node.attributes
|
|
128
|
+
|
|
129
|
+
if attributes.respond_to?(:each_key)
|
|
130
|
+
attributes.each_key do |name|
|
|
131
|
+
name_str = name.to_s
|
|
132
|
+
next unless name_str.start_with?("xmlns:")
|
|
133
|
+
|
|
134
|
+
namespace_uri = get_attribute(node, name_str)
|
|
135
|
+
prefix = name_str.sub("xmlns:", "")
|
|
136
|
+
if namespace_uri && (removed_namespaces.include?(namespace_uri) || disallowed_namespaces.include?(namespace_uri) || disallowed_namespaces.include?(prefix))
|
|
137
|
+
attributes_to_remove << name_str
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
# Remove the xmlns declarations
|
|
144
|
+
attributes_to_remove.each do |attr_name|
|
|
145
|
+
if remove_attribute(node, attr_name)
|
|
146
|
+
changes << {
|
|
147
|
+
type: :attribute_removed,
|
|
148
|
+
description: "Removed unused namespace declaration '#{attr_name}'",
|
|
149
|
+
node_name: node.name,
|
|
150
|
+
attribute: attr_name,
|
|
151
|
+
}
|
|
152
|
+
end
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
changes
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
def namespace_disallowed?(namespace_uri)
|
|
159
|
+
if allowed_namespaces.empty?
|
|
160
|
+
# Blacklist mode: disallowed namespaces are forbidden
|
|
161
|
+
disallowed_namespaces.include?(namespace_uri)
|
|
162
|
+
else
|
|
163
|
+
# Whitelist mode: only allowed namespaces are permitted
|
|
164
|
+
!allowed_namespaces.include?(namespace_uri)
|
|
165
|
+
end
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
def should_remove_attribute_by_name?(name, node, removed_namespaces)
|
|
169
|
+
# Check if this is a namespaced attribute by looking for colon in name
|
|
170
|
+
return false unless name.include?(":")
|
|
171
|
+
|
|
172
|
+
prefix, = name.split(":", 2)
|
|
173
|
+
|
|
174
|
+
# Find the namespace URI for this prefix
|
|
175
|
+
namespace_uri = find_namespace_uri(node, prefix)
|
|
176
|
+
|
|
177
|
+
return false unless namespace_uri
|
|
178
|
+
|
|
179
|
+
if namespace_disallowed?(namespace_uri)
|
|
180
|
+
removed_namespaces.add(namespace_uri)
|
|
181
|
+
true
|
|
182
|
+
else
|
|
183
|
+
false
|
|
184
|
+
end
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
def should_remove_moxml_attribute?(attr, node, removed_namespaces)
|
|
188
|
+
if attr.respond_to?(:namespace) && attr.namespace
|
|
189
|
+
namespace_uri = if attr.namespace.respond_to?(:href)
|
|
190
|
+
attr.namespace.href
|
|
191
|
+
elsif attr.namespace.respond_to?(:uri)
|
|
192
|
+
attr.namespace.uri
|
|
193
|
+
else
|
|
194
|
+
attr.namespace.to_s
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
return false unless namespace_uri && !namespace_uri.empty?
|
|
198
|
+
|
|
199
|
+
if namespace_disallowed?(namespace_uri)
|
|
200
|
+
removed_namespaces.add(namespace_uri)
|
|
201
|
+
true
|
|
202
|
+
else
|
|
203
|
+
false
|
|
204
|
+
end
|
|
205
|
+
else
|
|
206
|
+
# Fallback to name-based checking
|
|
207
|
+
name = attr.respond_to?(:name) ? attr.name : attr.to_s
|
|
208
|
+
should_remove_attribute_by_name?(name, node, removed_namespaces)
|
|
209
|
+
end
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
def find_namespace_uri(node, prefix)
|
|
213
|
+
# Check current node's namespace definitions
|
|
214
|
+
current = node
|
|
215
|
+
while current.respond_to?(:parent)
|
|
216
|
+
if current.respond_to?(:namespace_definitions)
|
|
217
|
+
ns_def = current.namespace_definitions.find do |ns|
|
|
218
|
+
ns.prefix == prefix
|
|
219
|
+
end
|
|
220
|
+
if ns_def
|
|
221
|
+
return ns_def.uri if ns_def.respond_to?(:uri)
|
|
222
|
+
return ns_def.href if ns_def.respond_to?(:href)
|
|
223
|
+
|
|
224
|
+
return ns_def.to_s
|
|
225
|
+
end
|
|
226
|
+
end
|
|
227
|
+
|
|
228
|
+
# Check if it's defined as an attribute (xmlns:prefix)
|
|
229
|
+
xmlns_value = get_attribute(current, "xmlns:#{prefix}")
|
|
230
|
+
return xmlns_value if xmlns_value
|
|
231
|
+
|
|
232
|
+
# Move to parent, but break if parent is nil or doesn't respond to parent
|
|
233
|
+
begin
|
|
234
|
+
current = current.parent
|
|
235
|
+
rescue StandardError
|
|
236
|
+
break
|
|
237
|
+
end
|
|
238
|
+
end
|
|
239
|
+
|
|
240
|
+
nil
|
|
241
|
+
end
|
|
242
|
+
end
|
|
243
|
+
end
|
|
244
|
+
end
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "base_remediation"
|
|
4
|
+
|
|
5
|
+
module SvgConform
|
|
6
|
+
module Remediations
|
|
7
|
+
# Remediation action for namespace-related issues
|
|
8
|
+
class NamespaceRemediation < BaseRemediation
|
|
9
|
+
attribute :type, :string, default: -> { "NamespaceRemediation" }
|
|
10
|
+
attribute :default_namespace, :string, default: "http://www.w3.org/2000/svg"
|
|
11
|
+
attribute :allowed_namespaces, :string, collection: true, default: -> {
|
|
12
|
+
["http://www.w3.org/2000/svg", "http://www.w3.org/1999/xlink",
|
|
13
|
+
"http://www.w3.org/XML/1998/namespace"]
|
|
14
|
+
}
|
|
15
|
+
attribute :remove_elements, :boolean, default: true
|
|
16
|
+
attribute :remove_attributes, :boolean, default: true
|
|
17
|
+
attribute :remove_declarations, :boolean, default: true
|
|
18
|
+
|
|
19
|
+
yaml do
|
|
20
|
+
map "default_namespace", to: :default_namespace
|
|
21
|
+
map "allowed_namespaces", to: :allowed_namespaces
|
|
22
|
+
map "remove_elements", to: :remove_elements
|
|
23
|
+
map "remove_attributes", to: :remove_attributes
|
|
24
|
+
map "remove_declarations", to: :remove_declarations
|
|
25
|
+
end
|
|
26
|
+
def apply(document, _context)
|
|
27
|
+
changes = []
|
|
28
|
+
default_namespace
|
|
29
|
+
|
|
30
|
+
# Skip xmlns handling - assume it's already correct in most cases
|
|
31
|
+
# (This avoids duplicate xmlns attribute issues)
|
|
32
|
+
|
|
33
|
+
# Remove invalid namespace elements and attributes based on configuration
|
|
34
|
+
nodes_to_remove = []
|
|
35
|
+
|
|
36
|
+
document.traverse do |node|
|
|
37
|
+
next unless element?(node)
|
|
38
|
+
|
|
39
|
+
# Check if element has invalid namespace using Moxml's namespace API
|
|
40
|
+
if remove_elements && node.respond_to?(:namespace) && node.namespace
|
|
41
|
+
namespace_uri = get_namespace_uri(node.namespace)
|
|
42
|
+
|
|
43
|
+
if namespace_uri && !allowed_namespaces.include?(namespace_uri)
|
|
44
|
+
nodes_to_remove << node
|
|
45
|
+
changes << {
|
|
46
|
+
type: :element_removed,
|
|
47
|
+
description: "Removed invalid namespace element: #{node.name} (#{namespace_uri})",
|
|
48
|
+
node_name: node.name,
|
|
49
|
+
namespace_uri: namespace_uri,
|
|
50
|
+
}
|
|
51
|
+
next # Skip attribute checking for elements we're removing
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# Remove invalid namespace attributes from all elements
|
|
56
|
+
if remove_attributes && node.respond_to?(:attributes) && node.attributes
|
|
57
|
+
invalid_attrs = []
|
|
58
|
+
|
|
59
|
+
node.attributes.each do |attr_name, attr_value|
|
|
60
|
+
# Handle both string keys and Moxml::Attribute objects
|
|
61
|
+
name_str = attr_name.respond_to?(:name) ? attr_name.name : attr_name.to_s
|
|
62
|
+
|
|
63
|
+
# For root SVG element, remove xmlns declarations for disallowed namespaces
|
|
64
|
+
if remove_declarations && node.name == "svg" && name_str.start_with?("xmlns:")
|
|
65
|
+
name_str.sub("xmlns:", "")
|
|
66
|
+
value_str = attr_value.respond_to?(:value) ? attr_value.value : attr_value.to_s
|
|
67
|
+
|
|
68
|
+
if !allowed_namespaces.include?(value_str)
|
|
69
|
+
invalid_attrs << name_str
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
# For all elements, remove attributes with invalid namespaces
|
|
74
|
+
# Check if attribute has namespace information (Moxml::Attribute objects)
|
|
75
|
+
if attr_name.respond_to?(:namespace) && attr_name.namespace
|
|
76
|
+
attr_namespace_uri = get_namespace_uri(attr_name.namespace)
|
|
77
|
+
|
|
78
|
+
if attr_namespace_uri && !allowed_namespaces.include?(attr_namespace_uri)
|
|
79
|
+
invalid_attrs << name_str
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
# Remove invalid attributes
|
|
85
|
+
invalid_attrs.each do |attr_name|
|
|
86
|
+
remove_attribute(node, attr_name)
|
|
87
|
+
description = if attr_name.start_with?("xmlns:")
|
|
88
|
+
"Removed invalid namespace declaration: #{attr_name}"
|
|
89
|
+
else
|
|
90
|
+
"Removed invalid namespace attribute: #{attr_name}"
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
changes << {
|
|
94
|
+
type: :attribute_removed,
|
|
95
|
+
description: description,
|
|
96
|
+
node_name: node.name,
|
|
97
|
+
attribute_name: attr_name,
|
|
98
|
+
}
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
# Remove invalid namespace elements
|
|
104
|
+
nodes_to_remove.each do |node|
|
|
105
|
+
remove_node(node)
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
changes
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
private
|
|
112
|
+
|
|
113
|
+
def get_namespace_uri(namespace)
|
|
114
|
+
# Extract URI from Moxml::Namespace object
|
|
115
|
+
if namespace.respond_to?(:uri)
|
|
116
|
+
namespace.uri
|
|
117
|
+
elsif namespace.respond_to?(:to_s)
|
|
118
|
+
# Extract URI from string representation if needed
|
|
119
|
+
uri_match = namespace.to_s.match(/="([^"]+)"/)
|
|
120
|
+
uri_match ? uri_match[1] : nil
|
|
121
|
+
else
|
|
122
|
+
nil
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
def find_namespace_uri_for_prefix(node, prefix)
|
|
127
|
+
# Check current node and ancestors for namespace declarations
|
|
128
|
+
current = node
|
|
129
|
+
while current
|
|
130
|
+
# Check for xmlns:prefix attribute
|
|
131
|
+
xmlns_attr = "xmlns:#{prefix}"
|
|
132
|
+
return current.attributes[xmlns_attr] if current.respond_to?(:attributes) && current.attributes[xmlns_attr]
|
|
133
|
+
|
|
134
|
+
# Check using get_attribute method
|
|
135
|
+
namespace_uri = get_attribute(current, xmlns_attr)
|
|
136
|
+
return namespace_uri if namespace_uri
|
|
137
|
+
|
|
138
|
+
# Move to parent
|
|
139
|
+
current = current.respond_to?(:parent) ? current.parent : nil
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
nil
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
def find_namespace_uri_for_attribute(node, prefix)
|
|
146
|
+
# Same logic as find_namespace_uri_for_prefix
|
|
147
|
+
find_namespace_uri_for_prefix(node, prefix)
|
|
148
|
+
end
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
end
|