uniword 1.2.5 → 1.4.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 +4 -4
- data/CHANGELOG.md +313 -0
- data/CONTRIBUTING.md +1 -1
- data/config/ooxml/schemas/shared_types.yml +5 -4
- data/data/schemas/ecma/dc.xsd +118 -0
- data/data/schemas/ecma/dcmitype.xsd +50 -0
- data/data/schemas/ecma/dcterms.xsd +331 -0
- data/data/schemas/ecma/opc-coreProperties.xsd +2 -2
- data/data/schemas/ecma/xml.xsd +117 -0
- data/lib/uniword/builder/bibliography_builder.rb +1 -1
- data/lib/uniword/builder/chart_builder.rb +22 -14
- data/lib/uniword/builder/comment_anchorer.rb +221 -0
- data/lib/uniword/builder/document_builder.rb +97 -6
- data/lib/uniword/builder/image_builder.rb +11 -10
- data/lib/uniword/builder/run_utils.rb +2 -0
- data/lib/uniword/builder.rb +1 -0
- data/lib/uniword/cli/fonts_cli.rb +52 -0
- data/lib/uniword/cli/main.rb +110 -11
- data/lib/uniword/cli/page_cli.rb +85 -0
- data/lib/uniword/cli/styles_cli.rb +204 -0
- data/lib/uniword/cli/theme_cli.rb +88 -0
- data/lib/uniword/cli/toc_cli.rb +22 -2
- data/lib/uniword/comment.rb +20 -15
- data/lib/uniword/comment_range.rb +3 -3
- data/lib/uniword/comments_part.rb +51 -19
- data/lib/uniword/configuration/configuration_loader.rb +5 -3
- data/lib/uniword/configuration.rb +93 -1
- data/lib/uniword/content_types.rb +19 -39
- data/lib/uniword/document_factory.rb +12 -18
- data/lib/uniword/document_writer.rb +16 -5
- data/lib/uniword/docx/chart_part.rb +34 -0
- data/lib/uniword/docx/custom_xml_item.rb +91 -0
- data/lib/uniword/docx/header_footer_part.rb +140 -0
- data/lib/uniword/docx/header_footer_part_collection.rb +135 -0
- data/lib/uniword/docx/header_footer_view.rb +225 -0
- data/lib/uniword/docx/id_allocator.rb +130 -36
- data/lib/uniword/docx/image_part.rb +83 -0
- data/lib/uniword/docx/package.rb +141 -333
- data/lib/uniword/docx/package_defaults.rb +83 -99
- data/lib/uniword/docx/package_integrity_checker.rb +312 -0
- data/lib/uniword/docx/package_serialization.rb +144 -233
- data/lib/uniword/docx/part.rb +125 -0
- data/lib/uniword/docx/part_collection.rb +131 -0
- data/lib/uniword/docx/part_loader/chart_loader.rb +50 -0
- data/lib/uniword/docx/part_loader/custom_xml_loader.rb +53 -0
- data/lib/uniword/docx/part_loader/embedding_loader.rb +26 -0
- data/lib/uniword/docx/part_loader/header_footer_loader.rb +101 -0
- data/lib/uniword/docx/part_loader/image_loader.rb +105 -0
- data/lib/uniword/docx/part_loader/load_context.rb +85 -0
- data/lib/uniword/docx/part_loader/raw_part_loader.rb +183 -0
- data/lib/uniword/docx/part_loader/theme_media_loader.rb +39 -0
- data/lib/uniword/docx/part_loader/xml_model_loader.rb +56 -0
- data/lib/uniword/docx/part_loader.rb +92 -0
- data/lib/uniword/docx/raw_part.rb +75 -0
- data/lib/uniword/docx/reconciler/body.rb +59 -68
- data/lib/uniword/docx/reconciler/fix.rb +46 -0
- data/lib/uniword/docx/reconciler/fix_codes.rb +37 -30
- data/lib/uniword/docx/reconciler/helpers.rb +18 -31
- data/lib/uniword/docx/reconciler/notes.rb +17 -8
- data/lib/uniword/docx/reconciler/package_structure.rb +168 -221
- data/lib/uniword/docx/reconciler/parts.rb +36 -13
- data/lib/uniword/docx/reconciler/referential_integrity.rb +222 -123
- data/lib/uniword/docx/reconciler/tables.rb +78 -16
- data/lib/uniword/docx/reconciler/theme.rb +7 -4
- data/lib/uniword/docx/reconciler.rb +36 -14
- data/lib/uniword/docx.rb +13 -0
- data/lib/uniword/drawingml/blip.rb +0 -1
- data/lib/uniword/drawingml/color_scheme.rb +5 -6
- data/lib/uniword/drawingml/font_scheme.rb +4 -8
- data/lib/uniword/drawingml/theme.rb +12 -6
- data/lib/uniword/errors.rb +8 -1
- data/lib/uniword/footer.rb +4 -0
- data/lib/uniword/header.rb +4 -0
- data/lib/uniword/hyperlink.rb +1 -1
- data/lib/uniword/image.rb +6 -6
- data/lib/uniword/images/image_manager.rb +13 -13
- data/lib/uniword/lazy_loader.rb +1 -2
- data/lib/uniword/model_attribute_access.rb +20 -4
- data/lib/uniword/ooxml/dotx_package.rb +42 -2
- data/lib/uniword/ooxml/element_order.rb +94 -0
- data/lib/uniword/ooxml/part_definition.rb +329 -0
- data/lib/uniword/ooxml/part_registry.rb +504 -0
- data/lib/uniword/ooxml/relationships/image_relationship.rb +6 -3
- data/lib/uniword/ooxml/relationships/package_relationships.rb +20 -22
- data/lib/uniword/ooxml/schema/element_serializer.rb +8 -7
- data/lib/uniword/ooxml/types/hex_color_value.rb +38 -0
- data/lib/uniword/ooxml/types/ooxml_boolean.rb +27 -14
- data/lib/uniword/ooxml/types/ooxml_boolean_optional.rb +21 -16
- data/lib/uniword/ooxml/types/theme_color_value.rb +22 -0
- data/lib/uniword/ooxml/types/unsigned_decimal_number.rb +30 -0
- data/lib/uniword/ooxml/types.rb +10 -0
- data/lib/uniword/ooxml.rb +3 -0
- data/lib/uniword/properties/alignment.rb +8 -3
- data/lib/uniword/properties/border.rb +52 -6
- data/lib/uniword/properties/cell_vertical_align.rb +4 -1
- data/lib/uniword/properties/color_value.rb +8 -3
- data/lib/uniword/properties/highlight.rb +9 -5
- data/lib/uniword/properties/shading.rb +4 -3
- data/lib/uniword/properties/tab_stop.rb +6 -1
- data/lib/uniword/properties/table_justification.rb +4 -1
- data/lib/uniword/properties/underline.rb +4 -2
- data/lib/uniword/properties/vertical_align.rb +6 -3
- data/lib/uniword/review/review_manager.rb +23 -9
- data/lib/uniword/revision.rb +9 -9
- data/lib/uniword/schema/model_generator.rb +31 -15
- data/lib/uniword/shared_types/hex_color.rb +4 -1
- data/lib/uniword/shared_types/pixel_measure.rb +4 -1
- data/lib/uniword/shared_types/point_measure.rb +4 -1
- data/lib/uniword/shared_types/text_alignment.rb +6 -1
- data/lib/uniword/shared_types/twips_measure.rb +4 -1
- data/lib/uniword/spreadsheetml/phonetic_pr.rb +1 -1
- data/lib/uniword/spreadsheetml/shared_string_table.rb +2 -2
- data/lib/uniword/spreadsheetml/table_formula.rb +1 -1
- data/lib/uniword/template/variable_resolver.rb +40 -7
- data/lib/uniword/themes/theme_transformation.rb +55 -41
- data/lib/uniword/toc/toc_generator.rb +6 -5
- data/lib/uniword/transformation/mhtml_element_renderer.rb +1 -5
- data/lib/uniword/transformation/mhtml_metadata_builder.rb +6 -6
- data/lib/uniword/validation/engine.rb +35 -0
- data/lib/uniword/validation/link_checker.rb +1 -1
- data/lib/uniword/validation/opc_validator.rb +16 -2
- data/lib/uniword/validation/report/layer_result.rb +0 -1
- data/lib/uniword/validation/report/terminal_formatter.rb +0 -1
- data/lib/uniword/validation/report/verification_report.rb +0 -2
- data/lib/uniword/validation/report.rb +20 -0
- data/lib/uniword/validation/rules/base.rb +10 -2
- data/lib/uniword/validation/rules/bookmark_pairing_rule.rb +38 -0
- data/lib/uniword/validation/rules/bookmark_uniqueness_rule.rb +48 -0
- data/lib/uniword/validation/rules/bookmarks_rule.rb +0 -2
- data/lib/uniword/validation/rules/content_types_coverage_rule.rb +0 -2
- data/lib/uniword/validation/rules/core_properties_namespace_rule.rb +0 -2
- data/lib/uniword/validation/rules/document_body_rule.rb +25 -0
- data/lib/uniword/validation/rules/document_context.rb +7 -0
- data/lib/uniword/validation/rules/empty_paragraphs_rule.rb +27 -0
- data/lib/uniword/validation/rules/font_table_signature_rule.rb +0 -2
- data/lib/uniword/validation/rules/fonts_rule.rb +0 -2
- data/lib/uniword/validation/rules/footnotes_rule.rb +0 -2
- data/lib/uniword/validation/rules/headers_footers_rule.rb +0 -2
- data/lib/uniword/validation/rules/images_rule.rb +0 -2
- data/lib/uniword/validation/rules/mc_ignorable_namespace_rule.rb +0 -2
- data/lib/uniword/validation/rules/model_context.rb +32 -0
- data/lib/uniword/validation/rules/model_rule.rb +34 -0
- data/lib/uniword/validation/rules/numbering_preservation_rule.rb +0 -2
- data/lib/uniword/validation/rules/numbering_rule.rb +0 -2
- data/lib/uniword/validation/rules/relationship_integrity_rule.rb +0 -1
- data/lib/uniword/validation/rules/rsid_rule.rb +0 -2
- data/lib/uniword/validation/rules/section_properties_rule.rb +0 -2
- data/lib/uniword/validation/rules/settings_rule.rb +0 -2
- data/lib/uniword/validation/rules/settings_values_rule.rb +0 -2
- data/lib/uniword/validation/rules/style_references_rule.rb +0 -2
- data/lib/uniword/validation/rules/table_grid_rule.rb +27 -0
- data/lib/uniword/validation/rules/table_properties_rule.rb +27 -0
- data/lib/uniword/validation/rules/tables_rule.rb +0 -2
- data/lib/uniword/validation/rules/theme_completeness_rule.rb +0 -2
- data/lib/uniword/validation/rules/theme_rule.rb +0 -2
- data/lib/uniword/validation/rules.rb +61 -23
- data/lib/uniword/validation/schema_registry.rb +11 -0
- data/lib/uniword/validation/validators/document_semantics_validator.rb +1 -9
- data/lib/uniword/validation/validators/xml_schema_validator.rb +46 -2
- data/lib/uniword/validation/validators.rb +0 -9
- data/lib/uniword/validation/verify_orchestrator.rb +0 -7
- data/lib/uniword/validation.rb +7 -2
- data/lib/uniword/version.rb +1 -1
- data/lib/uniword/vml/imagedata.rb +0 -1
- data/lib/uniword/wordprocessingml/attached_template.rb +0 -1
- data/lib/uniword/wordprocessingml/deleted_text.rb +1 -1
- data/lib/uniword/wordprocessingml/document_root.rb +121 -122
- data/lib/uniword/wordprocessingml/document_styling.rb +246 -0
- data/lib/uniword/wordprocessingml/endnotes.rb +4 -1
- data/lib/uniword/wordprocessingml/font_replacer.rb +147 -0
- data/lib/uniword/wordprocessingml/footnotes.rb +4 -1
- data/lib/uniword/wordprocessingml/hdr_shape_defaults.rb +0 -1
- data/lib/uniword/wordprocessingml/hyperlink.rb +0 -1
- data/lib/uniword/wordprocessingml/level.rb +6 -20
- data/lib/uniword/wordprocessingml/math_pr.rb +0 -11
- data/lib/uniword/wordprocessingml/numbering_definition.rb +16 -8
- data/lib/uniword/wordprocessingml/numbering_elements.rb +0 -15
- data/lib/uniword/wordprocessingml/page_setup.rb +181 -0
- data/lib/uniword/wordprocessingml/paragraph_properties.rb +33 -28
- data/lib/uniword/wordprocessingml/rsids.rb +0 -2
- data/lib/uniword/wordprocessingml/run.rb +3 -0
- data/lib/uniword/wordprocessingml/section_properties.rb +2 -2
- data/lib/uniword/wordprocessingml/settings.rb +8 -34
- data/lib/uniword/wordprocessingml/shape_defaults.rb +0 -1
- data/lib/uniword/wordprocessingml/style.rb +2 -1
- data/lib/uniword/wordprocessingml/style_cleanup.rb +198 -0
- data/lib/uniword/wordprocessingml/table_cell_properties.rb +6 -6
- data/lib/uniword/wordprocessingml/update_fields.rb +27 -0
- data/lib/uniword/wordprocessingml/w14_attributes.rb +30 -2
- data/lib/uniword/wordprocessingml.rb +5 -2
- data/lib/uniword.rb +27 -2
- metadata +52 -19
- data/config/validation_rules.yml +0 -60
- data/config/warning_rules.yml +0 -57
- data/lib/uniword/validation/document_validator.rb +0 -272
- data/lib/uniword/validation/structural_validator.rb +0 -116
- data/lib/uniword/validation/validators/content_type_validator.rb +0 -165
- data/lib/uniword/validation/validators/file_structure_validator.rb +0 -104
- data/lib/uniword/validation/validators/ooxml_part_validator.rb +0 -128
- data/lib/uniword/validation/validators/relationship_validator.rb +0 -147
- data/lib/uniword/validation/validators/zip_integrity_validator.rb +0 -110
- data/lib/uniword/validators/element_validator.rb +0 -93
- data/lib/uniword/validators/paragraph_validator.rb +0 -116
- data/lib/uniword/validators/table_validator.rb +0 -134
- data/lib/uniword/validators.rb +0 -9
- data/lib/uniword/warnings/warning.rb +0 -130
- data/lib/uniword/warnings/warning_collector.rb +0 -234
- data/lib/uniword/warnings/warning_report.rb +0 -159
- data/lib/uniword/warnings.rb +0 -9
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Uniword
|
|
4
|
+
module Validation
|
|
5
|
+
module Rules
|
|
6
|
+
# In-memory validation context: wraps a document model.
|
|
7
|
+
#
|
|
8
|
+
# Counterpart to DocumentContext (which wraps an on-disk DOCX
|
|
9
|
+
# package). Model-level rules consume this context via the Engine.
|
|
10
|
+
#
|
|
11
|
+
# @example Validate a built document
|
|
12
|
+
# context = ModelContext.new(document)
|
|
13
|
+
# issues = Validation::Engine.run(context)
|
|
14
|
+
class ModelContext
|
|
15
|
+
# @return [Wordprocessingml::DocumentRoot] the document model
|
|
16
|
+
attr_reader :document
|
|
17
|
+
|
|
18
|
+
# @param document [Wordprocessingml::DocumentRoot] in-memory model
|
|
19
|
+
def initialize(document)
|
|
20
|
+
@document = document
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# Context type used by the Engine to select rules.
|
|
24
|
+
#
|
|
25
|
+
# @return [Symbol] :model — this context wraps an in-memory model
|
|
26
|
+
def context_type
|
|
27
|
+
:model
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Uniword
|
|
4
|
+
module Validation
|
|
5
|
+
module Rules
|
|
6
|
+
# Base class for in-memory (model-level) validation rules.
|
|
7
|
+
#
|
|
8
|
+
# Model rules run against a Rules::ModelContext — the pre-save
|
|
9
|
+
# front-end of the validation engine — and inspect the document
|
|
10
|
+
# model directly instead of parsing package XML.
|
|
11
|
+
#
|
|
12
|
+
# @example Implement a model rule
|
|
13
|
+
# class MyModelRule < ModelRule
|
|
14
|
+
# def code = "DOC-900"
|
|
15
|
+
#
|
|
16
|
+
# def check(context)
|
|
17
|
+
# return [] if context.document.body
|
|
18
|
+
#
|
|
19
|
+
# [issue("Document body is missing")]
|
|
20
|
+
# end
|
|
21
|
+
# end
|
|
22
|
+
#
|
|
23
|
+
# Rules::Registry.register(MyModelRule)
|
|
24
|
+
class ModelRule < Base
|
|
25
|
+
# Model rules consume the in-memory ModelContext.
|
|
26
|
+
#
|
|
27
|
+
# @return [Symbol] :model
|
|
28
|
+
def context_type
|
|
29
|
+
:model
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Uniword
|
|
4
|
+
module Validation
|
|
5
|
+
module Rules
|
|
6
|
+
# DOC-204: every table must have a tblGrid.
|
|
7
|
+
#
|
|
8
|
+
# wml.xsd CT_Tbl requires exactly one tblGrid child; without it
|
|
9
|
+
# Word cannot lay out column widths and repairs the document.
|
|
10
|
+
class TableGridRule < ModelRule
|
|
11
|
+
def code = "DOC-204"
|
|
12
|
+
def category = :tables
|
|
13
|
+
def severity = "error"
|
|
14
|
+
|
|
15
|
+
def check(context)
|
|
16
|
+
context.document.tables.each_with_index.filter_map do |table, idx|
|
|
17
|
+
next if table.grid
|
|
18
|
+
|
|
19
|
+
issue("Table #{idx + 1} is missing the required tblGrid element",
|
|
20
|
+
part: "word/document.xml",
|
|
21
|
+
suggestion: "Add a w:tblGrid with one w:gridCol per column.")
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Uniword
|
|
4
|
+
module Validation
|
|
5
|
+
module Rules
|
|
6
|
+
# DOC-205: every table must have table properties (tblPr).
|
|
7
|
+
#
|
|
8
|
+
# wml.xsd CT_Tbl requires exactly one tblPr child as the table's
|
|
9
|
+
# first property element.
|
|
10
|
+
class TablePropertiesRule < ModelRule
|
|
11
|
+
def code = "DOC-205"
|
|
12
|
+
def category = :tables
|
|
13
|
+
def severity = "error"
|
|
14
|
+
|
|
15
|
+
def check(context)
|
|
16
|
+
context.document.tables.each_with_index.filter_map do |table, idx|
|
|
17
|
+
next if table.properties
|
|
18
|
+
|
|
19
|
+
issue("Table #{idx + 1} is missing the required tblPr element",
|
|
20
|
+
part: "word/document.xml",
|
|
21
|
+
suggestion: "Add a w:tblPr element to the table.")
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -1,30 +1,68 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
3
|
+
module Uniword
|
|
4
|
+
module Validation
|
|
5
|
+
# Document semantic validation rules and their registry.
|
|
6
|
+
module Rules
|
|
7
|
+
autoload :Base, "#{__dir__}/rules/base"
|
|
8
|
+
autoload :Registry, "#{__dir__}/rules/registry"
|
|
9
|
+
autoload :DocumentContext, "#{__dir__}/rules/document_context"
|
|
10
|
+
autoload :ModelContext, "#{__dir__}/rules/model_context"
|
|
11
|
+
autoload :ModelRule, "#{__dir__}/rules/model_rule"
|
|
12
|
+
autoload :DocumentBodyRule, "#{__dir__}/rules/document_body_rule"
|
|
13
|
+
autoload :BookmarkPairingRule,
|
|
14
|
+
"#{__dir__}/rules/bookmark_pairing_rule"
|
|
15
|
+
autoload :BookmarkUniquenessRule,
|
|
16
|
+
"#{__dir__}/rules/bookmark_uniqueness_rule"
|
|
17
|
+
autoload :EmptyParagraphsRule,
|
|
18
|
+
"#{__dir__}/rules/empty_paragraphs_rule"
|
|
19
|
+
autoload :TableGridRule, "#{__dir__}/rules/table_grid_rule"
|
|
20
|
+
autoload :TablePropertiesRule,
|
|
21
|
+
"#{__dir__}/rules/table_properties_rule"
|
|
22
|
+
autoload :StyleReferencesRule,
|
|
23
|
+
"#{__dir__}/rules/style_references_rule"
|
|
24
|
+
autoload :NumberingRule, "#{__dir__}/rules/numbering_rule"
|
|
25
|
+
autoload :FootnotesRule, "#{__dir__}/rules/footnotes_rule"
|
|
26
|
+
autoload :HeadersFootersRule,
|
|
27
|
+
"#{__dir__}/rules/headers_footers_rule"
|
|
28
|
+
autoload :BookmarksRule, "#{__dir__}/rules/bookmarks_rule"
|
|
29
|
+
autoload :ImagesRule, "#{__dir__}/rules/images_rule"
|
|
30
|
+
autoload :TablesRule, "#{__dir__}/rules/tables_rule"
|
|
31
|
+
autoload :FontsRule, "#{__dir__}/rules/fonts_rule"
|
|
32
|
+
autoload :ThemeRule, "#{__dir__}/rules/theme_rule"
|
|
33
|
+
autoload :SettingsRule, "#{__dir__}/rules/settings_rule"
|
|
34
|
+
autoload :McIgnorableNamespaceRule,
|
|
35
|
+
"#{__dir__}/rules/mc_ignorable_namespace_rule"
|
|
36
|
+
autoload :SettingsValuesRule,
|
|
37
|
+
"#{__dir__}/rules/settings_values_rule"
|
|
38
|
+
autoload :ThemeCompletenessRule,
|
|
39
|
+
"#{__dir__}/rules/theme_completeness_rule"
|
|
40
|
+
autoload :NumberingPreservationRule,
|
|
41
|
+
"#{__dir__}/rules/numbering_preservation_rule"
|
|
42
|
+
autoload :SectionPropertiesRule,
|
|
43
|
+
"#{__dir__}/rules/section_properties_rule"
|
|
44
|
+
autoload :CorePropertiesNamespaceRule,
|
|
45
|
+
"#{__dir__}/rules/core_properties_namespace_rule"
|
|
46
|
+
autoload :ContentTypesCoverageRule,
|
|
47
|
+
"#{__dir__}/rules/content_types_coverage_rule"
|
|
48
|
+
autoload :FontTableSignatureRule,
|
|
49
|
+
"#{__dir__}/rules/font_table_signature_rule"
|
|
50
|
+
autoload :RelationshipIntegrityRule,
|
|
51
|
+
"#{__dir__}/rules/relationship_integrity_rule"
|
|
52
|
+
autoload :RsidRule, "#{__dir__}/rules/rsid_rule"
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
26
56
|
|
|
27
57
|
# Register all built-in validation rules
|
|
58
|
+
# Model-level (in-memory) rules
|
|
59
|
+
Uniword::Validation::Rules::Registry.register(Uniword::Validation::Rules::DocumentBodyRule)
|
|
60
|
+
Uniword::Validation::Rules::Registry.register(Uniword::Validation::Rules::BookmarkPairingRule)
|
|
61
|
+
Uniword::Validation::Rules::Registry.register(Uniword::Validation::Rules::BookmarkUniquenessRule)
|
|
62
|
+
Uniword::Validation::Rules::Registry.register(Uniword::Validation::Rules::EmptyParagraphsRule)
|
|
63
|
+
Uniword::Validation::Rules::Registry.register(Uniword::Validation::Rules::TableGridRule)
|
|
64
|
+
Uniword::Validation::Rules::Registry.register(Uniword::Validation::Rules::TablePropertiesRule)
|
|
65
|
+
# Package-level (on-disk) rules
|
|
28
66
|
Uniword::Validation::Rules::Registry.register(Uniword::Validation::Rules::StyleReferencesRule)
|
|
29
67
|
Uniword::Validation::Rules::Registry.register(Uniword::Validation::Rules::NumberingRule)
|
|
30
68
|
Uniword::Validation::Rules::Registry.register(Uniword::Validation::Rules::FootnotesRule)
|
|
@@ -57,6 +57,7 @@ module Uniword
|
|
|
57
57
|
word/document.xml
|
|
58
58
|
word/styles.xml
|
|
59
59
|
word/settings.xml
|
|
60
|
+
word/webSettings.xml
|
|
60
61
|
word/fontTable.xml
|
|
61
62
|
word/numbering.xml
|
|
62
63
|
word/footnotes.xml
|
|
@@ -64,6 +65,13 @@ module Uniword
|
|
|
64
65
|
word/comments.xml
|
|
65
66
|
].freeze
|
|
66
67
|
|
|
68
|
+
# Document property parts and their primary schemas.
|
|
69
|
+
DOCPROPS_SCHEMAS = {
|
|
70
|
+
"docProps/core.xml" => "ecma/opc-coreProperties.xsd",
|
|
71
|
+
"docProps/app.xml" => "iso/shared-documentPropertiesExtended.xsd",
|
|
72
|
+
"docProps/custom.xml" => "iso/shared-documentPropertiesCustom.xsd",
|
|
73
|
+
}.freeze
|
|
74
|
+
|
|
67
75
|
# Pattern for header/footer parts
|
|
68
76
|
HEADER_FOOTER_PATTERN = %r{\Aword/(header|footer)\d*\.xml\z}
|
|
69
77
|
|
|
@@ -115,6 +123,7 @@ module Uniword
|
|
|
115
123
|
# For Word parts (document.xml, styles.xml, etc.), returns wml-2010.xsd
|
|
116
124
|
# which imports the base wml.xsd and all extension schemas.
|
|
117
125
|
# For relationship and content type parts, returns the appropriate schema.
|
|
126
|
+
# For docProps parts, returns the OPC/extended/custom properties schema.
|
|
118
127
|
#
|
|
119
128
|
# @param part_name [String] Path within ZIP (e.g., "word/document.xml")
|
|
120
129
|
# @return [String, nil] XSD path relative to schemas_dir
|
|
@@ -124,6 +133,8 @@ module Uniword
|
|
|
124
133
|
"ecma/opc-contentTypes.xsd"
|
|
125
134
|
when "_rels/.rels", ->(n) { n.match?(RELS_PATTERN) }
|
|
126
135
|
"ecma/opc-relationships.xsd"
|
|
136
|
+
when *DOCPROPS_SCHEMAS.keys
|
|
137
|
+
DOCPROPS_SCHEMAS[part_name]
|
|
127
138
|
when *WORDML_PARTS, ->(n) { n.match?(HEADER_FOOTER_PATTERN) }
|
|
128
139
|
"microsoft/wml-2010.xsd"
|
|
129
140
|
when ->(n) { n.match?(THEME_PATTERN) }
|
|
@@ -2,8 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
require "zip"
|
|
4
4
|
require "nokogiri"
|
|
5
|
-
require_relative "../rules"
|
|
6
|
-
require_relative "../report/validation_issue"
|
|
7
5
|
# LayerValidator autoloaded via lib/uniword/validation.rb
|
|
8
6
|
|
|
9
7
|
module Uniword
|
|
@@ -29,15 +27,9 @@ module Uniword
|
|
|
29
27
|
|
|
30
28
|
def validate(path)
|
|
31
29
|
issues = []
|
|
32
|
-
|
|
33
30
|
context = Rules::DocumentContext.new(path)
|
|
34
31
|
begin
|
|
35
|
-
|
|
36
|
-
rules.each do |rule|
|
|
37
|
-
next unless rule.applicable?(context)
|
|
38
|
-
|
|
39
|
-
issues.concat(rule.check(context))
|
|
40
|
-
end
|
|
32
|
+
issues = Engine.run(context)
|
|
41
33
|
ensure
|
|
42
34
|
context.close
|
|
43
35
|
end
|
|
@@ -2,8 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
require "zip"
|
|
4
4
|
require "nokogiri"
|
|
5
|
-
require_relative "../schema_registry"
|
|
6
|
-
require_relative "../report/validation_issue"
|
|
7
5
|
# LayerValidator autoloaded via lib/uniword/validation.rb
|
|
8
6
|
|
|
9
7
|
module Uniword
|
|
@@ -22,6 +20,11 @@ module Uniword
|
|
|
22
20
|
# validator = XmlSchemaValidator.new("xml_schema" => { "xsd_validation" => true })
|
|
23
21
|
# result = validator.validate('/path/to/document.docx')
|
|
24
22
|
class XmlSchemaValidator < LayerValidator
|
|
23
|
+
# Markup Compatibility namespace — the mc:Ignorable attribute
|
|
24
|
+
# itself lives here and is stripped during MCE preprocessing.
|
|
25
|
+
MCE_NAMESPACE_URI =
|
|
26
|
+
"http://schemas.openxmlformats.org/markup-compatibility/2006"
|
|
27
|
+
|
|
25
28
|
def layer_name
|
|
26
29
|
"XSD Schema"
|
|
27
30
|
end
|
|
@@ -85,6 +88,7 @@ module Uniword
|
|
|
85
88
|
content = entry.get_input_stream.read
|
|
86
89
|
schema = registry.load_schema(schema_path)
|
|
87
90
|
doc = Nokogiri::XML(content)
|
|
91
|
+
preprocess_mce(doc)
|
|
88
92
|
|
|
89
93
|
schema.validate(doc).each do |error|
|
|
90
94
|
issues << Report::ValidationIssue.new(
|
|
@@ -116,6 +120,46 @@ module Uniword
|
|
|
116
120
|
end
|
|
117
121
|
end
|
|
118
122
|
|
|
123
|
+
# Strip MCE-ignorable ATTRIBUTES per the part's own mc:Ignorable
|
|
124
|
+
# declaration (w14:paraId/textId and the mc:Ignorable attribute
|
|
125
|
+
# itself), so XSD validation is not drowned in false errors for
|
|
126
|
+
# content every real document carries.
|
|
127
|
+
#
|
|
128
|
+
# Extension ELEMENTS are deliberately kept: removing them changes
|
|
129
|
+
# libxml2's content-model evaluation and can expose pre-existing
|
|
130
|
+
# Word-vs-schema quirks (e.g. rsids placed late, tolerated via the
|
|
131
|
+
# sequence's trailing xsd:any) as false baseline errors.
|
|
132
|
+
# Operates in place on the parsed document; never touches the
|
|
133
|
+
# packaged bytes.
|
|
134
|
+
#
|
|
135
|
+
# @param doc [Nokogiri::XML::Document] parsed part to clean
|
|
136
|
+
# @return [void]
|
|
137
|
+
def preprocess_mce(doc)
|
|
138
|
+
root = doc.root
|
|
139
|
+
return unless root
|
|
140
|
+
|
|
141
|
+
ignorable = root["Ignorable"] || root["mc:Ignorable"]
|
|
142
|
+
return if ignorable.nil? || ignorable.empty?
|
|
143
|
+
|
|
144
|
+
uris = ignorable.split(/\s+/).filter_map do |prefix|
|
|
145
|
+
root.namespaces["xmlns:#{prefix}"]
|
|
146
|
+
end
|
|
147
|
+
# The mc:Ignorable attribute itself is MCE machinery and is
|
|
148
|
+
# undeclared on most root elements in the transitional XSDs.
|
|
149
|
+
strip_mce_attributes(root, uris + [MCE_NAMESPACE_URI])
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
# Remove attributes in ignorable namespaces from every element.
|
|
153
|
+
def strip_mce_attributes(doc, uris)
|
|
154
|
+
doc.traverse do |node|
|
|
155
|
+
next unless node.element?
|
|
156
|
+
|
|
157
|
+
node.attribute_nodes.each do |attr|
|
|
158
|
+
attr.remove if uris.include?(attr.namespace&.href)
|
|
159
|
+
end
|
|
160
|
+
end
|
|
161
|
+
end
|
|
162
|
+
|
|
119
163
|
def check_unknown_namespaces(registry, content, part_name, issues)
|
|
120
164
|
ns_uris = registry.detect_namespaces(content)
|
|
121
165
|
unknown = registry.unknown_namespaces(ns_uris)
|
|
@@ -3,16 +3,7 @@
|
|
|
3
3
|
module Uniword
|
|
4
4
|
module Validation
|
|
5
5
|
module Validators
|
|
6
|
-
autoload :FileStructureValidator,
|
|
7
|
-
"#{__dir__}/validators/file_structure_validator"
|
|
8
|
-
autoload :ZipIntegrityValidator,
|
|
9
|
-
"#{__dir__}/validators/zip_integrity_validator"
|
|
10
|
-
autoload :OoxmlPartValidator, "#{__dir__}/validators/ooxml_part_validator"
|
|
11
6
|
autoload :XmlSchemaValidator, "#{__dir__}/validators/xml_schema_validator"
|
|
12
|
-
autoload :RelationshipValidator,
|
|
13
|
-
"#{__dir__}/validators/relationship_validator"
|
|
14
|
-
autoload :ContentTypeValidator,
|
|
15
|
-
"#{__dir__}/validators/content_type_validator"
|
|
16
7
|
autoload :DocumentSemanticsValidator,
|
|
17
8
|
"#{__dir__}/validators/document_semantics_validator"
|
|
18
9
|
end
|
|
@@ -1,13 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require "time"
|
|
4
|
-
require_relative "opc_validator"
|
|
5
|
-
require_relative "schema_registry"
|
|
6
|
-
require_relative "report/verification_report"
|
|
7
|
-
require_relative "report/layer_result"
|
|
8
|
-
require_relative "report/terminal_formatter"
|
|
9
|
-
require_relative "validators/xml_schema_validator"
|
|
10
|
-
require_relative "validators/document_semantics_validator"
|
|
11
4
|
|
|
12
5
|
module Uniword
|
|
13
6
|
module Validation
|
data/lib/uniword/validation.rb
CHANGED
|
@@ -9,9 +9,14 @@ module Uniword
|
|
|
9
9
|
autoload :LayerValidator, "#{__dir__}/validation/layer_validator"
|
|
10
10
|
autoload :LayerValidationResult,
|
|
11
11
|
"#{__dir__}/validation/layer_validation_result"
|
|
12
|
-
autoload :DocumentValidator, "#{__dir__}/validation/document_validator"
|
|
13
12
|
autoload :Checkers, "#{__dir__}/validation/checkers"
|
|
14
13
|
autoload :Validators, "#{__dir__}/validation/validators"
|
|
15
|
-
autoload :
|
|
14
|
+
autoload :Engine, "#{__dir__}/validation/engine"
|
|
15
|
+
autoload :OpcValidator, "#{__dir__}/validation/opc_validator"
|
|
16
|
+
autoload :SchemaRegistry, "#{__dir__}/validation/schema_registry"
|
|
17
|
+
autoload :VerifyOrchestrator,
|
|
18
|
+
"#{__dir__}/validation/verify_orchestrator"
|
|
19
|
+
autoload :Rules, "#{__dir__}/validation/rules"
|
|
20
|
+
autoload :Report, "#{__dir__}/validation/report"
|
|
16
21
|
end
|
|
17
22
|
end
|
data/lib/uniword/version.rb
CHANGED