> ## 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.

# Content Nodes

> Build and navigate hierarchical document structures in Kodexa using content nodes, which represent text, sections, pages, features, and tags in KDDB.

Content nodes form the hierarchical structure of a Kodexa document. Each node represents a piece of content (text, a section, a page, etc.) and can have children, features, and tags.

## Node Basics

### Creating Nodes

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

  with Document() as doc:
      # Create the root node
      root = doc.create_node("document", "My Document")
      doc.content_node = root

      # Create child nodes with content
      section = doc.create_node("section", "Introduction", parent=root)
      para1 = doc.create_node("paragraph", "First paragraph.", parent=section)
      para2 = doc.create_node("paragraph", "Second paragraph.", parent=section)

      # Create nodes without initial content
      table = doc.create_node("table", parent=root)
      row = doc.create_node("row", parent=table)
      cell = doc.create_node("cell", "Cell content", parent=row)
  ```

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

  async function createNodes() {
    await Kodexa.init();
    const doc = await Kodexa.createDocument();

    try {
      // Create the root node
      const root = await doc.createNode('document');
      await root.setContent('My Document');

      // Create child nodes
      const section = await doc.createNode('section');
      await section.setContent('Introduction');
      await root.addChild(section);

      const para1 = await doc.createNode('paragraph');
      await para1.setContent('First paragraph.');
      await section.addChild(para1);

      const para2 = await doc.createNode('paragraph');
      await para2.setContent('Second paragraph.');
      await section.addChild(para2);
    } finally {
      doc.dispose();
    }
  }
  ```
</CodeGroup>

### Node Types

Common node types used in Kodexa documents:

| Type        | Description               |
| ----------- | ------------------------- |
| `document`  | Root node of the document |
| `page`      | A page in the document    |
| `section`   | A logical section         |
| `paragraph` | A paragraph of text       |
| `line`      | A line of text            |
| `word`      | An individual word        |
| `table`     | A table structure         |
| `row`       | A table row               |
| `cell`      | A table cell              |
| `image`     | An image element          |

## Node Content

### Reading and Writing Content

<CodeGroup>
  ```python Python theme={null}
  with Document() as doc:
      root = doc.create_node("document")
      doc.content_node = root
      para = doc.create_node("paragraph", "Initial content", parent=root)

      # Read content
      print(f"Content: {para.content}")

      # Update content
      para.content = "Updated content"

      # Content can be None
      empty_node = doc.create_node("section", parent=root)
      print(f"Empty content: {empty_node.content}")  # None
  ```

  ```typescript TypeScript theme={null}
  async function workWithContent() {
    await Kodexa.init();
    const doc = await Kodexa.createDocument();

    try {
      const root = await doc.createNode('document');
      const para = await doc.createNode('paragraph');
      await para.setContent('Initial content');
      await root.addChild(para);

      // Read content
      console.log(`Content: ${para.content}`);

      // Update content
      await para.setContent('Updated content');

      // Get content (async)
      const content = await para.getContent();
      console.log(`Content: ${content}`);
    } finally {
      doc.dispose();
    }
  }
  ```
</CodeGroup>

### Content Parts

Nodes can have multiple content parts for complex text:

<CodeGroup>
  ```python Python theme={null}
  with Document() as doc:
      root = doc.create_node("document")
      doc.content_node = root
      para = doc.create_node("paragraph", parent=root)

      # Set multiple content parts
      para.set_content_parts(["Hello ", "world", "!"])

      # Get content parts
      parts = para.get_content_parts()
      print(f"Parts: {parts}")  # ['Hello ', 'world', '!']

      # Full content joins parts
      print(f"Full: {para.content}")  # 'Hello world!'
  ```

  ```typescript TypeScript theme={null}
  async function contentParts() {
    await Kodexa.init();
    const doc = await Kodexa.createDocument();

    try {
      const root = await doc.createNode('document');
      const para = await doc.createNode('paragraph');
      await root.addChild(para);

      // Set content (parts can be set via features in TypeScript)
      await para.setContent('Hello world!');

      // Get content
      const content = await para.getContent();
      console.log(`Content: ${content}`);
    } finally {
      doc.dispose();
    }
  }
  ```
</CodeGroup>

### Aggregated Content

Get all content from a node and its descendants:

<CodeGroup>
  ```python Python theme={null}
  with Document() as doc:
      root = doc.create_node("document")
      doc.content_node = root

      section = doc.create_node("section", parent=root)
      doc.create_node("paragraph", "First paragraph.", parent=section)
      doc.create_node("paragraph", "Second paragraph.", parent=section)
      doc.create_node("paragraph", "Third paragraph.", parent=section)

      # Get all content from section and children
      all_text = section.get_all_content(separator=" ")
      print(f"All content: {all_text}")
      # "First paragraph. Second paragraph. Third paragraph."
  ```

  ```typescript TypeScript theme={null}
  async function aggregatedContent() {
    await Kodexa.init();
    const doc = await Kodexa.createDocument();

    try {
      const root = await doc.createNode('document');
      const section = await doc.createNode('section');
      await root.addChild(section);

      for (const text of ['First paragraph.', 'Second paragraph.', 'Third paragraph.']) {
        const para = await doc.createNode('paragraph');
        await para.setContent(text);
        await section.addChild(para);
      }

      // Get all content via children
      const children = await section.getChildren();
      const allText = children.map(c => c.content).join(' ');
      console.log(`All content: ${allText}`);
    } finally {
      doc.dispose();
    }
  }
  ```
</CodeGroup>

## Tree Navigation

### Parent and Children

<CodeGroup>
  ```python Python theme={null}
  with Document.from_kddb("document.kddb") as doc:
      root = doc.content_node

      # Get all children
      children = root.get_children()
      print(f"Root has {len(children)} children")

      for child in children:
          # Get parent (back to root)
          parent = child.get_parent()
          print(f"Node type: {child.type}, parent type: {parent.type}")

          # Get this node's children
          grandchildren = child.get_children()
          print(f"  Has {len(grandchildren)} children")
  ```

  ```typescript TypeScript theme={null}
  async function navigateTree() {
    await Kodexa.init();
    const doc = await Kodexa.fromBlob(kddbBlob);

    try {
      const root = await doc.getRoot();
      if (!root) return;

      // Get all children
      const children = await root.getChildren();
      console.log(`Root has ${children.length} children`);

      for (const child of children) {
        // Get parent (back to root)
        const parent = await child.getParent();
        console.log(`Node type: ${child.type}, parent type: ${parent?.type}`);

        // Get this node's children
        const grandchildren = await child.getChildren();
        console.log(`  Has ${grandchildren.length} children`);
      }
    } finally {
      doc.dispose();
    }
  }
  ```
</CodeGroup>

### Siblings

<CodeGroup>
  ```python Python theme={null}
  with Document.from_kddb("document.kddb") as doc:
      paragraphs = doc.select("//paragraph")

      for para in paragraphs:
          # Get all siblings (nodes with same parent)
          siblings = para.get_siblings()
          print(f"Has {len(siblings)} siblings")

          # Navigate to next/previous sibling
          next_node = para.next_node()
          prev_node = para.previous_node()

          if next_node:
              print(f"Next: {next_node.type}")
          if prev_node:
              print(f"Previous: {prev_node.type}")
  ```

  ```typescript TypeScript theme={null}
  async function navigateSiblings() {
    await Kodexa.init();
    const doc = await Kodexa.fromBlob(kddbBlob);

    try {
      const paragraphs = await doc.select('//paragraph');

      for (const para of paragraphs) {
        // Navigate to next/previous sibling
        const nextNode = await para.nextNode();
        const prevNode = await para.previousNode();

        // Check position
        const isFirst = await para.isFirstChild();
        const isLast = await para.isLastChild();

        console.log(`First: ${isFirst}, Last: ${isLast}`);
      }
    } finally {
      doc.dispose();
    }
  }
  ```
</CodeGroup>

### Depth and Position

<CodeGroup>
  ```python Python theme={null}
  with Document.from_kddb("document.kddb") as doc:
      nodes = doc.select("//*")

      for node in nodes:
          # Depth in tree (root = 0)
          depth = node.get_depth()

          # Index among siblings
          index = node.index

          print(f"Type: {node.type}, Depth: {depth}, Index: {index}")
  ```

  ```typescript TypeScript theme={null}
  async function nodePositions() {
    await Kodexa.init();
    const doc = await Kodexa.fromBlob(kddbBlob);

    try {
      const nodes = await doc.select('//*');

      for (const node of nodes) {
        // Depth in tree
        const depth = await node.getDepth();

        // Index among siblings
        const index = node.index;

        console.log(`Type: ${node.type}, Depth: ${depth}, Index: ${index}`);
      }
    } finally {
      doc.dispose();
    }
  }
  ```
</CodeGroup>

## Node Features

Features are typed key-value metadata attached to individual nodes:

<CodeGroup>
  ```python Python theme={null}
  with Document() as doc:
      root = doc.create_node("document")
      doc.content_node = root
      para = doc.create_node("paragraph", "Styled text", parent=root)

      # Add features (type, name, value)
      para.add_feature("style", "font-family", "Arial")
      para.add_feature("style", "font-size", "12pt")
      para.add_feature("style", "font-weight", "bold")
      para.add_feature("spatial", "bbox", {"x": 100, "y": 200, "w": 300, "h": 50})
      para.add_feature("ocr", "confidence", 0.95)

      # Retrieve a specific feature
      font = para.get_feature("style", "font-family")
      if font:
          print(f"Font: {font.get_value()}")

      # Get all features of a type
      style_features = para.get_features_of_type("style")
      for f in style_features:
          print(f"  {f.name}: {f.get_value()}")

      # Get all features
      all_features = para.get_features()
      print(f"Total features: {len(all_features)}")

      # Check if feature exists
      has_bbox = para.has_feature("spatial", "bbox")
  ```

  ```typescript TypeScript theme={null}
  async function nodeFeatures() {
    await Kodexa.init();
    const doc = await Kodexa.createDocument();

    try {
      const root = await doc.createNode('document');
      const para = await doc.createNode('paragraph');
      await para.setContent('Styled text');
      await root.addChild(para);

      // Add features (type, name, value)
      await para.setFeature('style', 'font-family', 'Arial');
      await para.setFeature('style', 'font-size', '12pt');
      await para.setFeature('style', 'font-weight', 'bold');
      await para.setFeature('spatial', 'bbox', { x: 100, y: 200, w: 300, h: 50 });
      await para.setFeature('ocr', 'confidence', 0.95);

      // Retrieve a specific feature value
      const font = await para.getFeatureValue('style', 'font-family');
      console.log(`Font: ${font}`);

      // Get all features of a type
      const styleFeatures = await para.getFeaturesOfType('style');
      for (const f of styleFeatures) {
        console.log(`  ${f.name}: ${f.value}`);
      }

      // Get all features
      const allFeatures = await para.getFeatures();
      console.log(`Total features: ${allFeatures.length}`);

      // Check if feature exists
      const hasBbox = await para.hasFeature('spatial', 'bbox');
    } finally {
      doc.dispose();
    }
  }
  ```
</CodeGroup>

## Node Tags

Tags annotate nodes with labels, optional confidence scores, and values:

<CodeGroup>
  ```python Python theme={null}
  with Document() as doc:
      root = doc.create_node("document")
      doc.content_node = root
      para = doc.create_node("paragraph", "Invoice total: $1,234.56", parent=root)

      # Simple tag
      para.tag("important")

      # Tag with confidence and value
      para.tag("invoice-total", confidence=0.95, value="$1,234.56")

      # Tag with additional data
      para.tag("extracted-field",
          confidence=0.92,
          value="1234.56",
          tag_uuid="field-uuid-123"
      )

      # Check for tag
      if para.has_tag("important"):
          print("Node is marked important")

      # Get tag details
      tag = para.get_tag("invoice-total")
      if tag:
          print(f"Value: {tag.get('Value')}")
          print(f"Confidence: {tag.get('Confidence')}")

      # Get all tags
      all_tags = para.get_tags()
      print(f"Tags: {all_tags}")

      # Remove a tag
      para.remove_tag("important")
  ```

  ```typescript TypeScript theme={null}
  async function nodeTags() {
    await Kodexa.init();
    const doc = await Kodexa.createDocument();

    try {
      const root = await doc.createNode('document');
      const para = await doc.createNode('paragraph');
      await para.setContent('Invoice total: $1,234.56');
      await root.addChild(para);

      // Simple tag
      await para.tag('important');

      // Tag with options
      await para.tagWithOptions('invoice-total', {
        confidence: 0.95,
        value: '$1,234.56'
      });

      // Check for tag
      const hasTag = await para.hasTag('important');
      if (hasTag) {
        console.log('Node is marked important');
      }

      // Get all tags
      const allTags = await para.getTags();
      console.log(`Tags: ${allTags}`);

      // Remove a tag
      await para.removeTag('important');
    } finally {
      doc.dispose();
    }
  }
  ```
</CodeGroup>

## Spatial Data (Bounding Boxes)

Nodes can have spatial information for document layout:

<CodeGroup>
  ```python Python theme={null}
  with Document() as doc:
      root = doc.create_node("document")
      doc.content_node = root
      para = doc.create_node("paragraph", "Text on page", parent=root)

      # Set bounding box via feature
      para.add_feature("spatial", "bbox", {
          "x": 100,      # Left position
          "y": 200,      # Top position
          "width": 300,  # Width
          "height": 50   # Height
      })

      # Set page reference
      para.add_feature("spatial", "page", 0)

      # Get bounding box
      bbox = para.get_feature("spatial", "bbox")
      if bbox:
          box = bbox.get_value()
          print(f"Position: ({box['x']}, {box['y']})")
          print(f"Size: {box['width']} x {box['height']}")
  ```

  ```typescript TypeScript theme={null}
  async function spatialData() {
    await Kodexa.init();
    const doc = await Kodexa.createDocument();

    try {
      const root = await doc.createNode('document');
      const para = await doc.createNode('paragraph');
      await para.setContent('Text on page');
      await root.addChild(para);

      // Set bounding box
      await para.setBBox(100, 200, 300, 50);

      // Get bounding box
      const bbox = await para.getBBox();
      if (bbox) {
        console.log(`Position: (${bbox.x}, ${bbox.y})`);
        console.log(`Size: ${bbox.width} x ${bbox.height}`);
      }

      // Set rotation
      await para.setRotate(90);
    } finally {
      doc.dispose();
    }
  }
  ```
</CodeGroup>

## Building Document Structures

### Invoice Example

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

  def build_invoice_structure():
      with Document() as doc:
          # Document root
          root = doc.create_node("document", "Invoice #12345")
          doc.content_node = root

          # Header section
          header = doc.create_node("section", "Header", parent=root)

          vendor = doc.create_node("paragraph", "Vendor: Acme Corp", parent=header)
          vendor.tag("vendor-name", value="Acme Corp", confidence=0.98)

          date = doc.create_node("paragraph", "Date: 2024-01-15", parent=header)
          date.tag("invoice-date", value="2024-01-15", confidence=0.95)

          # Line items table
          table = doc.create_node("table", parent=root)

          items = [
              ("Widget A", "100.00"),
              ("Widget B", "250.00"),
              ("Service Fee", "50.00")
          ]

          for desc, amount in items:
              row = doc.create_node("row", parent=table)

              desc_cell = doc.create_node("cell", desc, parent=row)
              desc_cell.tag("line-item-description")

              amt_cell = doc.create_node("cell", f"${amount}", parent=row)
              amt_cell.tag("line-item-amount", value=amount, confidence=0.92)

          # Total
          total = doc.create_node("paragraph", "Total: $400.00", parent=root)
          total.tag("invoice-total", value="400.00", confidence=0.99)

          return doc
  ```

  ```typescript TypeScript theme={null}
  async function buildInvoiceStructure() {
    await Kodexa.init();
    const doc = await Kodexa.createDocument();

    try {
      // Document root
      const root = await doc.createNode('document');
      await root.setContent('Invoice #12345');

      // Header section
      const header = await doc.createNode('section');
      await header.setContent('Header');
      await root.addChild(header);

      const vendor = await doc.createNode('paragraph');
      await vendor.setContent('Vendor: Acme Corp');
      await header.addChild(vendor);
      await vendor.tagWithOptions('vendor-name', { value: 'Acme Corp', confidence: 0.98 });

      const date = await doc.createNode('paragraph');
      await date.setContent('Date: 2024-01-15');
      await header.addChild(date);
      await date.tagWithOptions('invoice-date', { value: '2024-01-15', confidence: 0.95 });

      // Line items table
      const table = await doc.createNode('table');
      await root.addChild(table);

      const items = [
        { desc: 'Widget A', amount: '100.00' },
        { desc: 'Widget B', amount: '250.00' },
        { desc: 'Service Fee', amount: '50.00' }
      ];

      for (const item of items) {
        const row = await doc.createNode('row');
        await table.addChild(row);

        const descCell = await doc.createNode('cell');
        await descCell.setContent(item.desc);
        await row.addChild(descCell);
        await descCell.tag('line-item-description');

        const amtCell = await doc.createNode('cell');
        await amtCell.setContent(`$${item.amount}`);
        await row.addChild(amtCell);
        await amtCell.tagWithOptions('line-item-amount', { value: item.amount, confidence: 0.92 });
      }

      // Total
      const total = await doc.createNode('paragraph');
      await total.setContent('Total: $400.00');
      await root.addChild(total);
      await total.tagWithOptions('invoice-total', { value: '400.00', confidence: 0.99 });

      return doc;
    } catch (e) {
      doc.dispose();
      throw e;
    }
  }
  ```
</CodeGroup>
