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

# Selectors

> Query Kodexa documents with the selector engine, an XPath-like syntax for finding nodes, filtering by attributes, and navigating document hierarchies.

Selectors provide a powerful XPath-like syntax for querying nodes within a Kodexa document. Use selectors to find specific content, filter by attributes, and navigate the document structure.

## Basic Selectors

### Select All Nodes

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

  with Document.from_kddb("document.kddb") as doc:
      # Select all nodes in the document
      all_nodes = doc.select("//*")
      print(f"Total nodes: {len(all_nodes)}")

      # Select the first match only
      first_node = doc.select_first("//*")
      if first_node:
          print(f"First node type: {first_node.type}")
  ```

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

  async function selectAll() {
    await Kodexa.init();
    const doc = await Kodexa.fromBlob(kddbBlob);

    try {
      // Select all nodes
      const allNodes = await doc.select('//*');
      console.log(`Total nodes: ${allNodes.length}`);

      // Select the first match only
      const firstNode = await doc.selectFirst('//*');
      if (firstNode) {
        console.log(`First node type: ${firstNode.type}`);
      }
    } finally {
      doc.dispose();
    }
  }
  ```
</CodeGroup>

### Select by Node Type

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

      # All tables
      tables = doc.select("//table")

      # All pages
      pages = doc.select("//page")

      # First paragraph only
      first_para = doc.select_first("//paragraph")

      print(f"Found {len(paragraphs)} paragraphs")
      print(f"Found {len(tables)} tables")
      print(f"Found {len(pages)} pages")
  ```

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

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

      // All tables
      const tables = await doc.select('//table');

      // All pages
      const pages = await doc.select('//page');

      // First paragraph only
      const firstPara = await doc.selectFirst('//paragraph');

      console.log(`Found ${paragraphs.length} paragraphs`);
      console.log(`Found ${tables.length} tables`);
      console.log(`Found ${pages.length} pages`);
    } finally {
      doc.dispose();
    }
  }
  ```
</CodeGroup>

## Path Expressions

### Absolute vs Descendant Paths

| Selector               | Description                                        |
| ---------------------- | -------------------------------------------------- |
| `//paragraph`          | All paragraphs anywhere in document                |
| `/document/paragraph`  | Direct child paragraphs of root                    |
| `//section/paragraph`  | Paragraphs that are direct children of any section |
| `//section//paragraph` | Paragraphs anywhere under any section              |

<CodeGroup>
  ```python Python theme={null}
  with Document.from_kddb("document.kddb") as doc:
      # Direct children of root
      root_children = doc.select("/document/*")

      # Paragraphs directly under sections
      section_paragraphs = doc.select("//section/paragraph")

      # Paragraphs anywhere under sections (including nested)
      all_section_paras = doc.select("//section//paragraph")

      # Cells in tables
      cells = doc.select("//table/row/cell")
  ```

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

    try {
      // Direct children of root
      const rootChildren = await doc.select('/document/*');

      // Paragraphs directly under sections
      const sectionParagraphs = await doc.select('//section/paragraph');

      // Paragraphs anywhere under sections
      const allSectionParas = await doc.select('//section//paragraph');

      // Cells in tables
      const cells = await doc.select('//table/row/cell');
    } finally {
      doc.dispose();
    }
  }
  ```
</CodeGroup>

## Content Filtering

### Contains Function

<CodeGroup>
  ```python Python theme={null}
  with Document.from_kddb("document.kddb") as doc:
      # Paragraphs containing specific text
      invoices = doc.select("//paragraph[contains(@content, 'invoice')]")

      # Case-sensitive search
      total_nodes = doc.select("//paragraph[contains(@content, 'Total:')]")

      # Search in any node type
      matches = doc.select("//*[contains(@content, 'important')]")

      print(f"Found {len(invoices)} paragraphs mentioning invoice")
  ```

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

    try {
      // Paragraphs containing specific text
      const invoices = await doc.select("//paragraph[contains(@content, 'invoice')]");

      // Case-sensitive search
      const totalNodes = await doc.select("//paragraph[contains(@content, 'Total:')]");

      // Search in any node type
      const matches = await doc.select("//*[contains(@content, 'important')]");

      console.log(`Found ${invoices.length} paragraphs mentioning invoice`);
    } finally {
      doc.dispose();
    }
  }
  ```
</CodeGroup>

### Starts-With and Ends-With

<CodeGroup>
  ```python Python theme={null}
  with Document.from_kddb("document.kddb") as doc:
      # Content starting with specific text
      headers = doc.select("//paragraph[starts-with(@content, 'Section')]")

      # Content ending with specific text (if supported)
      # Note: Check SDK version for ends-with support
  ```

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

    try {
      // Content starting with specific text
      const headers = await doc.select("//paragraph[starts-with(@content, 'Section')]");

      console.log(`Found ${headers.length} section headers`);
    } finally {
      doc.dispose();
    }
  }
  ```
</CodeGroup>

## Tag Filtering

### Select Tagged Nodes

<CodeGroup>
  ```python Python theme={null}
  with Document.from_kddb("document.kddb") as doc:
      # Nodes with any tag
      tagged = doc.select("//*[hasTag()]")

      # Nodes with a specific tag
      important = doc.select("//*[@tag='important']")

      # Nodes with tag matching a prefix
      invoice_fields = doc.select("//*[hasTag('invoice-')]")

      # Combine tag and type
      invoice_totals = doc.select("//paragraph[@tag='invoice-total']")

      print(f"Found {len(tagged)} tagged nodes")
      print(f"Found {len(important)} important nodes")
  ```

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

    try {
      // Nodes with any tag
      const tagged = await doc.select("//*[hasTag()]");

      // Nodes with a specific tag
      const important = await doc.select("//*[@tag='important']");

      // Nodes with tag matching prefix
      const invoiceFields = await doc.select("//*[hasTag('invoice-')]");

      // Combine tag and type
      const invoiceTotals = await doc.select("//paragraph[@tag='invoice-total']");

      console.log(`Found ${tagged.length} tagged nodes`);
    } finally {
      doc.dispose();
    }
  }
  ```
</CodeGroup>

### Get Tagged Node Details

<CodeGroup>
  ```python Python theme={null}
  with Document.from_kddb("document.kddb") as doc:
      # Find all nodes with invoice-total tag
      totals = doc.select("//*[@tag='invoice-total']")

      for node in totals:
          # Get the tag details
          tag = node.get_tag("invoice-total")
          if tag:
              value = tag.get("Value")
              confidence = tag.get("Confidence")
              print(f"Total: {value} (confidence: {confidence})")
  ```

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

    try {
      // Find all nodes with invoice-total tag
      const totals = await doc.select("//*[@tag='invoice-total']");

      for (const node of totals) {
        // Get tag via features
        const tags = await node.getTags();
        console.log(`Node has tags: ${tags.join(', ')}`);
        console.log(`Content: ${node.content}`);
      }
    } finally {
      doc.dispose();
    }
  }
  ```
</CodeGroup>

## Position Filtering

### Index-Based Selection

<CodeGroup>
  ```python Python theme={null}
  with Document.from_kddb("document.kddb") as doc:
      # First paragraph (1-indexed)
      first = doc.select("//paragraph[1]")

      # Second paragraph
      second = doc.select("//paragraph[2]")

      # Last paragraph
      last = doc.select("//paragraph[last()]")

      # First three paragraphs
      first_three = doc.select("//paragraph[position() <= 3]")
  ```

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

    try {
      // First paragraph
      const first = await doc.select('//paragraph[1]');

      // Second paragraph
      const second = await doc.select('//paragraph[2]');

      // Using selectFirst for single results
      const firstPara = await doc.selectFirst('//paragraph');

      console.log(`First paragraph: ${firstPara?.content}`);
    } finally {
      doc.dispose();
    }
  }
  ```
</CodeGroup>

## Variables in Selectors

### Parameterized Queries

<CodeGroup>
  ```python Python theme={null}
  with Document.from_kddb("document.kddb") as doc:
      # Use variables in selectors
      variables = {"search_term": "invoice"}
      matches = doc.select(
          "//paragraph[contains(@content, $search_term)]",
          variables=variables
      )

      # Multiple variables
      variables = {
          "tag_name": "invoice-total",
          "min_confidence": 0.9
      }
      high_confidence = doc.select(
          "//*[@tag=$tag_name]",
          variables=variables
      )

      print(f"Found {len(matches)} matches")
  ```

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

    try {
      // Variables can be passed depending on SDK version
      // Check SDK documentation for exact syntax

      // Alternative: build selector string dynamically
      const searchTerm = 'invoice';
      const matches = await doc.select(
        `//paragraph[contains(@content, '${searchTerm}')]`
      );

      console.log(`Found ${matches.length} matches`);
    } finally {
      doc.dispose();
    }
  }
  ```
</CodeGroup>

## Common Selector Patterns

### Quick Reference

| Pattern             | Selector                                         | Description                     |
| ------------------- | ------------------------------------------------ | ------------------------------- |
| All nodes           | `//*`                                            | Every node in document          |
| By type             | `//paragraph`                                    | All paragraphs                  |
| Direct children     | `//section/paragraph`                            | Paragraphs under sections       |
| Any depth           | `//section//paragraph`                           | Paragraphs anywhere in sections |
| First of type       | `//paragraph[1]`                                 | First paragraph                 |
| By tag              | `//*[@tag='important']`                          | Tagged nodes                    |
| By content          | `//paragraph[contains(@content, 'text')]`        | Content search                  |
| Multiple conditions | `//paragraph[@tag='x'][contains(@content, 'y')]` | Combined filters                |

### Real-World Examples

<CodeGroup>
  ```python Python theme={null}
  with Document.from_kddb("document.kddb") as doc:
      # Extract all invoice line items
      line_items = doc.select("//row[@tag='line-item']")

      # Find vendor information
      vendor = doc.select_first("//paragraph[@tag='vendor-name']")

      # Get all amounts in a table
      amounts = doc.select("//table//cell[contains(@content, '$')]")

      # Find headers (paragraphs at start of sections)
      headers = doc.select("//section/paragraph[1]")

      # Get all nodes on page 1 (if page structure exists)
      page1_nodes = doc.select("//page[1]//*")

      # Find paragraphs with high-confidence tags
      # (filter in Python after selecting)
      tagged_paras = doc.select("//paragraph[hasTag()]")
      high_conf = [
          p for p in tagged_paras
          for tag in [p.get_tag(t) for t in p.get_tags()]
          if tag and tag.get("Confidence", 0) > 0.9
      ]
  ```

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

    try {
      // Extract all invoice line items
      const lineItems = await doc.select("//row[@tag='line-item']");

      // Find vendor information
      const vendor = await doc.selectFirst("//paragraph[@tag='vendor-name']");
      if (vendor) {
        console.log(`Vendor: ${vendor.content}`);
      }

      // Get all amounts in a table
      const amounts = await doc.select("//table//cell[contains(@content, '$')]");

      // Find headers (paragraphs at start of sections)
      const headers = await doc.select('//section/paragraph[1]');

      // Get all nodes on page 1
      const page1Nodes = await doc.select('//page[1]//*');

      console.log(`Line items: ${lineItems.length}`);
      console.log(`Amount cells: ${amounts.length}`);
    } finally {
      doc.dispose();
    }
  }
  ```
</CodeGroup>

## Working with Results

### Iterating Results

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

      for para in paragraphs:
          # Access node properties
          print(f"Type: {para.type}")
          print(f"Content: {para.content}")
          print(f"UUID: {para.uuid}")

          # Check tags
          if para.has_tag("important"):
              print("  -> Important!")

          # Get features
          font = para.get_feature("style", "font-family")
          if font:
              print(f"  Font: {font.get_value()}")
  ```

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

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

      for (const para of paragraphs) {
        // Access node properties
        console.log(`Type: ${para.type}`);
        console.log(`Content: ${para.content}`);

        // Check tags
        const hasImportant = await para.hasTag('important');
        if (hasImportant) {
          console.log('  -> Important!');
        }

        // Get features
        const font = await para.getFeatureValue('style', 'font-family');
        if (font) {
          console.log(`  Font: ${font}`);
        }
      }
    } finally {
      doc.dispose();
    }
  }
  ```
</CodeGroup>

### Chaining Selections

<CodeGroup>
  ```python Python theme={null}
  with Document.from_kddb("document.kddb") as doc:
      # Find all tables, then get cells from each
      tables = doc.select("//table")

      for table in tables:
          # Select within the context of this table node
          cells = table.select(".//cell")
          print(f"Table has {len(cells)} cells")

          # Get just the first row's cells
          first_row_cells = table.select("./row[1]/cell")
  ```

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

    try {
      // Find all tables
      const tables = await doc.select('//table');

      for (const table of tables) {
        // Get children and filter
        const children = await table.getChildren();
        const rows = children.filter(c => c.type === 'row');

        console.log(`Table has ${rows.length} rows`);
      }
    } finally {
      doc.dispose();
    }
  }
  ```
</CodeGroup>

## Performance Tips

<Note>
  For large documents, optimize your selectors:

  1. Be specific with paths (`//table/row/cell` vs `//*`)
  2. Use `select_first()` when you only need one result
  3. Combine conditions in one selector vs multiple queries
  4. Cache selector results when iterating multiple times
</Note>

<CodeGroup>
  ```python Python theme={null}
  with Document.from_kddb("large_document.kddb") as doc:
      # Good: Specific path
      cells = doc.select("//table/row/cell")

      # Less efficient: Broad search
      # all_nodes = doc.select("//*")

      # Good: Single result
      first = doc.select_first("//paragraph[@tag='title']")

      # Good: Combined conditions
      matches = doc.select("//paragraph[@tag='important'][contains(@content, 'urgent')]")

      # Less efficient: Multiple queries
      # tagged = doc.select("//paragraph[@tag='important']")
      # matches = [p for p in tagged if 'urgent' in p.content]
  ```

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

    try {
      // Good: Specific path
      const cells = await doc.select('//table/row/cell');

      // Good: Single result
      const first = await doc.selectFirst("//paragraph[@tag='title']");

      // Good: Combined conditions
      const matches = await doc.select(
        "//paragraph[@tag='important'][contains(@content, 'urgent')]"
      );
    } finally {
      doc.dispose();
    }
  }
  ```
</CodeGroup>
