A terminal explorer for OData CSDL metadata. Parse any $metadata XML and discover entities, properties, relationships, and field attributes โ then query live OData services directly from the terminal.
OData services expose their schema through $metadata but those XML documents can be enormous (10MB+, 700+ entities). This tool parses the CSDL and gives you fast, searchable access to every entity, property, navigation relationship, and annotation.
Particularly useful with SAP SuccessFactors, where documentation says "Worker Category" but the actual field is customString17.
pip install csdl-explore # Rich REPL
pip install csdl-explore[tui] # + Textual TUI (tree nav, split panes, query builder)csdl-explore metadata.xml # Interactive REPL
csdl-explore metadata.xml --tui # Full TUI
csdl-explore metadata.xml search contract # Search fields
csdl-explore metadata.xml entity EmpJob # Entity details
csdl-explore metadata.xml tree EmpJob # Visual tree- Rich REPL โ colored tables, visual trees, entity comparison
- Textual TUI โ tree navigation, tabbed views, split panes, navigation graph
- Live OData queries โ visual query builder with filter, select, expand, orderby
- SAP SuccessFactors auth โ Bearer, Basic, OAuth2 SAML
- Picklist exploration โ usage analysis, impact analysis, live value fetching
- Headless mode โ all commands work non-interactively for scripts and AI assistants
- Search โ across entity names, property names, labels, and picklist values
- Themes โ Terminal green + amber accent (default), Classic
$ csdl-explore metadata.xml
โญโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโฎ
โ CSDL Explorer โ
โ Loaded 735 entities โ
โฐโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโฏ
csdl> search contract
โโโโโโโโโโณโโโโโโโโโโโโณโโโโโโโโโโโโโโโโโโณโโโโโโโโโโ
โ Type โ Entity โ Match โ Details โ
โฃโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโซ
โ PROP โ EmpJob โ .contractType โ String โ
โ NAV โ EmpJob โ .contractTypeNavโ โ
โโโโโโโโโโปโโโโโโโโโโโโปโโโโโโโโโโโโโโโโโโปโโโโโโโโโโ
csdl> tree EmpJob
EmpJob
โโโ Keys
โ โโโ seqNumber Edm.Int64
โ โโโ startDate Edm.DateTime
โ โโโ userId Edm.String
โโโ Properties (45)
โ โโโ businessUnit Edm.String
โ โโโ ... and 43 more
โโโ Custom Fields (24)
โ โโโ customString7 Edm.String
โ โโโ ... and 23 more
โโโ Navigation (8)
โโโ employmentNav -> EmpEmployment
โโโ ... and 7 more
| Command | Aliases | Description |
|---|---|---|
entities |
List all entity types | |
entity <name> |
e |
Show all properties of an entity |
tree <name> |
t |
Show entity as visual tree |
search <term> |
s |
Search entities and properties |
custom <entity> |
c |
Show custom fields |
nav <entity> |
Show navigation properties | |
diff <e1> <e2> |
Compare two entities | |
path <entity> |
paths |
Suggest JSON paths |
emp / per |
List Emp*/Per* entities (SAP SF) | |
picklists |
List all picklists (JSON) | |
picklist <name> |
pk |
Fetch picklist values from live API |
batch-picklists <entity> |
Fetch all picklist values for an entity | |
query <entity> |
Execute OData query | |
model [entities] |
Show data model overview |
csdl-explore metadata.xml query EmpJob \
--select "userId,company,businessUnit" \
--filter "company eq 'ACME'" \
--top 10Query flags: --select, --filter, --orderby, --orderby-dir, --top, --expand, --asof-date, --from-date, --to-date
| Option | Description |
|---|---|
--tui |
Launch full Textual TUI |
--base-url <url> |
OData service base URL |
--auth-type <type> |
none, bearer, basic, oauth2 |
--format <fmt> |
table, json, json-compact, csv |
--wide |
Full column widths |
--filter <pattern> |
Filter properties by name glob |
--json-only |
JSON output only (for scripts) |
CSDL Explorer can query live OData services โ not just parse static metadata. You need a base URL and credentials.
| Type | Description |
|---|---|
none |
No authentication |
bearer |
Static Bearer token in the Authorization header |
basic |
HTTP Basic Auth (username + password) |
oauth2 |
SAP SAML Bearer assertion flow (IDP โ token exchange) |
Pass connection flags directly:
# Bearer token
csdl-explore metadata.xml --base-url https://api.example.com/odata/v2 \
--auth-type bearer --bearer-token YOUR_TOKEN \
query EmpJob --top 5
# Basic auth
csdl-explore metadata.xml --base-url https://api.example.com/odata/v2 \
--auth-type basic --username admin --password secret \
picklist ecJobCodePlace a .env file next to your metadata XML with the same stem name. If your metadata is metadata.xml, create metadata.env:
SAP_BASE_URL=https://api.example.com/odata/v2
SAP_AUTH_TYPE=bearer
SAP_BEARER_TOKEN=your-token-hereThen just run commands โ credentials are loaded automatically:
csdl-explore metadata.xml query EmpJob --top 5
csdl-explore metadata.xml picklist ecJobCodeCLI flags override .env values when both are present.
All .env keys:
| Key | Description |
|---|---|
SAP_BASE_URL |
OData service base URL |
SAP_AUTH_TYPE |
none, bearer, basic, oauth2 |
SAP_BEARER_TOKEN |
Bearer token |
SAP_USERNAME |
Basic auth username |
SAP_PASSWORD |
Basic auth password |
SAP_IDP_URL |
OAuth2: SAML IDP endpoint |
SAP_TOKEN_URL |
OAuth2: Token exchange endpoint |
SAP_CLIENT_ID |
OAuth2: Client ID |
SAP_USER_ID |
OAuth2: User ID for assertion |
SAP_COMPANY_ID |
OAuth2: Company ID |
SAP_PRIVATE_KEY |
OAuth2: Private key for signing |
SAP_GRANT_TYPE |
OAuth2: Grant type |
In the Textual TUI, credentials are configured through the auth modal (accessible from the Query tab). The TUI also reads the .env file on startup, so if you've already configured it for the CLI, the TUI picks it up automatically.
pip install csdl-explore[tui]
csdl-explore metadata.xml --tui| Key | Action |
|---|---|
/ |
Focus search |
Escape |
Clear search |
t |
Toggle tree sidebar |
Ctrl+T |
Cycle theme |
Ctrl+W |
Close current tab |
? |
Help |
q |
Quit |
from csdl_explore import CSDLExplorer
from pathlib import Path
explorer = CSDLExplorer.from_file(Path("metadata.xml"))
# Search
for r in explorer.search("worker"):
print(f"{r.entity}.{r.property}: {r.prop_type}")
# Entity details
entity = explorer.get_entity("EmpJob")
for prop in entity.properties.values():
print(f"{prop.name}: {prop.type} (label={prop.label})")
# Custom fields, comparison, picklist usage
fields = explorer.get_custom_fields("EmpJob")
comp = explorer.compare_entities("EmpCompensation", "EmpPayCompRecurring")
usage = explorer.get_picklist_usage()Any OData service with CSDL $metadata. Tested with:
- SAP SuccessFactors (full annotation support: labels, picklists, CRUD flags)
- SAP S/4HANA OData
- Standard OData v2/v3 services
MIT
