Class: Uniword::Docx::Package
- Inherits:
-
Lutaml::Model::Serializable
- Object
- Lutaml::Model::Serializable
- Uniword::Docx::Package
- Includes:
- PackageDefaults, PackageSerialization
- Defined in:
- lib/uniword/docx/package.rb
Overview
DOCX Package - Complete DOCX file format model
Represents the entire .docx file structure as a lutaml-model object. Each XML file within the ZIP is a separate lutaml-model class.
A DOCX package CONTAINS OOXML markup wrapped in an OPC ZIP container. This class lives in Uniword::Docx, not Uniword::Ooxml, because DOCX is a file format that uses OOXML, not the other way around.
Constant Summary
Constants included from PackageSerialization
Uniword::Docx::PackageSerialization::DOCX_INFRA_OPTIONS, Uniword::Docx::PackageSerialization::DOCX_PART_OPTIONS, Uniword::Docx::PackageSerialization::DOCX_PROPS_OPTIONS, Uniword::Docx::PackageSerialization::DOCX_XML_OPTIONS
Instance Attribute Summary collapse
-
#allocator ⇒ Object
Central ID allocator — owns all rId, footnote, bookmark, etc.
-
#custom_xml_items ⇒ Array<CustomXmlItem>?
Custom XML data items (customXml/item*.xml).
-
#endnotes_rels ⇒ Object
Returns the value of attribute endnotes_rels.
-
#footnotes_rels ⇒ Object
Returns the value of attribute footnotes_rels.
-
#modified_part_paths ⇒ Object
Paths that have been modified and should not use raw XML passthrough.
-
#profile ⇒ Object
Non-serialized attributes (DOCX packaging helpers).
-
#raw_xml_parts ⇒ Object
Raw XML from template ZIP for unmodified parts.
-
#settings_rels ⇒ Object
Returns the value of attribute settings_rels.
Class Method Summary collapse
-
.from_file(path) ⇒ Package
Load DOCX package from file.
-
.from_zip_content(zip_content, zip_path = nil) ⇒ Package
Create package from extracted ZIP content.
-
.to_file(document, path, profile: nil, validate: nil) ⇒ void
Save document to file (class method for DocumentWriter compatibility).
Instance Method Summary collapse
-
#add_stripped_part(path:, reason:) ⇒ void
Record a stripped part.
-
#applied_fixes ⇒ Array<Reconciler::Fix>
Audit trail of repairs applied by the Reconciler during the most recent save (to_zip_content).
- #body ⇒ Object
- #charts ⇒ Object
- #each_paragraph ⇒ Object
-
#embeddings ⇒ PartCollection
OLE/embedded object binaries (word/embeddings/*), keyed by target.
-
#embeddings=(value) ⇒ Object
Bulk-assign embeddings (Hash of target => Part/binary; nil clears).
-
#paragraphs ⇒ Object
Delegate common DocumentRoot methods for API compatibility.
-
#populate_allocator ⇒ Object
Populate the allocator from all existing template data.
-
#prepare_allocator ⇒ Object
Guarantee the single rId authority before reconciliation: reuse the package's allocator (loaded/builder-seeded) or start one, then seed it from the package's current relationships.
-
#raw_parts ⇒ PartCollection
Raw passthrough parts no registry definition models, keyed by package path ("docProps/meta.xml", "word/glossary/document.xml", ...).
-
#raw_parts=(value) ⇒ Object
Bulk-assign raw parts (Hash of path => RawPart/hash; nil clears).
-
#reorder_content_hash(content) ⇒ Object
Ensure [Content_Types].xml is first, _rels/.rels is second.
-
#stripped_parts ⇒ Array<StrippedPart>
Parts stripped at load because they were non-compliant (no content type declaration, OS artifact, ...).
- #styles_configuration ⇒ Object
- #tables ⇒ Object
- #text ⇒ Object
-
#to_file(path, validate: nil) ⇒ void
(also: #save)
Save package to file.
-
#to_zip_content(validate: nil) ⇒ Hash
Generate ZIP content hash.
Methods included from PackageSerialization
#add_standalone, #inject_part_relationships, #serialize_infrastructure, #serialize_package_parts, #serialize_part
Methods included from PackageDefaults
Instance Attribute Details
#allocator ⇒ Object
Central ID allocator — owns all rId, footnote, bookmark, etc. assignment. Seeded from template rels on load; used by builders during construction.
130 131 132 |
# File 'lib/uniword/docx/package.rb', line 130 def allocator @allocator end |
#custom_xml_items ⇒ Array<CustomXmlItem>?
Custom XML data items (customXml/item*.xml)
49 50 51 |
# File 'lib/uniword/docx/package.rb', line 49 def custom_xml_items @custom_xml_items end |
#endnotes_rels ⇒ Object
Returns the value of attribute endnotes_rels.
98 99 100 |
# File 'lib/uniword/docx/package.rb', line 98 def endnotes_rels @endnotes_rels end |
#footnotes_rels ⇒ Object
Returns the value of attribute footnotes_rels.
98 99 100 |
# File 'lib/uniword/docx/package.rb', line 98 def footnotes_rels @footnotes_rels end |
#modified_part_paths ⇒ Object
Paths that have been modified and should not use raw XML passthrough.
138 139 140 |
# File 'lib/uniword/docx/package.rb', line 138 def modified_part_paths @modified_part_paths end |
#profile ⇒ Object
Non-serialized attributes (DOCX packaging helpers)
97 98 99 |
# File 'lib/uniword/docx/package.rb', line 97 def profile @profile end |
#raw_xml_parts ⇒ Object
Raw XML from template ZIP for unmodified parts. When present, these are used verbatim instead of re-serializing through lutaml-model (which drops unmapped elements).
135 136 137 |
# File 'lib/uniword/docx/package.rb', line 135 def raw_xml_parts @raw_xml_parts end |
#settings_rels ⇒ Object
Returns the value of attribute settings_rels.
98 99 100 |
# File 'lib/uniword/docx/package.rb', line 98 def settings_rels @settings_rels end |
Class Method Details
.from_file(path) ⇒ Package
Load DOCX package from file
176 177 178 179 180 181 182 |
# File 'lib/uniword/docx/package.rb', line 176 def self.from_file(path) extractor = Infrastructure::ZipExtractor.new zip_content = extractor.extract(path) package = from_zip_content(zip_content, path) package.populate_allocator package end |
.from_zip_content(zip_content, zip_path = nil) ⇒ Package
Create package from extracted ZIP content
Parts load by iterating Ooxml::PartRegistry.loadable and dispatching each definition to its Docx::PartLoader strategy — see PartLoader for the load order and strategy registry.
193 194 195 196 197 |
# File 'lib/uniword/docx/package.rb', line 193 def self.from_zip_content(zip_content, zip_path = nil) package = new PartLoader.load(zip_content, package, zip_path: zip_path) package end |
.to_file(document, path, profile: nil, validate: nil) ⇒ void
This method returns an undefined value.
Save document to file (class method for DocumentWriter compatibility)
207 208 209 210 211 212 213 214 215 216 217 218 219 |
# File 'lib/uniword/docx/package.rb', line 207 def self.to_file(document, path, profile: nil, validate: nil) package = new package.document = document package.profile = profile || Profile.defaults copy_document_parts_to_package(document, package) package.content_types ||= minimal_content_types package.package_rels ||= minimal_package_rels package.document_rels ||= minimal_document_rels package.settings ||= Uniword::Wordprocessingml::Settings.new package.font_table ||= Uniword::Wordprocessingml::FontTable.new package.web_settings ||= Uniword::Wordprocessingml::WebSettings.new package.to_file(path, validate: validate) end |
Instance Method Details
#add_stripped_part(path:, reason:) ⇒ void
This method returns an undefined value.
Record a stripped part. Append-only; used by the loader.
168 169 170 |
# File 'lib/uniword/docx/package.rb', line 168 def add_stripped_part(path:, reason:) stripped_parts << StrippedPart.new(path: path, reason: reason) end |
#applied_fixes ⇒ Array<Reconciler::Fix>
Audit trail of repairs applied by the Reconciler during the most recent save (to_zip_content). Empty before the first save and when the package needed no repairs.
145 146 147 |
# File 'lib/uniword/docx/package.rb', line 145 def applied_fixes @applied_fixes ||= [] end |
#body ⇒ Object
320 321 322 |
# File 'lib/uniword/docx/package.rb', line 320 def body document&.body end |
#charts ⇒ Object
334 335 336 |
# File 'lib/uniword/docx/package.rb', line 334 def charts document&.charts || [] end |
#each_paragraph ⇒ Object
328 329 330 |
# File 'lib/uniword/docx/package.rb', line 328 def each_paragraph(&) paragraphs.each(&) end |
#embeddings ⇒ PartCollection
OLE/embedded object binaries (word/embeddings/*), keyed by target.
103 104 105 |
# File 'lib/uniword/docx/package.rb', line 103 def @embeddings ||= PartCollection.new(:target, Part) end |
#embeddings=(value) ⇒ Object
Bulk-assign embeddings (Hash of target => Part/binary; nil clears).
108 109 110 |
# File 'lib/uniword/docx/package.rb', line 108 def (value) .replace_all(value) end |
#paragraphs ⇒ Object
Delegate common DocumentRoot methods for API compatibility
312 313 314 |
# File 'lib/uniword/docx/package.rb', line 312 def paragraphs document&.paragraphs || [] end |
#populate_allocator ⇒ Object
Populate the allocator from all existing template data. Must be called BEFORE any builder runs (populate-first principle).
223 224 225 |
# File 'lib/uniword/docx/package.rb', line 223 def populate_allocator @allocator = IdAllocator.populate_from_package(self) end |
#prepare_allocator ⇒ Object
Guarantee the single rId authority before reconciliation: reuse the package's allocator (loaded/builder-seeded) or start one, then seed it from the package's current relationships. Seeding preserves loaded rIds verbatim; earlier builder allocations keep their ids — a seeded rel whose id collides is reallocated deterministically (IdAllocator#seed_from_rels).
233 234 235 236 237 238 239 |
# File 'lib/uniword/docx/package.rb', line 233 def prepare_allocator self.allocator ||= IdAllocator.new allocator.seed_from_rels(package_rels&.relationships, scope: :package) allocator.seed_from_rels(document_rels&.relationships) allocator end |
#raw_parts ⇒ PartCollection
Raw passthrough parts no registry definition models, keyed by package path ("docProps/meta.xml", "word/glossary/document.xml", ...). Carried byte-for-byte from load to save — see PartLoader::RawPartLoader for claiming and PackageSerialization#serialize_raw_parts for emission.
119 120 121 |
# File 'lib/uniword/docx/package.rb', line 119 def raw_parts @raw_parts ||= PartCollection.new(:path, RawPart) end |
#raw_parts=(value) ⇒ Object
Bulk-assign raw parts (Hash of path => RawPart/hash; nil clears).
124 125 126 |
# File 'lib/uniword/docx/package.rb', line 124 def raw_parts=(value) raw_parts.replace_all(value) end |
#reorder_content_hash(content) ⇒ Object
Ensure [Content_Types].xml is first, _rels/.rels is second.
303 304 305 306 307 308 |
# File 'lib/uniword/docx/package.rb', line 303 def reorder_content_hash(content) priority = {} priority["[Content_Types].xml"] = content.delete("[Content_Types].xml") if content.key?("[Content_Types].xml") priority["_rels/.rels"] = content.delete("_rels/.rels") if content.key?("_rels/.rels") content.replace(priority.merge(content)) end |
#stripped_parts ⇒ Array<StrippedPart>
Parts stripped at load because they were non-compliant (no
content type declaration, OS artifact, ...). Populated by
Docx::PartLoader::RawPartLoader when
Uniword.configuration.on_noncompliant_content is :strip
(the default). Empty in :raise mode and for packages
constructed by hand.
158 159 160 |
# File 'lib/uniword/docx/package.rb', line 158 def stripped_parts @stripped_parts ||= [] end |
#styles_configuration ⇒ Object
338 339 340 |
# File 'lib/uniword/docx/package.rb', line 338 def styles_configuration document&.styles_configuration end |
#tables ⇒ Object
316 317 318 |
# File 'lib/uniword/docx/package.rb', line 316 def tables document&.tables || [] end |
#text ⇒ Object
324 325 326 |
# File 'lib/uniword/docx/package.rb', line 324 def text document&.text || "" end |
#to_file(path, validate: nil) ⇒ void Also known as: save
This method returns an undefined value.
Save package to file
249 250 251 252 253 |
# File 'lib/uniword/docx/package.rb', line 249 def to_file(path, validate: nil) zip_content = to_zip_content(validate: validate) packager = Infrastructure::ZipPackager.new packager.package(zip_content, path) end |
#to_zip_content(validate: nil) ⇒ Hash
Generate ZIP content hash
Runs the Reconciler (the only mutating pass), records its repair report on #applied_fixes, and — unless validation is disabled — refuses invalid output via the PackageIntegrityChecker gate.
266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 |
# File 'lib/uniword/docx/package.rb', line 266 def to_zip_content(validate: nil) content = {} self.content_types ||= self.class.minimal_content_types self.package_rels ||= self.class.minimal_package_rels self.document_rels ||= self.class.minimal_document_rels self.settings ||= Uniword::Wordprocessingml::Settings.new self.font_table ||= Uniword::Wordprocessingml::FontTable.new self.web_settings ||= Uniword::Wordprocessingml::WebSettings.new # An allocator carried into the save (builder-managed document # or loaded package) selects light-touch repairs; documents # without one get the full normalization repertoire. rIds flow # through the allocator either way. builder_managed = !allocator.nil? prepare_allocator reconciler = Reconciler.new(self, profile: profile || Profile.defaults, allocator: allocator, builder_managed: builder_managed) reconciler.reconcile @applied_fixes = reconciler.applied_fixes log_applied_fixes inject_part_relationships(content, content_types, package_rels, document_rels) serialize_package_parts(content, content_types, package_rels, document_rels) # OOXML requires [Content_Types].xml as the first ZIP entry. reorder_content_hash(content) enforce_package_integrity(content, validate) content end |