Path-Based Addressing in OfficeCLI: How `/slide[1]/shape[2]` 1-Based Indexing Works
OfficeCLI locates elements inside Office documents using hierarchical paths that follow /type[index] syntax with 1-based indexing, where the first element is [1] and the final element can be referenced using last().
OfficeCLI (iOfficeAI/OfficeCLI) provides a command-line interface for programmatically manipulating Word, Excel, and PowerPoint files. Understanding path-based addressing is essential for scripting document modifications, as every element—from slides to shapes to paragraphs—is identified via filesystem-like paths that use 1-based numerical indexing rather than conventional 0-based arrays.
Path Syntax Fundamentals
OfficeCLI treats Office documents as hierarchical XML trees where each element is addressed by a path segment consisting of the element's local XML tag name followed by an index in square brackets. According to the README.md (lines 14-16), the standard format follows this pattern:
/<element-type>[<index>]/<child-type>[<index>]
The index values start at 1, not 0. This means /slide[1] refers to the first slide in a presentation, while /slide[1]/shape[2] targets the second shape on that first slide. When the index is omitted entirely, as in /slide, the command operates on all matching children of that type.
Indexing Strategies and Selectors
Positional Indexing (1-Based)
Positional indexes reflect an element's current location in the document structure. The first element of any type is always [1], the second [2], and so forth. As documented in skills/officecli-pptx/SKILL.md (lines 30-33), these indexes are dynamic—they shift immediately when elements are added or removed, making positional addressing convenient for sequential access but potentially unstable during batch operations that modify structure.
Named Attribute Selectors
For stable references that survive structural changes, OfficeCLI supports attribute selectors using the @ symbol. Instead of relying on the positional index /slide[1]/shape[2], you can reference /slide[1]/shape[@name=Subtitle] to target a shape by its name property. This approach remains valid even if the shape's numerical position changes due to insertions or deletions elsewhere in the document.
Special Selectors
The last() function provides a convenient way to address the most recently added element without knowing its numerical index. For example, /slide[last()] targets the final slide in a presentation, while /slide[1]/shape[last()] selects the last shape on the first slide regardless of how many shapes exist.
Element Types and Document Hierarchy
Different Office formats use specific XML tag names as path segments that correspond to their underlying Open XML structure:
- PowerPoint:
slide,shape,chart,table - Word:
paragraph,table,run - Excel:
sheet,row,cell,chart
The TypeScript interfaces in sdk/node/index.d.ts define these paths as strings passed to the path parameter across SDK methods, validating that the element type names match the local XML tags for each Office format.
Shell Quoting Requirements
Because paths contain square brackets and special characters that trigger shell globbing patterns, they must be properly quoted when used in terminal commands. The documentation in skills/officecli-pptx/SKILL.md specifically warns that unquoted brackets may cause the shell to interpret them as wildcard patterns. Always use single or double quotes around paths:
officecli get deck.pptx '/slide[1]/shape[2]'
Practical Implementation Examples
The following workflow demonstrates creating a presentation, navigating its structure via 1-based paths, and manipulating elements using both positional and named addressing:
# Create a new presentation
officecli create deck.pptx
# Add a slide (automatically becomes /slide[1])
officecli add deck.pptx / --type slide --prop title="Q4 Report"
# Add two shapes to the first slide
officecli add deck.pptx '/slide[1]' --type shape --prop name=Title --prop text="Revenue"
officecli add deck.pptx '/slide[1]' --type shape --prop name=Subtitle --prop text="25% Growth"
# Retrieve the second shape by positional index (1-based)
officecli get deck.pptx '/slide[1]/shape[2]' --json
# Returns: {"tag":"shape","path":"/slide[1]/shape[2]","attributes":{"name":"Subtitle","text":"25% Growth"}}
# Access the same element using stable name attribute
officecli get deck.pptx '/slide[1]/shape[@name=Subtitle]' --json
# Update fill color using positional path
officecli set deck.pptx '/slide[1]/shape[1]' --prop fill=FF0000
# Remove the final slide regardless of total count
officecli remove deck.pptx '/slide[last()]'
# Batch operations targeting specific paths
cat <<EOF | officecli batch deck.pptx --json
[
{"command":"set","path":"/slide[1]/shape[1]","props":{"text":"Q4 Revenue"}},
{"command":"set","path":"/slide[1]/shape[2]","props":{"text":"+25% YoY"}}
]
EOF
After any structural mutation—such as adding, removing, or reordering slides or shapes—you should re-query the document to confirm current indexes, as positional references may have shifted.
Summary
- OfficeCLI uses 1-based indexing where the first element is
[1], not[0], as documented inREADME.md - Paths follow the syntax
/<element-type>[<index>]and support arbitrary nesting depth for parent-child relationships - Positional indexes reflect current document state and shift during structural edits, while named selectors (
[@name=value]) provide stable references across mutations - The
last()selector addresses the final element of a type without requiring knowledge of the total count - Always quote paths containing brackets to prevent shell interpretation errors
- Omitting the index operates on all matching elements of that type
Frequently Asked Questions
Why does OfficeCLI use 1-based indexing instead of 0-based?
OfficeCLI adopts 1-based indexing to align with user expectations from traditional document editing interfaces and Microsoft Office's internal object model conventions. According to the repository's README.md, this makes the CLI more intuitive for non-programmers while maintaining consistency with how Office applications natively reference slide numbers and paragraph positions.
How do I address the last element without knowing its index?
Use the last() function in your path, such as /slide[last()] for the final slide or /slide[1]/shape[last()] for the last shape on the first slide. This selector dynamically resolves to the highest index currently present for that element type, making it ideal for scripts that append elements and then need to modify the most recent addition.
What happens to indexes when I add or remove elements?
Positional indexes are dynamic and shift immediately after structural changes. If you delete /slide[1], what was previously /slide[2] becomes /slide[1]. Similarly, inserting a new slide before existing ones renumbers all subsequent slides. For stable scripting across document mutations, use attribute selectors like [@name=Title] rather than numeric indexes.
Do I need special syntax for attribute values containing spaces?
Yes, when using attribute selectors with values containing spaces, ensure proper shell quoting and include the value in quotes within the path. For example: '/slide[1]/shape[@name="Main Title"]'. Regardless of content, the square brackets and equals sign in paths always require shell quoting to prevent glob expansion, as noted in the PPTX skill documentation.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →