A pipe-friendly CLI for exploring and querying XML files. Built with Node.js/TypeScript.
Binary name: xmlq
xmlq <command> [options] [file]
All commands accept a file path or read from stdin when no file is given. All output goes to stdout (machine-readable by default), errors/warnings to stderr.
Quick overview of an XML file — the first thing you run on an unfamiliar file.
xmlq stat data.xml
File: data.xml (2.1 MB)
Root: <catalog xmlns="urn:example:catalog">
Elements: 12,483
Max depth: 6
Namespaces: urn:example:catalog, urn:example:meta
Top-level: <product> x 1200, <category> x 45, <metadata> x 1
| Flag | Description |
|---|---|
--json |
Output as JSON (for piping) |
List all unique element names with occurrence counts. Essential for understanding what a file contains.
xmlq tags data.xml
1200 product
1200 price
1200 name
1200 sku
45 category
45 description
1 catalog
1 metadata
| Flag | Description |
|---|---|
--sort name |
Sort alphabetically instead of by count (default: by count desc) |
--depth N |
Only count tags up to depth N |
--json |
Output as JSON |
Show the structural skeleton of the document — unique element hierarchy, not every node. Critical for understanding nesting without drowning in output.
xmlq tree data.xml
catalog
├── metadata
│ ├── created
│ └── version
├── category (x45)
│ ├── @id
│ ├── name
│ └── description
└── product (x1200)
├── @sku
├── @category-ref
├── name
├── price
│ ├── @currency
│ └── #text
└── tags
└── tag (x1..5)
Shows attributes as @attr, text content as #text (only when element has both children and text). Repetition counts shown in parentheses.
| Flag | Description |
|---|---|
--depth N |
Limit tree depth (default: unlimited) |
--no-attrs |
Hide attributes |
--no-counts |
Hide repetition counts |
Query nodes using XPath expressions. The core workhorse command.
xmlq select '//product[price > 100]' data.xml
Outputs matching XML fragments, one per match:
<product sku="A-001" category-ref="electronics">
<name>Widget Pro</name>
<price currency="USD">149.99</price>
<tags><tag>premium</tag><tag>new</tag></tags>
</product>| Flag | Description |
|---|---|
--first N |
Return only first N matches (crucial for large files) |
--count |
Just print the number of matches |
--text |
Extract text content only (one line per match) |
--attr NAME |
Extract a specific attribute value (one line per match) |
--compact |
Output XML without pretty-printing |
--json |
Convert matched nodes to JSON |
--wrap |
Wrap multiple results in a <results> root element |
Short aliases for common patterns:
# These are equivalent:
xmlq select '//product' --first 1 data.xml
xmlq first '//product' data.xml
# These are equivalent:
xmlq select '//product' --count data.xml
xmlq count '//product' data.xml
# These are equivalent:
xmlq select '//product/name' --text data.xml
xmlq text '//product/name' data.xmlShorthand: select first N matching nodes. The most used command when exploring — you almost never want all 1200 products dumped to your terminal.
xmlq first '//product' data.xml # first 1 match
xmlq first 5 '//product' data.xml # first 5 matches
Count matches for an XPath expression.
xmlq count '//product' data.xml
# 1200
xmlq count '//product[price > 100]' data.xml
# 342
Extract text content of matched nodes, one value per line.
xmlq text '//product/name' data.xml
Widget Pro
Widget Basic
Gadget X
...
| Flag | Description |
|---|---|
--first N |
Limit to first N |
--trim |
Trim whitespace (default: on) |
--no-trim |
Preserve original whitespace |
List attributes of matched elements. Useful for discovering the data model.
xmlq attrs '//product' data.xml
When used without XPath, discovers all attribute names across the entire document:
xmlq attrs data.xml
product/@sku 1200 unique values
product/@category-ref 45 unique values
price/@currency 3 unique values [USD, EUR, GBP]
category/@id 45 unique values
Small-cardinality attributes (<=10 unique values) show all distinct values inline.
| Flag | Description |
|---|---|
--values |
List all unique values per attribute |
Pretty-print / reformat XML.
xmlq fmt data.xml # pretty-print to stdout
xmlq fmt --indent 4 data.xml # custom indent
xmlq fmt --compact data.xml # minify
| Flag | Description |
|---|---|
--indent N |
Spaces per indent level (default: 2) |
--compact |
Minify — remove all insignificant whitespace |
--in-place |
Overwrite the file (instead of writing to stdout) |
Convert XML to JSON. Pipe to jq for further processing.
xmlq json data.xml | jq '.catalog.product[0]'
xmlq select '//product' --first 5 data.xml | xmlq json
| Flag | Description |
|---|---|
--compact |
Minify JSON output |
Check if the file is well-formed XML.
xmlq validate data.xml
# OK: well-formed XML
xmlq validate broken.xml
# ERROR: line 42, col 15: unexpected closing tag </item>
Exit code: 0 for valid, 1 for errors.
List namespaces used in the document.
xmlq ns data.xml
default urn:example:catalog
meta urn:example:meta
xsi http://www.w3.org/2001/XMLSchema-instance
Infer an XSD (XML Schema Definition) from the document — analyzes elements, attributes, text types, and occurrence patterns to produce a standard XSD that can be used by XML tools and validators.
xmlq schema data.xml
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="catalog">
<xs:complexType>
<xs:sequence>
<xs:element name="category" maxOccurs="unbounded">
<xs:complexType>
<xs:sequence>
<xs:element name="name" type="xs:string"/>
<xs:element name="description" type="xs:string"/>
</xs:sequence>
<xs:attribute name="id" type="xs:string" use="required"/>
</xs:complexType>
</xs:element>
<xs:element name="product" maxOccurs="unbounded">
<xs:complexType>
<xs:sequence>
<xs:element name="name" type="xs:string"/>
<xs:element name="price">
<xs:complexType>
<xs:simpleContent>
<xs:extension base="xs:decimal">
<xs:attribute name="currency" use="required">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:enumeration value="EUR"/>
<xs:enumeration value="GBP"/>
<xs:enumeration value="USD"/>
</xs:restriction>
</xs:simpleType>
</xs:attribute>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:element>
<xs:element name="tags" minOccurs="0">
<xs:complexType>
<xs:sequence>
<xs:element name="tag" type="xs:string" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
<xs:attribute name="sku" type="xs:string" use="required"/>
<xs:attribute name="category-ref" type="xs:string" use="required"/>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>| Flag | Description |
|---|---|
--json |
Output inferred schema as JSON |
Install the xmlq skill for Claude Code AI agent integration.
xmlq skill --install
Creates .claude/skills/xmlq/SKILL.md in the current directory. This file teaches Claude Code how to use xmlq commands — Claude discovers it automatically and can then use xmlq to explore XML files on the user's behalf.
| Flag | Description |
|---|---|
--install |
Deploy SKILL.md to .claude/skills/xmlq/ in current directory |
Prints "Installed" on first run, "Updated" if the file already existed.
xmlq can be used by AI coding agents like Claude Code. The skill --install command deploys a skill file that teaches the agent all available commands, flags, and pipe patterns.
Setup:
# 1. Install xmlq globally
npm install -g @pvasek/xmlq
# 2. In your project directory, install the skill
xmlq skill --installAfter this, Claude Code will automatically discover and use xmlq when working with XML files in the project.
These work with any command:
| Flag | Description |
|---|---|
--help, -h |
Show help |
--version, -v |
Show version |
--no-color |
Disable colored output |
--ns PREFIX=URI |
Register namespace prefix for XPath queries |
The CLI is designed for Unix pipelines:
# Find expensive products, convert to JSON, process with jq
xmlq select '//product[price > 100]' data.xml | xmlq json | jq '.[].name'
# Count products per category
xmlq text '//product/@category-ref' data.xml | sort | uniq -c | sort -rn
# Extract all SKUs to a file
xmlq text '//product/@sku' data.xml > skus.txt
# Pretty-print a fragment from a larger pipeline
curl -s https://api.example.com/feed.xml | xmlq first 3 '//item'
# Validate all XML files in a directory
find . -name '*.xml' -exec xmlq validate {} \;- Parser: DOM-based (e.g.
fast-xml-parser) for v1. Design command interfaces so a streaming/SAX backend can be swapped in later for large files. - XPath: Use
xpathorfontoxpathfor XPath 1.0/2.0 support. XPath is the standard XML query language — no need to invent a custom one. - Output: Colored + human-friendly when stdout is a TTY, plain text when piped.
--jsonflag always produces machine-readable output. - Packaging: Publish to npm (
npx @pvasek/xmlq), optionally bundle withpkgorbun build --compilefor a standalone binary.
The commands are designed around a typical discovery workflow:
stat → "what is this file?"
tree → "what's the structure?"
tags → "what elements exist?"
attrs → "what data fields are there?"
first → "show me an example record"
select → "query specific data"
text → "extract values"
json → "convert for further processing"