Skip to content

command query

goworm edited this page Jul 9, 2026 · 55 revisions

query

Query document elements using CSS-like selectors.

Synopsis

officecli query <file> <selector> [--find <text>] [--json | --compact [--fields k,v,...]]

Description

Searches the document for elements matching a CSS-like selector expression. Returns all matching elements with their paths and properties. Read-only.

Arguments

Name Type Required Default Description
file FileInfo Yes - Office document path
selector string Yes - CSS-like selector expression

Options

Name Type Required Default Description
--find string No - Case-insensitive text/value substring filter — hard rename of the legacy --text flag.
--json bool No false Output as structured JSON. Mutually exclusive with --compact.
--compact bool No false (v1.0.134+, pptx/docx only) One line per element instead of the full JSON tree — see --compact output below.
--fields string No - Comma-separated Format keys appended as extra k=v columns in --compact output (e.g. --fields x,y,width). Only meaningful with --compact.

Selector Syntax

Attribute Filters

Operator Meaning Example
= Exact match [style=Heading1]
!= Not equal [font!=Arial]
~= Contains text [text~=quarterly]
>= Greater or equal (numeric) [size>=24pt]
<= Less or equal (numeric) [size<=12pt]

Notes:

  • Filter diagnostics (v1.0.124+): when no matches are returned, --json output includes a structured filterDiagnostic object naming the unknown key (or the operator that didn't match) and a did-you-mean list — matches on both the full key and the last segment of a dotted key. Emitted operator-independently, so [size>=99] on the wrong element type explains why instead of returning silent-empty.
  • Can combine: shape[fill=FF0000][size>=24pt] (implicit AND)
  • Boolean and / or: cell[value>5000 or value<100], cell[(type=Number or type=Date) and value>0]. Applies to query, set, and remove across all three formats via the shared filter engine.
  • not(...) negation (v1.0.134+): not(expr) negates the inner expression — cell[not(value=hi)] matches every cell whose value isn't hi. not(key) alone (no operator) is exists-negation — cell[not(bold)] matches cells where bold is absent/falsy, the "column is empty" case that previously had no spelling. Word-bounded: a column literally named not still works as a predicate ([not=5]) and can be exists-checked with quotes (["not"]).
  • Top-level comma union (v1.0.133+): a comma outside any [...]/(...)/quotes splits the selector into independently-evaluated parts whose results are unioned (deduped by path) — row[Dept=Sales],row[Dept=Marketing] matches rows satisfying either predicate, across query/set/remove on all three formats. A comma inside brackets is not a union split: row[Dept=A,B] stays one predicate string passed to the handler. Positional unions (shape[1],shape[3]) worked before this fix; predicate unions (row[Dept=Sales],row[Dept=Marketing]) previously collapsed to an impossible AND and silently matched nothing outside PowerPoint.
  • Has-attribute exists: [link] matches any element where the attribute is present and non-empty.
  • Excel row-by-column-name: Sheet1!row[Salary>5000] matches rows where the named column's value satisfies the predicate (also works on detected header-row tables). OR'd table-column predicates inside row[…] fail loud, never silent.
  • Color-aware: [fill=#FF0000] matches [fill=FF0000]
  • Dimension-aware: compares 2cm vs 1in correctly
  • Special keys text and type match node content and type
  • \!= accepted for zsh compatibility

Child Selector

parent[filter] > child[filter]

Generic XML Fallback

Unknown selectors match any XML element by local name (case-insensitive).

Output Format

The query command returns a list of DocumentNodes matching the selector. The output varies depending on whether --json is used.

Text Output (default)

The text output starts with a match count, followed by each matching node listed with its path, text content, and formatting attributes.

Matches: {count}
  /body/p[1]: Heading text
    style: Heading1
    alignment: center
  /body/p[3]: Another paragraph
    style: Normal

Example:

Matches: 3
  /body/p[1]: Introduction
    style: Heading1
    alignment: center
    font: Arial
  /body/p[4]: Chapter One
    style: Heading1
    alignment: left
  /body/p[9]: Chapter Two
    style: Heading1
    alignment: left

JSON Output (--json)

With --json, the output is an object containing the match count and an array of DocumentNode results.

{
  "Matches": 3,
  "Results": [
    {
      "Path": "/body/p[1]",
      "Type": "Paragraph",
      "Text": "Introduction",
      "Preview": null,
      "Style": "Heading1",
      "ChildCount": 1,
      "Format": {
        "alignment": "center",
        "font": "Arial"
      },
      "Children": []
    },
    {
      "Path": "/body/p[4]",
      "Type": "Paragraph",
      "Text": "Chapter One",
      "Preview": null,
      "Style": "Heading1",
      "ChildCount": 1,
      "Format": {
        "alignment": "left"
      },
      "Children": []
    }
  ]
}

Each element in the Results array is a DocumentNode with the same fields as described in get Output Format: Path, Type, Text, Preview, Style, ChildCount, Format, and Children.

--compact Output (v1.0.134+, pptx/docx only)

For agent loops that only need path + text to locate an edit target, the full JSON tree is tens of fields of noise per node — on multi-page decks the output can run to tens of thousands of characters and get truncated by observation limits, silently hiding matches. --compact renders one TSV-ish line per element instead:

{path}<TAB>[{label}]<TAB>"{text, ≤60 chars, \t/\n/"/\\ escaped, … if truncated}"
{path}<TAB>[table {R}x{C}]                    (tables fold to one line, no cell descent)
{path}<TAB>[{label}]<TAB>(empty)               (no text)
total: N of M elements[ / K slides]            (always the final line, even on 0 matches)
  • pptx labels carry the semantic type (title/placeholder/textbox/shape); docx paragraphs label by style name.
  • N equals the element lines above (a folded table counts as 1) — lineCount-1 == N mechanically proves the reader saw every match.
  • M counts all top-level frames regardless of selector (docx excludes sectPr — layout metadata isn't addressable).
  • --fields x,y,width appends opt-in k=v columns after the text column (a missing key emits k=).
  • This is a stability contract — column order, the TAB separator, truncation, (empty), [label] brackets, and the total-line shape may only gain new trailing columns, never change or reorder existing ones.
  • xlsx rejects --compactview text is already the per-row compact form; the error points at view text --range instead.
  • --json and --compact are mutually exclusive.
officecli query deck.pptx shape --compact
officecli query deck.pptx shape --compact --fields x,y,width

Format-Specific References

See Also


Based on OfficeCLI v1.0.134

Clone this wiki locally