> ## Documentation Index
> Fetch the complete documentation index at: https://developer.kodexa.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Working with a Document

> Create, save, load, and manipulate Kodexa Documents using the Document SDK in Python and TypeScript, with examples for each common operation.

Kodexa is a powerful document processing platform that allows developers to work with documents in a structured and efficient manner. This guide will walk you through the basics of creating, saving, loading, and working with Kodexa Documents.

## Creating a Document

You can create documents in several ways using the Kodexa Document SDK:

<CodeGroup>
  ```python Python theme={null}
  from kodexa_document import Document

  # Create an empty document
  doc = Document()

  # Create from text
  doc = Document.from_text("Some content")

  # Create from JSON
  doc = Document.from_json(json_string)
  ```

  ```typescript TypeScript theme={null}
  import { Kodexa } from '@kodexa/document';

  await Kodexa.init();

  // Create an empty document
  const doc = await Kodexa.createDocument();

  // Create from text
  const doc = await Kodexa.fromText("Some content");

  // Create from JSON
  const doc = await Kodexa.fromJson(jsonString);
  ```
</CodeGroup>

## Saving a Document

You can save a Kodexa Document to a file or a store. Documents are saved in the KDDB format (a SQLite database):

<CodeGroup>
  ```python Python theme={null}
  doc.to_kddb('my-document.kddb')
  doc.close()
  ```

  ```typescript TypeScript theme={null}
  const blob = await doc.toBlob();
  // Save blob to file or upload
  await doc.dispose();
  ```
</CodeGroup>

By convention, we use the `.kddb` extension for Kodexa Document Database files.

## Loading a Document

To load a previously saved Kodexa Document:

<CodeGroup>
  ```python Python theme={null}
  another_document = Document.from_kddb('my-document.kddb')
  another_document.close()
  ```

  ```typescript TypeScript theme={null}
  const blob = await fetch('my-document.kddb').then(r => r.blob());
  const doc = await Kodexa.fromBlob(blob);
  await doc.dispose();
  ```
</CodeGroup>

### Detached Documents

Sometimes you may want to make changes to a document without affecting the original file. In Python, you can load the document in detached mode:

```python theme={null}
detached_document = Document.from_kddb('my-document.kddb', detached=True)
```

## Anatomy of a Kodexa Document

The Kodexa Document Model provides a flexible and powerful way to represent structured and unstructured documents. At its core, it consists of a Document object that contains metadata and a hierarchical tree of ContentNodes, each of which can have features and tags attached to them.

Let's explore the key components of the model.

## Core Components

### Document Structure

```mermaid theme={null}
graph TD
    A[Document] --> B[Metadata]
    A --> C[Content Node Tree]
    A --> D[Source Metadata]
    A --> E[Native Documents]
    A --> F[Data Objects & Attributes]
    A --> G[Audit Trail]
    C --> H[Root Content Node]
    H --> I[Child Node 1]
    H --> J[Child Node 2]
    I --> K[Grandchild Node]

    style A fill:#f9f,stroke:#333,stroke-width:2px
    style C fill:#bbf,stroke:#333,stroke-width:2px
    style H fill:#bfb,stroke:#333,stroke-width:2px

```

A Kodexa Document consists of:

1. **Document Metadata**: Flexible dictionary-based metadata about the document
2. **Content Node Tree**: Hierarchical structure of content nodes
3. **Source Metadata**: Information about the document's origin (filename, MIME type, checksum)
4. **Native Documents**: Embedded binary files (original PDFs, images, etc.)
5. **Data Objects & Attributes**: Structured extracted data organized by Data Definition
6. **Audit Trail**: Change history and revision tracking

### Content Nodes

ContentNodes are the building blocks of the document structure. Each ContentNode represents a logical section of content and has the following properties:

```mermaid theme={null}
graph LR
    A[ContentNode] --> B[Node Type]
    A --> C[Content]
    A --> D[Features]
    A --> E[Children]
    A --> F[Tags]
    A --> G[Index]

    style A fill:#f9f,stroke:#333,stroke-width:2px

```

Key attributes:

* **node\_type**: Identifies the type of node (e.g., 'page', 'line', 'word', 'cell')
* **content**: The actual text content of the node
* **features**: List of attached features (metadata)
* **tags**: Annotations linking content to extracted data
* **children**: Child nodes in the hierarchy
* **id**: Unique numeric identifier
* **index**: Position among siblings
* **virtual**: Whether the node is a virtual/synthesized node

### Features

Features are flexible metadata containers attached to ContentNodes:

```mermaid theme={null}
graph TD
    A[Feature Types] --> B[Tags]
    A --> C[Spatial]
    A --> D[Custom Features]

    B --> E[Named Tags]
    B --> F[Tag Values]

    C --> G[Bounding Boxes]
    C --> H[Coordinates]

    style A fill:#f9f,stroke:#333,stroke-width:2px
    style B fill:#bbf,stroke:#333,stroke-width:2px
    style C fill:#bfb,stroke:#333,stroke-width:2px

```

Each feature has:

* **feature\_type**: Category of the feature (e.g., 'tag', 'spatial')
* **name**: Identifier for the feature
* **value**: The feature's data (always stored as an array)

## Working with Documents

### Creating Document Structure

<CodeGroup>
  ```python Python theme={null}
  from kodexa_document import Document

  doc = Document()

  # Create a root node
  root = doc.create_node(node_type="document")
  doc.content_node = root

  # Add child nodes
  page = doc.create_node(node_type="page", content="Page content")
  root.add_child(page)

  line = doc.create_node(node_type="line", content="A line of text")
  page.add_child(line)
  ```

  ```typescript TypeScript theme={null}
  import { Kodexa } from '@kodexa/document';

  await Kodexa.init();
  const doc = await Kodexa.createDocument();

  const root = await doc.getRoot();
  const node = await doc.createNode("page");
  await root.addChild(node);
  ```
</CodeGroup>

### Working with Features

<CodeGroup>
  ```python Python theme={null}
  # Add a feature
  node.add_feature("tag", "paragraph", "body")

  # Add spatial information (bounding box)
  node.set_bbox([10, 20, 100, 200])

  # Get feature value
  value = node.get_feature_value("tag", "paragraph")

  # Check if feature exists
  has_it = node.has_feature("tag", "paragraph")

  # Get all features
  features = node.get_features()

  # Get features by type
  tag_features = node.get_features_of_type("tag")

  # Remove a feature
  node.remove_feature("tag", "paragraph")
  ```

  ```typescript TypeScript theme={null}
  // Add a feature
  await node.setFeature("tag", "paragraph", "body");

  // Set bounding box
  await node.setBBox(10, 20, 100, 200);

  // Get feature value
  const value = await node.getFeatureValue("tag", "paragraph");

  // Check if feature exists
  const hasIt = await node.hasFeature("tag", "paragraph");

  // Get all features
  const features = await node.getFeatures();

  // Get features by type
  const tagFeatures = await node.getFeaturesOfType("tag");
  ```
</CodeGroup>

### Working with Tags

Tags are annotations on nodes that link content to extracted data:

<CodeGroup>
  ```python Python theme={null}
  # Apply a tag
  node.tag("company_name", confidence=0.95, value="Acme Corp")

  # Check if node has a tag
  if node.has_tag("company_name"):
      tags = node.get_tags()
      for tag in tags:
          print(f"Tag: {tag.value} (confidence: {tag.confidence})")

  # Remove a tag
  node.remove_tag("company_name")
  ```

  ```typescript TypeScript theme={null}
  // Apply a tag
  await node.tag("company_name");

  // Apply a tag with options
  await node.tagWithOptions("company_name", {
      confidence: 0.95
  });

  // Check if node has a tag
  if (await node.hasTag("company_name")) {
      const tags = await node.getTags();
      console.log(tags);
  }

  // Remove a tag
  await node.removeTag("company_name");
  ```
</CodeGroup>

## Node Navigation and Selection

The document model provides powerful ways to navigate and select nodes:

1. **Direct Navigation**:
   * `get_children()` / `getChildren()`: Get immediate child nodes
   * `get_parent()` / `getParent()`: Get parent node
   * `next_node()` / `nextNode()`: Get next sibling
   * `previous_node()` / `previousNode()`: Get previous sibling
   * `get_child(index)` / `getChild(index)`: Get child by index
2. **Selector-based Navigation**:

<CodeGroup>
  ```python Python theme={null}
  # Select all nodes of type 'page'
  pages = document.select("//page")

  # Select nodes with specific tags
  tagged = document.select("//*[hasTag('paragraph')]")

  # Select first match only
  first_page = document.select_first("//page")
  ```

  ```typescript TypeScript theme={null}
  // Select all nodes of type 'page'
  const pages = await document.select("//page");

  // Select nodes with specific tags
  const tagged = await document.select("//*[hasTag('paragraph')]");

  // Select first match only
  const firstPage = await document.selectFirst("//page");
  ```
</CodeGroup>

## Data Objects and Attributes

Documents can contain structured extracted data organized by Data Definition:

<CodeGroup>
  ```python Python theme={null}
  # Get all data objects
  objects = doc.data_objects.get_all()

  # Get attributes for an object
  attrs = doc.data_attributes.get_for_data_object(obj_id)
  ```

  ```typescript TypeScript theme={null}
  // Get all data objects
  const objects = await doc.dataObjects.getAll();

  // Get attributes for an object
  const attrs = await doc.dataAttributes.getForDataObject(objId);
  ```
</CodeGroup>

## Document Metadata

<CodeGroup>
  ```python Python theme={null}
  # Access metadata
  doc.metadata["schema_version"] = "1.0"
  print(doc.metadata)

  # Source metadata
  print(doc.source)
  ```

  ```typescript TypeScript theme={null}
  // Set metadata
  await doc.setMetadataValue("schemaVersion", "1.0");

  // Get metadata
  const meta = await doc.getMetadata();
  ```
</CodeGroup>

## Working with Document Content

Kodexa uses a powerful selector syntax to find and manipulate content within documents.

Selectors work similarly to CSS selectors or XPath, allowing you to build queries that can be executed on a document instance.

### Basic Selector Example

To find all content nodes matching a regex:

```python theme={null}
nodes = document.select('//*[contentRegex("Name")]')
```

This returns a list of the matching content nodes.

### Selector Syntax

The selector syntax is composed of several parts:

1. Axis & Node Type: Defines how to navigate the tree structure.
2. Predicate: Further filters the selected nodes based on conditions.

### Axis Examples

* `//`: Current node and all children
* `/`: Root node
* `.`: Current Node (or root if from the document)
* `./line/.`: All nodes of type line under the current node
* `parent::line`: Any node in the parent structure of this node that is of node type line

### Predicate Functions

Predicates can use various functions, such as:

* `contentRegex`: Matches content against a regular expression
* `typeRegex`: Matches node type name against a regular expression
* `hasTag`: Checks if a node has a specific tag
* `hasFeature`: Checks if a node has a specific feature
* `content`: Returns the content of the node
* `uuid`: Returns the UUID of the node

### Operators

Operators can be used to combine functions:

* `|`: Union the results of two sides
* `=`: Test that two sides are equal
* `and`: Boolean AND operation
* `or`: Boolean OR operation

### Pipeline Selectors

Kodexa also supports "pipeline" selectors, allowing you to chain multiple selectors:

```python theme={null}
document.select('//word stream //*[hasTag("ORG")] stream * [hasTag("PERSON")]')
```

This example streams all nodes of type word, then filters those with the "ORG" tag, and finally filters those with the "PERSON" tag.

## Best Practices

1. **Node Types**: Use consistent node types throughout your document to make selection and processing easier
2. **Features**:
   * Use features to add metadata rather than modifying node content
   * Keep feature names consistent across your application
   * Use appropriate feature types for different kinds of metadata
3. **Content Structure**:
   * Maintain a logical hierarchy that reflects the document's structure
   * Use indexes appropriately to maintain node order
   * Consider using virtual nodes for sparse content
4. **Performance**:
   * Use selectors efficiently
   * Batch operations when possible
   * Use KDDB format for large documents
5. **Resource Management**:
   * Always close documents when done (Python: `doc.close()`, TypeScript: `await doc.dispose()`)
   * Use context managers in Python: `with Document() as doc:`

## Error Handling

The document model includes error handling through exceptions:

<CodeGroup>
  ```python Python theme={null}
  from kodexa_document import Document, ContentException

  try:
      doc = Document.from_kddb("my-document.kddb")
      # ... work with document
  except Exception as e:
      print(f"Error: {str(e)}")
  finally:
      doc.close()
  ```

  ```typescript TypeScript theme={null}
  try {
      const doc = await Kodexa.fromBlob(blob);
      // ... work with document
      await doc.dispose();
  } catch (error) {
      console.error("Error:", error);
  }
  ```
</CodeGroup>

## Conclusion

Kodexa Documents provide a powerful way to work with structured content. By understanding how to create, save, load, and query documents using selectors, you can efficiently process and analyze complex document structures in your applications.
