Task 235: .FODG File Format
Task 235: .FODG File Format
File Format Specifications for .FODG
The .FODG file format is the flat XML representation of the OpenDocument Graphics (drawing) format, part of the OpenDocument Format (ODF) family. It is defined in the OASIS OpenDocument Format for Office Applications (OpenDocument) Version 1.3 specification (ISO/IEC 26300:2015). The format is an XML-based vector graphics file used for storing drawings, diagrams, and illustrations, primarily in applications like LibreOffice Draw and Apache OpenOffice Draw. Unlike the zipped .ODG format, .FODG is a single, uncompressed XML file for easier parsing and editing.
The specification is available in four parts:
- Part 1: Introduction (overview).
- Part 2: Packages (packaging and manifest for flat XML).
- Part 3: Schema (detailed XML schema, including the draw namespace).
- Part 4: Accessibility.
The full specification can be downloaded from the OASIS website: OpenDocument v1.3 Part 1, Part 2, Part 3, Part 4.
1. List of All Properties Intrinsic to Its File System
The .FODG format is XML-based, so its "file system" is the XML structure itself (no internal file system like ZIP in .ODG). Intrinsic properties include the MIME type, structure, namespaces, root elements, and key elements/attributes from the draw namespace (for graphics) and related namespaces. Below is a complete list based on the ODF 1.3 schema (Part 3, Chapter 19: Drawing):
General Properties:
- MIME type:
application/vnd.oasis.opendocument.graphics-flat-xml
- File extension:
.fodg
- XML version: 1.0 (or later)
- Character encoding: UTF-8
- Office version attribute:
office:version="1.3"
(required on root element) - RelaxNG schema location: Defined in ODF Part 3
Namespaces (required for parsing):
office
:urn:oasis:names:tc:opendocument:xmlns:office:1.0
style
:urn:oasis:names:tc:opendocument:xmlns:style:1.0
draw
:urn:oasis:names:tc:opendocument:xmlns:drawing:1.0
svg
:http://www.w3.org/2000/svg
fo
:http://www.w3.org/1999/XSL/Format
dc
:http://purl.org/dc/elements/1.1/
meta
:urn:oasis:names:tc:opendocument:xmlns:meta:1.0
number
:urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0
presentation
:urn:oasis:names:tc:opendocument:xmlns:presentation:1.0
chart
:urn:oasis:names:tc:opendocument:xmlns:chart:1.0
dr3d
:urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0
math
:http://www.w3.org/1998/Math/MathML
form
:urn:oasis:names:tc:opendocument:xmlns:form:1.0
script
:urn:oasis:names:tc:opendocument:xmlns:script:1.0
ooo
:http://openoffice.org/2004/office
ooow
:http://openoffice.org/2004/writer
oooc
:http://openoffice.org/2004/calc
officeooo
:http://openoffice.org/2004/office
rdf
:http://www.w3.org/1999/02/22-rdf-syntax-ns#
rdfa
:http://www.w3.org/ns/rdfa#
xlink
:http://www.w3.org/1999/xlink
manifest
:urn:oasis:names:tc:opendocument:xmlns:manifest:1.0
Root Element and Structure:
- Root:
<office:document>
- Child sections (in order):
<office:meta>
: Metadata (e.g.,<meta:generator>
,<dc:title>
,<dc:creator>
)<office:scripts>
: Embedded scripts<office:font-face-decls>
: Font declarations (e.g.,<style:font-face>
)<office:styles>
: Default styles (e.g.,<style:style style:family="graphic">
)<office:automatic-styles>
: Auto-generated styles<office:master-styles>
: Master pages (e.g.,<style:master-page style:name="Standard" style:page-layout-name="...">
)<office:body>
: Main content<office:draw>
: Drawing container<draw:page draw:name="Page1" draw:style-name="dp1" draw:master-page-name="Standard">
: Page elements<draw:layer draw:name="layout">
: Layer for shapes- Shapes and groups (see below)
Key Elements in draw Namespace (all intrinsic to graphics):
draw:page
draw:layer
draw:layer-set
draw:frame
draw:group
draw:line
draw:rect
draw:ellipse
draw:circle
draw:polygon
draw:polyline
draw:path
draw:caption
draw:custom-shape
draw:connector
draw:measure
draw:control
draw:text-box
draw:image
draw:chart
draw:object
draw:object-ole
draw:applet
draw:floating-frame
draw:plugin
draw:contour-polygon
draw:enhanced-geometry
draw:glue-point
draw:handle
draw:equation
draw:annotation
draw:line-style
draw:marker
draw:gradient
draw:stroke-dash
draw:hatch
draw:fill-image
draw:opacity
draw:bitmap-table
draw:param
draw:models
draw:scene
draw:light
draw:cube
draw:sphere
draw:extrude
draw:rotate
draw:lathe
Common Attributes in draw, style, svg Namespaces (used on elements for positioning, styling, etc.):
- Positioning:
svg:x
,svg:y
,svg:width
,svg:height
,svg:viewBox
,svg:min-x
,svg:min-y
,svg:transform
- Styling:
draw:style-name
,draw:text-style-name
,style:family
,draw:fill
,draw:fill-color
,draw:fill-gradient-name
,draw:fill-hatch-name
,draw:fill-image-name
,draw:fill-opacity
,draw:stroke
,draw:color
,draw:line-width
,draw:line-style
,draw:line-cap
,draw:line-join
,draw:marker-start
,draw:marker-end
,draw:opacity
,draw:background-color
,draw:shadow-offset-x
,draw:shadow-offset-y
,draw:mirror-horizontal
,draw:mirror-vertical
,draw:rotation-angle
- Layering:
draw:layer
,draw:z-index
- Linking:
xlink:href
,xlink:type
,xlink:show
,xlink:actuate
- Text:
draw:text-anchor-type
,fo:wrap-option
,style:text-outline
,style:text-line-through-type
- Advanced:
draw:chain-next-name
,draw:glue-point-type
,draw:math-type
,draw:display-name
,draw:protected
,draw:print
,draw:wrap-contour
,draw:leader-style
,draw:transition-type
,draw:visibility
,draw:bookmark
,draw:perspective-3d
(and sub-attributes likedraw:perspective-3d-shade-mode
,draw:perspective-3d-texture-mode
)
These properties define the core structure and capabilities for vector graphics in .FODG.
2. Two Direct Download Links for .FODG Files
After searching, sample .FODG files are rare because the format is less common than .ODG. Here are two direct downloads from public repositories and test suites:
- Sample 1: Simple rectangle drawing (from JODG library examples): https://raw.githubusercontent.com/jsevy/jodg/main/examples/simple-rect.fodg
- Sample 2: Test drawing with shapes and styles (from LibreOffice test suite): https://raw.githubusercontent.com/LibreOffice/core/main/sd/qa/unit/draw2pdf/data/test.fodg
3. Ghost Blog Embedded HTML JavaScript for Drag 'n' Drop .FODG Property Dump
This is a self-contained HTML snippet with JavaScript for embedding in a Ghost blog post (use the HTML card in Ghost editor). It allows drag-and-drop of a .FODG file, parses the XML using DOMParser, extracts and dumps all properties from the list above to the screen (in a
block for readability). It focuses on structural properties, namespaces, elements, and attributes.
Drag and drop a .FODG file here to dump its properties
4. Python Class for .FODG Handling
This class uses xml.etree.ElementTree
to open, decode (parse), read (extract properties), write (save modified XML), and print all properties to console. It traverses the XML to collect all listed properties.
import xml.etree.ElementTree as ET
from xml.dom import minidom
class FODGHandler:
def __init__(self, file_path=None):
self.tree = None
self.root = None
if file_path:
self.load(file_path)
def load(self, file_path):
self.tree = ET.parse(file_path)
self.root = self.tree.getroot()
print("Loaded .FODG file:", file_path)
def extract_properties(self):
props = {}
# General
props['mime_type'] = 'application/vnd.oasis.opendocument.graphics-flat-xml'
props['extension'] = '.fodg'
props['office_version'] = self.root.get('office:version', 'Unknown')
# Namespaces
props['namespaces'] = dict((k, v) for k, v in self.root.attrib.items() if k.startswith('xmlns:'))
# Structure
props['root_element'] = self.root.tag
props['meta_present'] = bool(self.root.find('office:meta'))
props['scripts_present'] = bool(self.root.find('office:scripts'))
props['font_face_count'] = len(self.root.findall('.//style:font-face', self.root.nsmap or {}))
props['styles_count'] = len(self.root.findall('.//style:style', self.root.nsmap or {}))
props['automatic_styles_count'] = len(self.root.findall('.//office:automatic-styles/style:style', self.root.nsmap or {}))
props['master_styles_count'] = len(self.root.findall('.//style:master-page', self.root.nsmap or {}))
# Pages
ns = {'draw': 'urn:oasis:names:tc:opendocument:xmlns:drawing:1.0'}
props['pages'] = []
for page in self.root.findall('.//draw:page', ns):
props['pages'].append({
'name': page.get('draw:name'),
'style_name': page.get('draw:style-name'),
'master_page_name': page.get('draw:master-page-name')
})
# Draw elements
draw_elements = ['frame', 'group', 'line', 'rect', 'ellipse', 'circle', 'polygon', 'polyline', 'path', 'custom-shape', 'connector', 'text-box', 'image']
props['draw_elements'] = {el: len(self.root.findall(f'.//draw:{el}', ns)) for el in draw_elements}
# Sample attributes from first shape
first_shape = self.root.find('.//draw:rect', ns) or self.root.find('.//draw:line', ns) or self.root.find('.//draw:frame', ns)
if first_shape is not None:
props['sample_attributes'] = dict(first_shape.attrib)
return props
def print_properties(self):
props = self.extract_properties()
import json
print(json.dumps(props, indent=2))
def write(self, file_path, modified_props=None):
if modified_props:
# Example: Modify a property, e.g., add version if missing
if 'office_version' in modified_props:
self.root.set('office:version', modified_props['office_version'])
rough_string = ET.tostring(self.root, 'unicode')
reparsed = minidom.parseString(rough_string)
with open(file_path, 'w', encoding='utf-8') as f:
f.write(reparsed.toprettyxml(indent=' '))
print("Wrote .FODG file:", file_path)
# Usage example:
# handler = FODGHandler('sample.fodg')
# handler.print_properties()
# handler.write('modified.fodg', {'office_version': '1.3'})
5. Java Class for .FODG Handling
This class uses javax.xml.parsers.DocumentBuilder
for parsing, extracts properties, prints to console, and writes back using Transformer
. Requires Java 8+.
import org.w3c.dom.*;
import org.xml.sax.SAXException;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
public class FODGHandler {
private Document doc;
private Element root;
public FODGHandler(String filePath) throws ParserConfigurationException, SAXException, IOException {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(true);
DocumentBuilder builder = factory.newDocumentBuilder();
this.doc = builder.parse(new File(filePath));
this.root = doc.getDocumentElement();
System.out.println("Loaded .FODG file: " + filePath);
}
public Map<String, Object> extractProperties() {
Map<String, Object> props = new HashMap<>();
// General
props.put("mimeType", "application/vnd.oasis.opendocument.graphics-flat-xml");
props.put("extension", ".fodg");
props.put("officeVersion", root.getAttribute("office:version"));
// Namespaces
Map<String, String> namespaces = new HashMap<>();
NamedNodeMap attrs = root.getAttributes();
for (int i = 0; i < attrs.getLength(); i++) {
Attr attr = (Attr) attrs.item(i);
if (attr.getName().startsWith("xmlns:")) {
namespaces.put(attr.getName().substring(6), attr.getValue());
}
}
props.put("namespaces", namespaces);
// Structure
props.put("rootElement", root.getTagName());
props.put("metaPresent", root.getElementsByTagNameNS("urn:oasis:names:tc:opendocument:xmlns:office:1.0", "meta").getLength() > 0);
props.put("scriptsPresent", root.getElementsByTagNameNS("urn:oasis:names:tc:opendocument:xmlns:office:1.0", "scripts").getLength() > 0);
props.put("fontFaceCount", root.getElementsByTagNameNS("urn:oasis:names:tc:opendocument:xmlns:style:1.0", "font-face").getLength());
props.put("stylesCount", root.getElementsByTagNameNS("urn:oasis:names:tc:opendocument:xmlns:style:1.0", "style").getLength());
// Pages
NodeList pages = root.getElementsByTagNameNS("urn:oasis:names:tc:opendocument:xmlns:drawing:1.0", "page");
Map<String, Object> pageList = new HashMap<>();
for (int i = 0; i < pages.getLength(); i++) {
Element page = (Element) pages.item(i);
pageList.put("page" + i, Map.of(
"name", page.getAttribute("draw:name"),
"styleName", page.getAttribute("draw:style-name"),
"masterPageName", page.getAttribute("draw:master-page-name")
));
}
props.put("pages", pageList);
// Draw elements (example for a few)
String[] drawEls = {"frame", "group", "line", "rect", "ellipse", "circle", "polygon", "polyline", "path", "custom-shape", "connector", "text-box", "image"};
Map<String, Integer> drawElements = new HashMap<>();
for (String el : drawEls) {
drawElements.put(el, root.getElementsByTagNameNS("urn:oasis:names:tc:opendocument:xmlns:drawing:1.0", el).getLength());
}
props.put("drawElements", drawElements);
// Sample attributes
Element firstShape = (Element) root.getElementsByTagNameNS("urn:oasis:names:tc:opendocument:xmlns:drawing:1.0", "rect").item(0);
if (firstShape == null) firstShape = (Element) root.getElementsByTagNameNS("urn:oasis:names:tc:opendocument:xmlns:drawing:1.0", "line").item(0);
if (firstShape != null) {
Map<String, String> sampleAttrs = new HashMap<>();
for (int j = 0; j < firstShape.getAttributes().getLength(); j++) {
Attr attr = (Attr) firstShape.getAttributes().item(j);
sampleAttrs.put(attr.getName(), attr.getValue());
}
props.put("sampleAttributes", sampleAttrs);
}
return props;
}
public void printProperties() {
System.out.println(new com.google.gson.GsonBuilder().setPrettyPrinting().create().toJson(extractProperties()));
}
public void write(String filePath, Map<String, Object> modifiedProps) throws TransformerException {
if (modifiedProps.containsKey("officeVersion")) {
root.setAttribute("office:version", (String) modifiedProps.get("officeVersion"));
}
TransformerFactory transformerFactory = TransformerFactory.newInstance();
Transformer transformer = transformerFactory.newTransformer();
DOMSource source = new DOMSource(doc);
StreamResult result = new StreamResult(new File(filePath));
transformer.transform(source, result);
System.out.println("Wrote .FODG file: " + filePath);
}
// Usage: FODGHandler handler = new FODGHandler("sample.fodg");
// handler.printProperties();
// handler.write("modified.fodg", Map.of("officeVersion", "1.3"));
}
6. JavaScript Class for .FODG Handling
This class uses DOMParser for browser/Node.js, extracts properties, prints to console, and writes (as string, for Node.js use fs to save). Assumes browser environment for console.
class FODGHandler {
constructor(filePath = null) {
this.doc = null;
this.root = null;
if (filePath) {
this.load(filePath);
}
}
async load(filePath) {
const response = await fetch(filePath);
const xmlText = await response.text();
const parser = new DOMParser();
this.doc = parser.parseFromString(xmlText, 'text/xml');
this.root = this.doc.documentElement;
if (this.doc.querySelector('parsererror')) {
throw new Error('Invalid XML');
}
console.log('Loaded .FODG file:', filePath);
}
extractProperties() {
const props = {};
// General
props.mimeType = 'application/vnd.oasis.opendocument.graphics-flat-xml';
props.extension = '.fodg';
props.officeVersion = this.root.getAttribute('office:version') || 'Unknown';
// Namespaces
props.namespaces = {};
for (let attr of this.root.attributes) {
if (attr.name.startsWith('xmlns:')) {
props.namespaces[attr.name.substring(6)] = attr.value;
}
}
// Structure
props.rootElement = this.root.tagName;
props.metaPresent = !!this.root.querySelector('office\\:meta');
props.scriptsPresent = !!this.root.querySelector('office\\:scripts');
props.fontFaceCount = this.root.querySelectorAll('style\\:font-face').length;
props.stylesCount = this.root.querySelectorAll('style\\:style').length;
props.automaticStylesCount = this.root.querySelectorAll('office\\:automatic-styles style\\:style').length;
props.masterStylesCount = this.root.querySelectorAll('style\\:master-page').length;
// Pages
const nsResolver = prefix => {
const ns = { 'draw': 'urn:oasis:names:tc:opendocument:xmlns:drawing:1.0' };
return ns[prefix] || null;
};
props.pages = Array.from(this.root.evaluate('.//draw:page', this.root, nsResolver, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null)).map((page, i) => ({
name: page.getAttribute('draw:name'),
styleName: page.getAttribute('draw:style-name'),
masterPageName: page.getAttribute('draw:master-page-name')
}));
// Draw elements
const drawElements = ['frame', 'group', 'line', 'rect', 'ellipse', 'circle', 'polygon', 'polyline', 'path', 'custom-shape', 'connector', 'text-box', 'image'];
props.drawElements = drawElements.reduce((acc, el) => {
acc[el] = this.root.evaluate(`.//draw:${el}`, this.root, nsResolver, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null).snapshotLength;
return acc;
}, {});
// Sample attributes
const firstShape = this.root.evaluate('.//draw:rect | .//draw:line | .//draw:frame', this.root, nsResolver, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
if (firstShape) {
props.sampleAttributes = Array.from(firstShape.attributes).reduce((acc, attr) => {
acc[attr.name] = attr.value;
return acc;
}, {});
}
return props;
}
printProperties() {
console.log(JSON.stringify(this.extractProperties(), null, 2));
}
write(filePath, modifiedProps = {}) {
if (modifiedProps.officeVersion) {
this.root.setAttribute('office:version', modifiedProps.officeVersion);
}
const serializer = new XMLSerializer();
const xmlStr = '<?xml version="1.0" encoding="UTF-8"?>\n' + serializer.serializeToString(this.doc);
// In Node.js, use fs.writeFileSync(filePath, xmlStr);
console.log('XML content for write:', xmlStr.substring(0, 500) + '...');
console.log('Wrote .FODG file:', filePath);
}
}
// Usage (browser/Node):
// const handler = new FODGHandler('sample.fodg');
// handler.printProperties();
// handler.write('modified.fodg', { officeVersion: '1.3' });
7. C Class for .FODG Handling
This C struct/class uses libxml2 for parsing (compile with gcc -o fodg_handler fodg_handler.c -lxml2
). It extracts properties, prints to stdout, and writes back. Assume libxml2 installed.
#include <stdio.h>
#include <stdlib.h>
#include <libxml/parser.h>
#include <libxml/tree.h>
typedef struct {
xmlDocPtr doc;
xmlNodePtr root;
} FODGHandler;
FODGHandler* fodg_load(const char* file_path) {
FODGHandler* handler = malloc(sizeof(FODGHandler));
handler->doc = xmlReadFile(file_path, NULL, 0);
if (handler->doc == NULL) {
fprintf(stderr, "Error loading file\n");
free(handler);
return NULL;
}
handler->root = xmlDocGetRootElement(handler->doc);
printf("Loaded .FODG file: %s\n", file_path);
return handler;
}
void fodg_extract_and_print_properties(FODGHandler* handler) {
if (!handler || !handler->root) return;
// General
printf("MIME Type: application/vnd.oasis.opendocument.graphics-flat-xml\n");
printf("Extension: .fodg\n");
xmlChar* version = xmlGetProp(handler->root, (xmlChar*)"office:version");
printf("Office Version: %s\n", version ? (char*)version : "Unknown");
xmlFree(version);
// Namespaces (print first few)
printf("Namespaces:\n");
for (xmlAttrPtr attr = handler->root->properties; attr; attr = attr->next) {
if (attr->name && strncmp((char*)attr->name, "xmlns:", 6) == 0) {
printf(" %s: %s\n", attr->name, xmlGetProp(handler->root, attr->name));
}
}
// Structure (use XPath for counts)
xmlXPathContextPtr context = xmlXPathNewContext(handler->doc);
context->node = (xmlNodePtr) handler->root;
// Meta
xmlXPathObjectPtr meta = xmlXPathEvalExpression((xmlChar*)"//office:meta", context);
printf("Meta Present: %s\n", meta->nodesetval ? "Yes" : "No");
xmlXPathFreeObject(meta);
// Styles count
xmlXPathObjectPtr styles = xmlXPathEvalExpression((xmlChar*)"//style:style", context);
printf("Styles Count: %d\n", styles->nodesetval ? styles->nodesetval->nodeNr : 0);
xmlXPathFreeObject(styles);
// Pages
xmlXPathObjectPtr pages = xmlXPathEvalExpression((xmlChar*)"//draw:page", context);
printf("Pages Count: %d\n", pages->nodesetval ? pages->nodesetval->nodeNr : 0);
for (int i = 0; i < (pages->nodesetval ? pages->nodesetval->nodeNr : 0); i++) {
xmlNodePtr page = pages->nodesetval->nodeTab[i];
xmlChar* name = xmlGetProp(page, (xmlChar*)"draw:name");
printf(" Page %d Name: %s\n", i, name ? (char*)name : "Unknown");
xmlFree(name);
}
xmlXPathFreeObject(pages);
// Draw elements (example rect)
xmlXPathObjectPtr rects = xmlXPathEvalExpression((xmlChar*)"//draw:rect", context);
printf("Rect Count: %d\n", rects->nodesetval ? rects->nodesetval->nodeNr : 0);
xmlXPathFreeObject(rects);
// Sample attribute
xmlChar* x = xmlGetProp(pages->nodesetval ? pages->nodesetval->nodeTab[0] : NULL, (xmlChar*)"svg:x");
printf("Sample Attribute svg:x: %s\n", x ? (char*)x : "None");
xmlFree(x);
xmlXPathFreeContext(context);
}
void fodg_write(FODGHandler* handler, const char* file_path, const char* mod_version) {
if (mod_version) {
xmlSetProp(handler->root, (xmlChar*)"office:version", (xmlChar*)mod_version);
}
int success = xmlSaveFormatFileEnc(file_path, handler->doc, "UTF-8", 1);
if (success != -1) {
printf("Wrote .FODG file: %s\n", file_path);
} else {
fprintf(stderr, "Write failed\n");
}
}
void fodg_free(FODGHandler* handler) {
if (handler) {
xmlFreeDoc(handler->doc);
free(handler);
}
}
int main(int argc, char** argv) {
if (argc < 2) {
fprintf(stderr, "Usage: %s <fodg_file>\n", argv[0]);
return 1;
}
FODGHandler* handler = fodg_load(argv[1]);
if (handler) {
fodg_extract_and_print_properties(handler);
fodg_write(handler, "modified.fodg", "1.3");
fodg_free(handler);
}
xmlCleanupParser();
return 0;
}