Ootempl.Relationships (ootempl v0.3.0)

Manages relationship XML for Office Open XML documents.

This module provides functions to parse, modify, and generate relationship IDs in .docx relationship files (word/_rels/document.xml.rels). Relationships link the main document to media files, styles, and other resources using unique IDs like rId1, rId2, etc.

Relationship Structure

Relationship files follow the OpenXML format:

<?xml version="1.0"?>
<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
  <Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles" Target="styles.xml"/>
  <Relationship Id="rId5" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/image" Target="media/image1.png"/>
</Relationships>

Usage

Parse a relationship file:

{:ok, rels} = Relationships.parse_relationships(xml_string)

Extract existing IDs:

ids = Relationships.extract_relationship_ids(rels)
# ["rId1", "rId5"]

Generate a new unique ID:

new_id = Relationships.generate_unique_id(ids)
# "rId6"

Create an image relationship:

rel = Relationships.create_image_relationship(new_id, "media/image2.png")

Add the relationship to the XML:

updated_rels = Relationships.add_relationship(rels, rel)

Serialize back to XML string:

{:ok, xml_string} = Relationships.serialize_relationships(updated_rels)

Summary

Functions

Adds a relationship to the relationship XML element.

Creates an image relationship entry.

Extracts all relationship IDs from a relationship XML element.

Generates a unique relationship ID given a list of existing IDs.

Parses relationship XML into an :xmerl element structure.

Serializes relationship XML back to an XML string.

Types

relationship()

@type relationship() :: %{id: String.t(), type: String.t(), target: String.t()}

Functions

add_relationship(rels_xml, relationship)

Adds a relationship to the relationship XML element.

Creates a new <Relationship> element and appends it to the <Relationships> root.

Returns the updated XML element with the new relationship added.

Examples

iex> xml = ~s(<?xml version="1.0"?><Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships"></Relationships>)
iex> {:ok, rels} = Ootempl.Relationships.parse_relationships(xml)
iex> rel = Ootempl.Relationships.create_image_relationship("rId1", "media/image1.png")
iex> updated = Ootempl.Relationships.add_relationship(rels, rel)
iex> Ootempl.Relationships.extract_relationship_ids(updated)
["rId1"]

create_image_relationship(id, target)

@spec create_image_relationship(String.t(), String.t()) :: relationship()

Creates an image relationship entry.

Returns a relationship map with the specified ID and target path. The relationship type is automatically set to the OpenXML image relationship type.

Examples

iex> Ootempl.Relationships.create_image_relationship("rId10", "media/image1.png")
%{
  id: "rId10",
  type: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image",
  target: "media/image1.png"
}

extract_relationship_ids(rels_xml)

@spec extract_relationship_ids(Ootempl.Xml.xml_element()) :: [String.t()]

Extracts all relationship IDs from a relationship XML element.

Returns a list of relationship ID strings like ["rId1", "rId2", "rId5"].

Examples

iex> xml = ~s(<?xml version="1.0"?><Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships"><Relationship Id="rId1" Type="http://example.com" Target="foo.xml"/></Relationships>)
iex> {:ok, rels} = Ootempl.Relationships.parse_relationships(xml)
iex> Ootempl.Relationships.extract_relationship_ids(rels)
["rId1"]

generate_unique_id(existing_ids)

@spec generate_unique_id([String.t()]) :: String.t()

Generates a unique relationship ID given a list of existing IDs.

Extracts the numeric part from existing IDs (e.g., "rId5"5), finds the maximum, and increments it to generate a new unique ID.

Returns "rId1" if no existing IDs are provided.

Examples

iex> Ootempl.Relationships.generate_unique_id([])
"rId1"

iex> Ootempl.Relationships.generate_unique_id(["rId1", "rId5"])
"rId6"

iex> Ootempl.Relationships.generate_unique_id(["rId1", "rId5", "rId20"])
"rId21"

parse_relationships(xml_string)

@spec parse_relationships(String.t()) ::
  {:ok, Ootempl.Xml.xml_element()} | {:error, term()}

Parses relationship XML into an :xmerl element structure.

Returns {:ok, xml_element} on success, or {:error, reason} if parsing fails.

Examples

iex> xml = ~s(<?xml version="1.0"?><Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships"></Relationships>)
iex> {:ok, _rels} = Ootempl.Relationships.parse_relationships(xml)

serialize_relationships(rels_xml)

@spec serialize_relationships(Ootempl.Xml.xml_element()) ::
  {:ok, String.t()} | {:error, term()}

Serializes relationship XML back to an XML string.

Returns {:ok, xml_string} on success, or {:error, reason} if serialization fails.

Examples

iex> xml = ~s(<?xml version="1.0"?><Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships"><Relationship Id="rId1" Type="http://example.com" Target="foo.xml"/></Relationships>)
iex> {:ok, rels} = Ootempl.Relationships.parse_relationships(xml)
iex> {:ok, serialized} = Ootempl.Relationships.serialize_relationships(rels)
iex> String.contains?(serialized, "rId1")
true