# How to Query Elements in Office Documents Using CSS-Like Selectors in OfficeCLI

> Effortlessly query Office documents using CSS selectors with OfficeCLI. Extract specific elements from Word, Excel, and PowerPoint files easily. Learn how to use the query command.

- Repository: [OfficeAI/OfficeCLI](https://github.com/iofficeai/OfficeCLI)
- Tags: how-to-guide
- Published: 2026-07-28

---

**OfficeCLI enables precise extraction of document elements from Word, Excel, and PowerPoint files by accepting CSS-style selector strings through its `query` command.**

OfficeCLI is an open-source command-line interface and SDK for programmatic Office document manipulation. You can **query elements in Office documents using CSS-like selectors** to target specific paragraphs, table rows, or text runs without manually parsing Open XML. The resident server parses your selector and returns matching nodes as structured JSON objects.

## How the Query Command Processes Selectors

When you send a `query` command, the resident server ([`ResidentServer.cs`](https://github.com/iOfficeAI/OfficeCLI/blob/main/ResidentServer.cs)) immediately validates the presence of a selector argument. According to the source code at lines 2073–2079, the server checks for the `selector` parameter or its alias `path`, throwing an `ArgumentException` if neither is provided:

```csharp
// ResidentServer.cs – lines 2073-2079
var selector = req.GetArgOrNull("selector") ?? req.GetArgOrNull("path") ?? "";
if (string.IsNullOrEmpty(selector))
    throw new ArgumentException("'query' requires a selector. Example: {\"command\": \"query\", \"selector\": \"row[Score>80]\"}");

```

Once validated, the selector string is passed to `AttributeFilter.FilterSelector`, which invokes the language-agnostic selector engine implemented in [`WordHandler.Selector.cs`](https://github.com/iOfficeAI/OfficeCLI/blob/main/WordHandler.Selector.cs). This design allows the same CSS-like syntax to work across Word, Excel, and PowerPoint documents.

## CSS-Like Selector Syntax Supported

The selector parser located in [`src/officecli/Handlers/Word/WordHandler.Selector.cs`](https://github.com/iOfficeAI/OfficeCLI/blob/main/src/officecli/Handlers/Word/WordHandler.Selector.cs) (lines 15–122) implements a subset of CSS selectors specifically tailored for Office document structures. The parsing logic uses `ParseSelector`, `SplitChildCombinator`, and `ParseSingleSelector` to tokenize your query before matching against the document DOM.

### Element Names

Target specific Office XML elements using case-insensitive tag names:

- `p` – paragraphs
- `run` – text runs
- `row` – table rows (Excel/Word tables)
- `cell` – table cells

### Attribute Tests

Filter elements by their XML attributes using bracket notation:

- `[attr=value]` – exact string match
- `[attr>num]` – numeric greater-than comparison
- `[attr<"text"]` – string less-than comparison (lexical)

### Pseudo-Selectors

Refine selections with functional pseudo-classes:

- `:contains("text")` – elements containing specific text
- `:empty` – elements with no child content
- `:no-alt` – elements lacking alternative text attributes

### Child Combinators

Navigate document hierarchies using the child combinator `>` (the parser specifically skips `>` characters inside brackets to avoid confusion with attribute operators):

```csharp
// Example: table > row > cell selects direct cell children of rows within tables

```

## Python SDK Integration

The Python wrapper ([`sdk/python/officecli.py`](https://github.com/iOfficeAI/OfficeCLI/blob/main/sdk/python/officecli.py)) exposes the selector functionality by forwarding your dictionary directly to the resident process. Lines 24–26 of the SDK include `selector` in the top-level request schema alongside fields like `index`, `after`, `before`, and `xpath`:

```python

# sdk/python/officecli.py – field list excerpt

# ... index, after, before, to, selector, text, mode, depth, part, xpath, action, …

```

This means any Python code can query documents by including the `selector` key in the request payload.

## Practical Code Examples

### Python SDK Example

Query Excel rows where the Score column exceeds 80:

```python
import officecli

with officecli.create("sales.xlsx") as doc:
    result = doc.send({
        "command": "query",
        "selector": "row[Score>80]"
    })
    print("High scores:", result)

```

### Direct CLI Usage

From the command line, use the `--selector` flag to extract paragraphs containing specific text:

```bash
officecli query --selector "p:contains('Important')" report.docx

```

### Internal C# Implementation

For reference, the internal evaluation flow uses `AttributeFilter.FilterSelector` with a key resolver to map attribute names to values:

```csharp
var (matches, warnings) = AttributeFilter.FilterSelector(
        selector,               // e.g., "row[Score>80]"
        _handler.Query,        // document-specific query delegate
        keyResolver);          // attribute name resolver

```

The `MatchesParagraphAttrs` and `MatchesRunSelector` methods then verify each candidate node against the parsed `SelectorPart` objects.

## Summary

- **Argument validation** occurs in [`ResidentServer.cs`](https://github.com/iOfficeAI/OfficeCLI/blob/main/ResidentServer.cs) (lines 2073–2079), requiring either `selector` or `path` parameters.
- **Parser implementation** resides in [`WordHandler.Selector.cs`](https://github.com/iOfficeAI/OfficeCLI/blob/main/WordHandler.Selector.cs) (lines 15–122), supporting element names, attribute tests, pseudo-selectors, and child combinators.
- **Cross-format support** means selectors work identically across Word, Excel, and PowerPoint documents.
- **Python SDK** at [`sdk/python/officecli.py`](https://github.com/iOfficeAI/OfficeCLI/blob/main/sdk/python/officecli.py) (lines 24–26) forwards the selector field transparently to the resident server.
- **Return format** consists of JSON objects representing matched nodes, or raw text for non-JSON payloads.

## Frequently Asked Questions

### What happens if I omit the selector argument in a query command?

The resident server raises an `ArgumentException` with a specific error message. In [`ResidentServer.cs`](https://github.com/iOfficeAI/OfficeCLI/blob/main/ResidentServer.cs) at lines 2073–2079, the code checks for `selector` or `path` arguments, and if both are missing or empty, it throws: `'query' requires a selector. Example: {"command": "query", "selector": "row[Score>80]"}`.

### Which document elements can I target with CSS-like selectors?

You can target structural elements including paragraphs (`p`), text runs (`run`), table rows (`row`), and table cells (`cell`). The selector engine also supports attribute-based filtering like `[attr=value]` and pseudo-selectors such as `:contains("text")` and `:empty`.

### How does the Python SDK handle selector queries?

The Python SDK ([`sdk/python/officecli.py`](https://github.com/iOfficeAI/OfficeCLI/blob/main/sdk/python/officecli.py)) treats the selector as a standard request field. When you call `doc.send()` with a dictionary containing `"command": "query"` and a `"selector"` string, the SDK serializes this payload and pipes it to the resident server, returning the parsed JSON response directly to your Python code.

### Can I use the child combinator `>` inside attribute values?

The parser in [`WordHandler.Selector.cs`](https://github.com/iOfficeAI/OfficeCLI/blob/main/WordHandler.Selector.cs) specifically handles this edge case by skipping `>` characters that appear inside brackets. This allows you to safely use comparison operators like `[attr>80]` without the parser misinterpreting the `>` as a child combinator.