Class: Uniword::Ooxml::DotxPackage

Inherits:
Lutaml::Model::Serializable
  • Object
show all
Defined in:
lib/uniword/ooxml/dotx_package.rb

Overview

DOTX/DOTM Package - Word Template formats

Represents .dotx (template) and .dotm (macro-enabled template) files. Structure is identical to DOCX but used as document templates. Templates often contain StyleSets and building blocks.

This is the CORRECT OOP approach:

  • ONE model class for the container

  • Each XML part is a proper model attribute

  • No serializer/deserializer anti-pattern

Examples:

Load template

package = DotxPackage.from_file('template.dotx')
package.core_properties.title = 'New Template Title'
package.to_file('output.dotx')

Direct Known Subclasses

StyleSetPackage

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#raw_document_xmlObject

Access raw document XML (for compatibility)



185
186
187
# File 'lib/uniword/ooxml/dotx_package.rb', line 185

def raw_document_xml
  @raw_document_xml
end

Class Method Details

.from_file(path) ⇒ Document

Load DOTX/DOTM package from file

Parameters:

  • path (String)

    Path to .dotx or .dotm file

Returns:

  • (Document)

    Loaded document (Generated::Wordprocessingml::DocumentRoot)



67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
# File 'lib/uniword/ooxml/dotx_package.rb', line 67

def self.from_file(path)
  # Extract ZIP content
  extractor = Infrastructure::ZipExtractor.new
  zip_content = extractor.extract(path)

  # Parse package with properties and theme
  package = from_zip_content(zip_content)

  # Parse main document XML using generated classes
  # Document is aliased in lib/uniword.rb to Generated::Wordprocessingml::DocumentRoot
  document = if package.raw_document_xml
               Uniword::Wordprocessingml::DocumentRoot.from_xml(package.raw_document_xml)
             else
               Uniword::Wordprocessingml::DocumentRoot.new
             end

  # Transfer properties from package to document
  document.core_properties = package.core_properties if package.core_properties
  document.app_properties = package.app_properties if package.app_properties
  document.theme = package.theme if package.theme

  # Transfer model-based configurations
  document.styles_configuration = package.styles_configuration if package.styles_configuration
  document.numbering_configuration = package.numbering_configuration if package.numbering_configuration
  document.settings = package.settings if package.settings
  document.font_table = package.font_table if package.font_table
  document.web_settings = package.web_settings if package.web_settings
  document.document_rels = package.document_rels if package.document_rels
  document.content_types = package.content_types if package.content_types
  document.package_rels = package.package_rels if package.package_rels
  document.footnotes = package.footnotes if package.footnotes
  document.endnotes = package.endnotes if package.endnotes

  document
end

.from_zip_content(zip_content) ⇒ DotxPackage

Create package from extracted ZIP content

Parameters:

  • zip_content (Hash)

    Extracted ZIP files

Returns:



107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
# File 'lib/uniword/ooxml/dotx_package.rb', line 107

def self.from_zip_content(zip_content)
  package = new

  # Parse lutaml-model files
  package.core_properties = CoreProperties.from_xml(zip_content["docProps/core.xml"]) if zip_content["docProps/core.xml"]

  package.app_properties = AppProperties.from_xml(zip_content["docProps/app.xml"]) if zip_content["docProps/app.xml"]

  package.theme = Uniword::Drawingml::Theme.from_xml(zip_content["word/theme/theme1.xml"]) if zip_content["word/theme/theme1.xml"]

  # Parse styles and numbering as models
  package.styles_configuration = Uniword::Wordprocessingml::StylesConfiguration.from_xml(zip_content["word/styles.xml"]) if zip_content["word/styles.xml"]

  package.numbering_configuration = Uniword::Wordprocessingml::NumberingConfiguration.from_xml(zip_content["word/numbering.xml"]) if zip_content["word/numbering.xml"]

  # Store raw document XML (will be parsed by DotxHandler)
  package.raw_document_xml = zip_content["word/document.xml"] if zip_content["word/document.xml"]

  # Parse settings
  if zip_content["word/settings.xml"]
    package.settings = Uniword::Wordprocessingml::Settings.from_xml(
      zip_content["word/settings.xml"],
    )
  end

  # Parse font table
  if zip_content["word/fontTable.xml"]
    package.font_table = Uniword::Wordprocessingml::FontTable.from_xml(
      zip_content["word/fontTable.xml"],
    )
  end

  # Parse web settings
  if zip_content["word/webSettings.xml"]
    package.web_settings = Uniword::Wordprocessingml::WebSettings.from_xml(
      zip_content["word/webSettings.xml"],
    )
  end

  # Parse content types
  if zip_content["[Content_Types].xml"]
    package.content_types = Uniword::ContentTypes::Types.from_xml(
      zip_content["[Content_Types].xml"],
    )
  end

  # Parse package relationships
  if zip_content["_rels/.rels"]
    package.package_rels = Uniword::Ooxml::Relationships::PackageRelationships.from_xml(
      zip_content["_rels/.rels"],
    )
  end

  # Parse document relationships
  if zip_content["word/_rels/document.xml.rels"]
    package.document_rels = Uniword::Ooxml::Relationships::PackageRelationships.from_xml(
      zip_content["word/_rels/document.xml.rels"],
    )
  end

  # Parse footnotes
  if zip_content["word/footnotes.xml"]
    package.footnotes = Uniword::Wordprocessingml::Footnotes.from_xml(
      zip_content["word/footnotes.xml"],
    )
  end

  # Parse endnotes
  if zip_content["word/endnotes.xml"]
    package.endnotes = Uniword::Wordprocessingml::Endnotes.from_xml(
      zip_content["word/endnotes.xml"],
    )
  end

  package
end

.supported_extensionsArray<String>

Get supported file extensions

Returns:

  • (Array<String>)

    Array of supported extensions



190
191
192
# File 'lib/uniword/ooxml/dotx_package.rb', line 190

def self.supported_extensions
  [".dotx", ".dotm"]
end

.to_file(document, path, profile: nil) ⇒ Object

Save document to file

Parameters:

  • document (Document)

    The document to save (Generated::Wordprocessingml::DocumentRoot)

  • path (String)

    Output path



198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
# File 'lib/uniword/ooxml/dotx_package.rb', line 198

def self.to_file(document, path, profile: nil)
  # Create package
  package = new

  # Transfer properties to package
  package.core_properties = document.core_properties || CoreProperties.new
  package.app_properties = document.app_properties || AppProperties.new
  package.theme = document.theme

  # Transfer model-based configurations
  package.styles_configuration = document.styles_configuration
  package.numbering_configuration = document.numbering_configuration

  # Serialize main document
  package.raw_document_xml = document.to_xml(encoding: "UTF-8")

  # Generate ZIP content
  zip_content = package.to_zip_content

  # Add required OOXML infrastructure files
  add_required_files(zip_content)

  # Package and save
  packager = Infrastructure::ZipPackager.new
  packager.package(zip_content, path)
end

Instance Method Details

#to_file(path) ⇒ Object

Save package to file

Parameters:

  • path (String)

    Output path



228
229
230
231
232
233
# File 'lib/uniword/ooxml/dotx_package.rb', line 228

def to_file(path)
  zip_content = to_zip_content

  packager = Infrastructure::ZipPackager.new
  packager.package(zip_content, path)
end

#to_zip_contentHash

Generate ZIP content hash

Returns:

  • (Hash)

    File paths => content



238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
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
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
# File 'lib/uniword/ooxml/dotx_package.rb', line 238

def to_zip_content
  content = {}

  # Serialize lutaml-model files with prefix: false
  if core_properties
    content["docProps/core.xml"] =
      core_properties.to_xml(encoding: "UTF-8", prefix: false)
  end
  if app_properties
    content["docProps/app.xml"] =
      app_properties.to_xml(encoding: "UTF-8", prefix: false)
  end

  # Theme serialization (no raw XML fallback)
  if theme
    content["word/theme/theme1.xml"] =
      theme.to_xml(encoding: "UTF-8")
  end

  # Serialize model-based configurations
  if styles_configuration
    content["word/styles.xml"] =
      styles_configuration.to_xml(encoding: "UTF-8")
  end

  if numbering_configuration
    content["word/numbering.xml"] =
      numbering_configuration.to_xml(encoding: "UTF-8")
  end

  # Serialize main document (word/document.xml)
  if @document
    content["word/document.xml"] = @document.to_xml(encoding: "UTF-8")
  elsif @raw_document_xml
    # Fallback to raw XML if document wasn't parsed yet
    content["word/document.xml"] = @raw_document_xml
  end

  # Serialize settings
  if settings
    content["word/settings.xml"] =
      settings.to_xml(encoding: "UTF-8")
  end

  # Serialize font table
  if font_table
    content["word/fontTable.xml"] =
      font_table.to_xml(encoding: "UTF-8")
  end

  # Serialize web settings
  if web_settings
    content["word/webSettings.xml"] =
      web_settings.to_xml(encoding: "UTF-8")
  end

  # Serialize content types
  if content_types
    content["[Content_Types].xml"] =
      content_types.to_xml(declaration: true)
  end

  # Serialize package relationships
  if package_rels
    content["_rels/.rels"] =
      package_rels.to_xml(declaration: true)
  end

  # Serialize document relationships
  if document_rels
    content["word/_rels/document.xml.rels"] =
      document_rels.to_xml(declaration: true)
  end

  # Serialize footnotes
  if footnotes
    content["word/footnotes.xml"] =
      footnotes.to_xml(encoding: "UTF-8")
  end

  # Serialize endnotes
  if endnotes
    content["word/endnotes.xml"] =
      endnotes.to_xml(encoding: "UTF-8")
  end

  content
end