Ootempl.Replacement (ootempl v0.3.0)

Replaces placeholders in Word XML text nodes while preserving formatting.

This module handles the core XML manipulation logic for replacing {{variable}} placeholders with values from data maps. It handles the complexities of Word's XML structure, including:

  • Preserving Word formatting (bold, italic, font, size, color)
  • XML-escaping replacement values to prevent corruption
  • Unescaping literal {{ and }} sequences to {{ and }}
  • Collecting all errors for batch reporting

Word XML Structure

Word stores text in <w:t> elements within <w:r> (run) elements that carry formatting:

<w:p>  <!-- paragraph -->
  <w:r>  <!-- run with formatting -->
    <w:rPr>...</w:rPr>  <!-- run properties (formatting) -->
    <w:t>Hello {{name}}</w:t>  <!-- text -->
  </w:r>
</w:p>

Split Placeholders

Word often splits placeholders across multiple <w:t> elements. Documents must be normalized using Ootempl.Xml.Normalizer before calling this module to ensure placeholders are consolidated. The main Ootempl.render/3 API handles this automatically.

Examples

Replacing placeholders in a Word document:

    data = %{"name" => "World"}
    {:ok, doc} = Ootempl.Xml.parse("<w:p><w:r><w:t>Hello {{name}}</w:t></w:r></w:p>")
    {:ok, result} = Ootempl.Replacement.replace_in_document(doc, data)
    # result now contains "Hello World"

Summary

Functions

Replaces all placeholders in the document XML with values from the data map.

Types

placeholder_error_detail()

@type placeholder_error_detail() :: %{
  placeholder: String.t(),
  reason: Ootempl.DataAccess.error_reason()
}

xml_element()

@type xml_element() :: Ootempl.Xml.xml_element()

xml_node()

@type xml_node() :: Ootempl.Xml.xml_node()

xml_text()

@type xml_text() :: Ootempl.Xml.xml_text()

Functions

replace_in_document(xml_element, data, filters \\ Filters.active_registry())

@spec replace_in_document(xml_element(), map(), Ootempl.Filters.registry()) ::
  {:ok, xml_element()} | {:error, Ootempl.PlaceholderError.t()}

Replaces all placeholders in the document XML with values from the data map.

Processes the entire document tree, replacing placeholders while preserving all formatting. Collects all errors and returns them together for batch reporting.

Note: This function expects the document to already be normalized (split placeholders merged). Use Ootempl.Xml.Normalizer.normalize/1 first if needed, or use the high-level Ootempl.render/3 API which handles normalization automatically.

Parameters

  • xml_element - The root XML element (typically the document root)
  • data - Map containing replacement values (string keys)

Returns

  • {:ok, modified_xml} - Modified XML with all replacements applied
  • {:error, %PlaceholderError{}} - Struct containing all placeholder resolution errors

Examples

Successful replacement:

    import Ootempl.Xml
    {:ok, doc} = Ootempl.Xml.parse("<w:p><w:r><w:t>{{name}}</w:t></w:r></w:p>")
    Ootempl.Replacement.replace_in_document(doc, %{"name" => "John"})
    # => {:ok, modified_xml}

Missing placeholder:

    {:ok, doc} = Ootempl.Xml.parse("<w:p><w:r><w:t>{{missing}}</w:t></w:r></w:p>")
    Ootempl.Replacement.replace_in_document(doc, %{})
    # => {:error, %Ootempl.PlaceholderError{
    #      message: "Placeholder {{missing}} could not be resolved",
    #      placeholders: [%{placeholder: "{{missing}}", reason: {:path_not_found, ["missing"]}}]
    #    }}