Introduction
mq is a command-line tool that processes Markdown using a syntax similar to jq. It’s written in Rust, allowing you to easily slice, filter, map, and transform structured data.
Why mq?
mq makes working with Markdown files as easy as jq makes working with JSON. It’s especially useful for:
- LLM Workflows: Efficiently manipulate and process Markdown used in LLM prompts and outputs
- Documentation Management: Extract, transform, and organize content across multiple documentation files
- Content Analysis: Quickly extract specific sections or patterns from Markdown documents
- Batch Processing: Apply consistent transformations across multiple Markdown files
Features
- Slice and Filter: Extract specific parts of your Markdown documents with ease.
- Map and Transform: Apply transformations to your Markdown content.
- Command-line Interface: Simple and intuitive CLI for quick operations.
- Extensibility: Easily extendable with custom functions.
- Built-in support: Filter and transform content with many built-in functions and selectors.
- REPL Support: Interactive command-line REPL for testing and experimenting.
- IDE Support: VSCode Extension and Language Server Protocol (LSP) support for custom function development.
Getting Started
Getting Started
This section guides you through the installation of mq.
Install
Quick Install
curl -sSL https://mqlang.org/install.sh | bash
# Install the debugger
curl -sSL https://mqlang.org/install.sh | bash -s -- --with-debug
The installer will:
- Download the latest mq binary for your platform
- Install it to
~/.mq/bin/ - Update your shell profile to add mq to your PATH
Cargo
# Install from crates.io
cargo install mq-run
# Install from Github
cargo install --git https://github.com/harehare/mq.git mq-run --tag v0.5.12
# Latest Development Version
cargo install --git https://github.com/harehare/mq.git mq-run --bin mq
# Install the debugger
cargo install --git https://github.com/harehare/mq.git mq-run --bin mq-dbg --features="debugger"
# Install using binstall
cargo binstall [email protected]
Binaries
You can download pre-built binaries from the GitHub releases page:
# macOS (Apple Silicon)
curl -L https://github.com/harehare/mq/releases/download/v0.5.12/mq-aarch64-apple-darwin -o /usr/local/bin/mq && chmod +x /usr/local/bin/mq
# Linux x86_64
curl -L https://github.com/harehare/mq/releases/download/v0.5.12/mq-x86_64-unknown-linux-gnu -o /usr/local/bin/mq && chmod +x /usr/local/bin/mq
# Linux arm64
curl -L https://github.com/harehare/mq/releases/download/v0.5.12/mq-aarch64-unknown-linux-gnu -o /usr/local/bin/mq && chmod +x /usr/local/bin/mq
# Windows (PowerShell)
Invoke-WebRequest -Uri https://github.com/harehare/mq/releases/download/v0.5.12/mq-x86_64-pc-windows-msvc.exe -OutFile "$env:USERPROFILE\bin\mq.exe"
Homebrew
# Using Homebrew (macOS and Linux)
$ brew install harehare/tap/mq
Docker
$ docker run --rm ghcr.io/harehare/mq:0.5.12
mq-lsp (Language Server)
The mq Language Server provides IDE features like completion, hover, and diagnostics for mq query files.
Quick Install
curl -sSL https://mqlang.org/install_lsp.sh | bash
Cargo
# Install from crates.io
cargo install mq-lsp
# Install from Github
cargo install --git https://github.com/harehare/mq.git mq-lsp --tag v0.5.12
# Latest Development Version
cargo install --git https://github.com/harehare/mq.git mq-lsp
# Install using binstall
cargo binstall [email protected]
Binaries
You can download pre-built binaries from the GitHub releases page:
# macOS (Apple Silicon)
curl -L https://github.com/harehare/mq/releases/download/v0.5.12/mq-lsp-aarch64-apple-darwin -o /usr/local/bin/mq-lsp && chmod +x /usr/local/bin/mq-lsp
# Linux x86_64
curl -L https://github.com/harehare/mq/releases/download/v0.5.12/mq-lsp-x86_64-unknown-linux-gnu -o /usr/local/bin/mq-lsp && chmod +x /usr/local/bin/mq-lsp
# Linux arm64
curl -L https://github.com/harehare/mq/releases/download/v0.5.12/mq-lsp-aarch64-unknown-linux-gnu -o /usr/local/bin/mq-lsp && chmod +x /usr/local/bin/mq-lsp
# Windows (PowerShell)
Invoke-WebRequest -Uri https://github.com/harehare/mq/releases/download/v0.5.12/mq-lsp-x86_64-pc-windows-msvc.exe -OutFile "$env:USERPROFILE\bin\mq-lsp.exe"
Visual Studio Code Extension
You can install the VSCode extension from the Visual Studio Marketplace.
Neovim
You can install the Neovim plugin by following the instructions in the mq.nvim README.
GitHub Actions
You can use mq in your GitHub Actions workflows with the Setup mq action:
steps:
- uses: actions/checkout@v4
- uses: harehare/setup-mq@v1
- run: mq '.code' README.md
MCP (Model Context Protocol) server
mq supports an MCP server for integration with LLM applications.
See the MCP documentation for more information.
Python
You can use mq in Python through the markdown-query package:
# Install from PyPI
$ pip install markdown-query
npm
You can use mq in npm through the mq-web package:
$ npm i mq-web
Web crawler
# Using Homebrew (macOS and Linux)
$ brew install harehare/tap/mqcr
Development
Prerequisites
Setting up the development environment
Clone the repository:
git clone https://github.com/harehare/mq.git
cd mq
Install development dependencies:
# Using cargo
cargo install just wasm-pack
Or if you prefer using asdf:
# Using asdf
asdf install
Common development tasks
Here are some useful commands to help you during development:
# Run the CLI with the provided arguments
just run '.code'
# Run formatting, linting and all tests
just test
# Run formatter and linter
just lint
# Build the project in release mode
just build
# Update documentation
just docs
Check the just --list for more available commands and build options.
Syntax Highlighting
Using bat
bat is a cat clone with syntax highlighting and Git integration. You can use mq’s Sublime syntax file to enable syntax highlighting for mq files in bat.
Setting up mq syntax highlighting
- Create the bat syntax directory if it doesn’t exist:
mkdir -p "$(bat --config-dir)/syntaxes"
- Copy the mq syntax file:
# Clone the mq repository or download mq.sublime-syntax
curl -o "$(bat --config-dir)/syntaxes/mq.sublime-syntax" \
https://raw.githubusercontent.com/harehare/mq/main/assets/mq.sublime-syntax
- Rebuild bat’s cache:
bat cache --build
Usage
Now you can use bat to display mq files with syntax highlighting:
# View an mq file with syntax highlighting
bat query.mq
Example
Create a sample mq file:
cat > example.mq << 'EOF'
# This is a comment
def greet(name):
s"Hello, ${name}!"
end
.h | .text | greet("World")
EOF
View it with syntax highlighting:
bat example.mq
Editor Support
In addition to bat, mq syntax highlighting is available for:
- Visual Studio Code: Install the mq extension
Playground
An Online Playground is available, powered by WebAssembly.
Interactive TUI
The Text-based User Interface (TUI) provides an interactive way to explore and query Markdown files directly in your terminal.
Quick Install
curl -fsSL https://raw.githubusercontent.com/harehare/mq-tui/main/bin/install.sh | bash
$ mq tui file.md
TUI Features
- Interactive Querying: Enter and edit queries in real-time with immediate feedback
- Detail View: Examine the structure of selected markdown nodes in depth
- Navigation: Browse through query results with keyboard shortcuts
- Query History: Access and reuse previous queries
TUI Key Bindings
| Key | Action |
|---|---|
: (colon) | Enter query mode |
Enter | Execute query |
Esc / q | Exit query mode / Exit app |
↑/k, ↓/j | Navigate results |
d | Toggle detail view |
? / F1 | Show help screen |
Ctrl+l | Clear query |
PgUp/PgDn | Page through results |
Home/End | Jump to first/last result |
Repository
The source code and further documentation for mqt are available on GitHub:
https://github.com/harehare/mqt
Web crawler
mq-crawler is a web crawler that fetches HTML content from websites, converts it to Markdown format, and processes it with mq queries. It’s distributed as the mqcr binary.
Key Features
- HTML to Markdown conversion: Automatically converts crawled HTML pages to clean Markdown
- robots.txt compliance: Respects robots.txt rules for ethical web crawling
- mq-lang integration: Processes content with mq-lang queries for filtering and transformation
- Configurable crawling: Customizable delays, domain restrictions, and link discovery
- Flexible output: Save to files or output to stdout
Installation
# Using Homebrew (macOS and Linux)
$ brew install harehare/tap/mqcr
Usage
mqcr [OPTIONS] <URL>
Options
-o, --output <OUTPUT>: Directory to save markdown files (stdout if not specified)-c, --crawl-delay <CRAWL_DELAY>: Delay between requests in seconds (default: 1)--robots-path <ROBOTS_PATH>: Custom robots.txt URL-m, --mq-query <MQ_QUERY>: mq-lang query for processing content (default:identity())
Examples
# Basic crawling to stdout
mqcr https://example.com
# Save to directory with custom delay
mqcr -o ./output -c 2 https://example.com
# Process with mq-lang query
mqcr -m '.h | select(contains("News"))' https://example.com
MCP
The mq MCP server enables integration with AI applications that support the Model Context Protocol (MCP). This server provides tools for processing Markdown content using mq queries.
Overview
The MCP server exposes four main tools:
html_to_markdown- Converts HTML to Markdown and applies mq queriesextract_markdown- Extracts content from Markdown using mq queriesavailable_functions- Lists available mq functionsavailable_selectors- Lists available mq selectors
Configuration
Claude Desktop
Add the following to your Claude Desktop configuration file:
{
"mcpServers": {
"mq": {
"command": "/path/to/mq",
"args": ["mcp"]
}
}
}
Claude Code
$ claude mcp add mq-mcp -- mq mcp
VS Code
Add the following to your VS Code settings:
{
"mcp": {
"servers": {
"mq-mcp": {
"type": "stdio",
"command": "/path/to/mq",
"args": ["mcp"]
}
}
}
}
Replace /path/to/mq with the actual path to your mq binary.
Usage
Converting HTML to Markdown
The html_to_markdown tool converts HTML content to Markdown format and applies an optional mq query:
html_to_markdown({
"html": "<h1>Title</h1><p>Content</p>",
"query": ".h1"
})
Extracting from Markdown
The extract_markdown tool processes Markdown content with mq queries:
extract_markdown({
"markdown": "# Title\n\nContent",
"query": ".h1"
})
Getting Available Functions
The available_functions tool returns all available mq functions:
available_functions()
Returns JSON with function names, descriptions, parameters, and examples.
Getting Available Selectors
The available_selectors tool returns all available mq selectors:
available_selectors()
Returns JSON with selector names, descriptions, and parameters.
Query Examples
Common mq queries you can use with the MCP tools:
.h1- Select all h1 headingsselect(.code.lang == "js")- Select JavaScript code blocks.text- Extract all text contentselect(.h1, .h2)- Select h1 and h2 headingsselect(not(.code))- Select everything except code blocks
Debugger
The mq debugger allows you to step through execution, set breakpoints, and inspect the state of your mq programs during runtime. This is particularly useful for debugging complex queries and understanding how data flows through your transformations.
Installation
To use the debugger, you need to install mq with the debugger feature enabled.
Quick Install
curl -sSL https://mqlang.org/install.sh | bash -s -- --with-debug
Cargo
You can do this by building from source:
cargo install --git https://github.com/harehare/mq.git mq-run --bin mq-dbg
Alternatively, if a prebuilt binary is available for your platform, download it from the releases page and ensure it is in your PATH.
Homebrew
If you use Homebrew, you can install the debugger-enabled mq with:
brew install harehare/tap/mq-dbg
Getting Started
The debugger is available through the mq-dbg binary when the debugger feature is enabled.
# Enable debugging for an mq script
mq-dbg -f your-script.mq input.md
Debugger Interface
Once the debugger starts, you’ll see a prompt (mqdbg) where you can enter debugging commands. The debugger will automatically display the current source code location with line numbers, highlighting the current execution point.
10| def process_headers() {
=> 11| . | select(.type == "heading")
12| | map(.level)
13| }
(mqdbg)
Available Commands
The debugger supports the following commands:
Navigation Commands
| Command | Alias | Description |
|---|---|---|
step | s | Step into the next expression, diving into function calls |
next | n | Step over the current expression, skipping over function calls |
finish | f | Run until the current function returns |
continue | c | Continue normal execution until the next breakpoint |
Breakpoint Commands
| Command | Alias | Description |
|---|---|---|
breakpoint [line] | b [line] | Set a breakpoint at the specified line number |
breakpoint | b | List all active breakpoints |
clear [id] | cl [id] | Clear a specific breakpoint by ID |
clear | cl | Clear all breakpoints |
Inspection Commands
| Command | Alias | Description |
|---|---|---|
info | i | Display current environment variables and context |
list | l | Show source code around the current execution point |
long-list | ll | Show the entire source code with line numbers |
backtrace | bt | Print the current call stack |
Control Commands
| Command | Alias | Description |
|---|---|---|
help | - | Display help information for all commands |
quit | q | Quit the debugger and exit |
Setting Breakpoints
You can set breakpoints in several ways:
Interactive Breakpoints
You can set breakpoints interactively from the debugger prompt:
(mqdbg) breakpoint 15
(mqdbg) breakpoint
Breakpoints:
[1] 15:10 (enabled)
Programmatic Breakpoints
You can also set breakpoints directly in your mq code using the breakpoint() function:
def process_data(items) {
breakpoint() # Execution will pause here when debugger is attached
| items | filter(fn(item): item == "test")
}
When the debugger encounters a breakpoint() function call during execution, it will automatically pause and enter interactive debugging mode.
Note: The breakpoint() function only has an effect when running under the debugger (mq-dbg). In normal execution (mq), it is ignored and has no impact on performance.
Example
This page demonstrates practical examples of mq queries for common Markdown processing tasks. Each example includes the query, explanation, and typical use cases.
Basic Element Selection
Select All Headings
Extract all headings from a markdown document:
.h
Input example:
# Main Title
## Section 1
### Subsection 1.1
## Section 2
Output: Returns all heading elements with their levels and text.
Extract Specific Table Row
Extract the second row from a markdown table:
.[1][]
Input example:
| Name | Age | City |
| ----- | --- | ---- |
| Alice | 30 | NYC |
| Bob | 25 | LA |
Output: Returns ["Bob", "25", "LA"]
Extract Specific List
Extract the second list from the document:
.[1]
Code Block Operations
Exclude Code Blocks
Filter out all code blocks from a document, keeping only prose content:
select(!.code)
Input example:
This is a paragraph.
```js
console.log("code");
Another paragraph.
**Output**: Returns only the paragraph elements, excluding the code block.
### Extract JavaScript Code Blocks
Select only code blocks with a specific language:
```js
select(.code.lang == "js")
Input example:
````js
const x = 1;
x = 1
const y = 2;
**Output**: Returns only the two JavaScript code blocks.
### Extract Language Names
Get a list of all programming languages used in code blocks:
```js
.code.lang
Example output: ["js", "python", "rust", "bash"]
Link and MDX Operations
Extract MDX Components
Select all MDX components (JSX-like elements in Markdown):
select(is_mdx())
Input example:
Regular paragraph.
<CustomComponent prop="value" />
Another paragraph.
<AnotherComponent>
Content
</AnotherComponent>
Output: Returns only the MDX component elements.
Extract URLs from Links
Get all URLs from markdown links:
.link.url
Input example:
Check out [mq](https://mqlang.org) and [GitHub](https://github.com).
Example output: ["https://mqlang.org", "https://github.com"]
Advanced Markdown Processing
Generate Table of Contents
Create a hierarchical table of contents from headings:
.h
| let link = to_link("#" + to_text(self), to_text(self), "")
| let level = .h.depth
| if (!is_none(level)): to_md_list(link, level - 1)
Input example:
# Introduction
## Getting Started
### Installation
## Usage
Output:
- [Introduction](#introduction)
- [Getting Started](#getting-started)
- [Installation](#installation)
- [Usage](#usage)
Generate XML Sitemap
Create an XML sitemap from markdown files:
def sitemap(item, base_url):
let path = replace(to_text(item), ".md", ".html")
| let loc = base_url + path
| s"<url>
<loc>${loc}</loc>
<priority>1.0</priority>
</url>"
end
Usage example:
$ mq 'sitemap(__FILE__, "https://example.com")' docs/**/*.md
Example output:
<url>
<loc>https://example.com/docs/intro.html</loc>
<priority>1.0</priority>
</url>
Custom Functions and Programming
Define Custom Function
Create reusable functions for complex transformations:
def snake_to_camel(x):
let words = split(x, "_")
| foreach (word, words):
let first_char = upcase(first(word))
| let rest_str = downcase(slice(word, 1, len(word)))
| s"${first_char}${rest_str}";
| join("")
end
| snake_to_camel("hello_world")
Example input: "user_name"
Example output: "UserName"
Map Over Arrays
Transform each element in an array:
map([1, 2, 3, 4, 5], fn(x): x + 1;)
Example output: [2, 3, 4, 5, 6]
Filter Arrays
Select elements that meet a condition:
filter([5, 15, 8, 20, 3], fn(x): x > 10;)
Example output: [15, 20]
Fold Arrays
Combine array elements into a single value:
fold([1, 2, 3, 4], 0, fn(acc, x): acc + x;)
Example output: 10
File Processing
CSV to Markdown Table
Convert CSV data to a formatted markdown table:
$ mq 'include "csv" | csv_parse(true) | csv_to_markdown_table()' example.csv
Use case: Convert spreadsheet data to markdown format for documentation. The csv_parse(true) treats the first row as headers.
Input example (example.csv):
Name,Age,City
Alice,30,NYC
Bob,25,LA
Example output:
| Name | Age | City |
| ----- | --- | ---- |
| Alice | 30 | NYC |
| Bob | 25 | LA |
Merge Multiple Files
Combine multiple markdown files with file path separators:
$ mq -S 's"\n${__FILE__}\n"' 'identity()' docs/books/**/**.md
The -S flag adds a separator between files, and __FILE__ is a special variable containing the current file path.
Example output:
docs/intro.md
# Introduction
...
docs/usage.md
# Usage
...
Process Files in Parallel
Process large numbers of files efficiently:
$ mq -P 5 '.h1' docs/**/*.md
LLM Workflows
Extract Context for LLM Prompts
Extract specific sections to create focused context for LLM inputs:
select(.h || .code) | self[:10]
Example: Extract first 10 sections with headings or code for a code review prompt.
Document Statistics
$ mq -A 'let headers = count_by(fn(x): x | select(.h);)
| let paragraphs = count_by(fn(x): x | select(.text);)
| let code_blocks = count_by(fn(x): x | select(.code);)
| let links = count_by(fn(x): x | select(.link);)
| s"Headers: ${headers}, Paragraphs: ${paragraphs}, Code: ${code_blocks}, Links: ${links}"'' docs/books/**/**.md
Generate Documentation Index
.h
| let level = .h.level
| let text = to_text(self)
| let indent = repeat(" ", level - 1)
| let anchor = downcase(replace(text, " ", "-"))
| if (!is_empty(text)): s"${indent}- [${text}](#${anchor})"
Reference
Reference
This is a reference documentation for the mq.
CLI
The mq command-line interface provides tools for querying and manipulating markdown content. Below is the complete reference for all available commands and options.
Usage: mq [OPTIONS] [QUERY OR FILE] [FILES]... [COMMAND]
Commands:
repl Start a REPL session for interactive query execution
fmt Format mq files based on specified formatting options
docs Show functions documentation for the query
check Check syntax errors in mq files
help Print this message or the help of the given subcommand(s)
Arguments:
[QUERY OR FILE]
[FILES]...
Options:
-A, --aggregate
Aggregate all input files/content into a single array
-f, --from-file
load filter from the file
-I, --input-format <INPUT_FORMAT>
Set input format [possible values: markdown, mdx, html, text, null, raw]
-L, --directory <MODULE_DIRECTORIES>
Search modules from the directory
-M, --module-names <MODULE_NAMES>
Load additional modules from specified files
--args <NAME> <VALUE>
Sets string that can be referenced at runtime
--rawfile <NAME> <FILE>
Sets file contents that can be referenced at runtime
--stream
Enable streaming mode for processing large files line by line
--json
--csv
Include the built-in CSV module
--fuzzy
Include the built-in Fuzzy module
--yaml
Include the built-in YAML module
--toml
Include the built-in TOML module
--xml
Include the built-in XML module
--test
Include the built-in test module
-F, --output-format <OUTPUT_FORMAT>
Set output format [default: markdown] [possible values: markdown, html, text, json, none]
-U, --update
Update the input markdown (aliases: -i, --in-place, --inplace)
--unbuffered
Unbuffered output
--list-style <LIST_STYLE>
Set the list style for markdown output [default: dash] [possible values: dash, plus, star]
--link-title-style <LINK_TITLE_STYLE>
Set the link title surround style for markdown output [default: double] [possible values: double, single, paren]
--link-url-style <LINK_URL_STYLE>
Set the link URL surround style for markdown links [default: none] [possible values: none, angle]
-S, --separator <QUERY>
Specify a query to insert between files as a separator
-o, --output <FILE>
Output to the specified file
--list
List all available subcommands (built-in and external)
-P <PARALLEL_THRESHOLD>
Number of files to process before switching to parallel processing [default: 10]
-h, --help
Print help
-V, --version
Print version
# Examples:
## To filter markdown nodes:
mq 'query' file.md
## To read query from file:
mq -f 'file' file.md
## To start a REPL session:
mq repl
## To format mq file:
mq fmt --check file.mq
Types and Values
Values
42(a number)"Hello, world!"(a string):value(a symbol)[1, 2, 3],array(1, 2, 3)(an array){"a": 1, "b": 2, "c": 3},dict(["a", 1], ["b", 2], ["c", 3])(a dictionary)true,false(a boolean)None
Types
| Type | Description | Examples |
|---|---|---|
| Number | Represents numeric values. | 1, 3.14, -42 |
| String | Represents sequences of characters, including Unicode code points and escape sequences in the form of \{0x000}. | "hello", "123", "😊", "\u{1F600}" |
| Symbol | Represents immutable, interned identifiers prefixed with :. Used for constant values and keys. | :value, :success, :error, :ok |
| Boolean | Represents truth values. | true, false |
| Array | Represents ordered collections of values. | [1, 2, 3], array(1, 2, 3) |
| Dict | Represents key-value mappings (dictionaries). | {"a": 1, "b": 2}, dict(["a", 1], ["b", 2]) |
| Function | Represents executable code. | def foo(): 42; let name = def foo(): 42; |
Accessing Values
Array Index Access
Arrays can be accessed using square bracket notation with zero-based indexing:
let arr = [1, 2, 3, 4, 5]
arr[0] # Returns 1 (first element)
arr[2] # Returns 3 (third element)
arr[6] # Returns None
You can also use the get function explicitly:
get(arr, 0) # Same as arr[0]
arr | get(2) # Same as arr[2]
Array Slice Access
Arrays support slice notation to extract subarrays using the arr[start:end] syntax:
let arr = [1, 2, 3, 4, 5]
arr[1:4] # Returns [2, 3, 4] (elements from index 1 to 3)
arr[0:3] # Returns [1, 2, 3] (first three elements)
arr[2:5] # Returns [3, 4, 5] (elements from index 2 to end)
Slice indices work as follows:
start: The starting index (inclusive)end: The ending index (exclusive)- Both indices are zero-based
- If
startorendis out of bounds, it will be clamped to valid range
let arr = [1, 2, 3, 4, 5]
arr[0:2] # Returns [1, 2]
arr[3:10] # Returns [4, 5] (end index clamped to array length)
arr[2:2] # Returns [] (empty slice when start equals end)
Dictionary Key Access
Dictionaries can be accessed using square bracket notation with keys:
let d = {"name": "Alice", "age": 30, "city": "Tokyo"}
d["name"] # Returns "Alice"
d["age"] # Returns 30
d["city"] # Returns "Tokyo"
You can also use the get function explicitly:
get(d, "name") # Same as di["name"]
d | get("age") # Same as d["age"]
Dynamic Access
Both arrays and dictionaries support dynamic access using variables:
let arr = [10, 20, 30]
| let index = 1
| arr[index] # Returns 20
let d = {"x": 100, "y": 200}
| let key = "x"
| d[key] # Returns 100
Environment Variables
A module handling environment-specific functionality.
__FILE__: Contains the path to the file currently being processed.
Conditionals and Comparisons
Conditionals and Comparisons
Conditional expressions and comparison operators in mq allow for decision-making based on the evaluation of conditions, enabling dynamic behavior in your queries.
Conditionals
mq supports standard conditional operations through the following functions:
and(a, b),a && b- Returns true if bothaandbare trueor(a, b), a || b- Returns true if eitheraorbis truenot(a), !a- Returns true ifais false
Examples
# Basic comparisons
and(true, true, true)
true && true && true
# => true
or(true, false, true)
true || false || true
# => true
not(false)
!false
# => true
Comparisons
mq provides comparison functionality through built-in functions.
Basic Comparisons
Standard comparison operators are supported:
eq(a, b), a == b- Returns true ifaequalsbne(a, b), a != b- Returns true ifadoes not equalbgt(a, b), a > b- Returns true ifais greater thanbgte(a, b), a >= b- Returns true ifais greater than or equal toblt(a, b), a < b- Returns true ifais less thanblte(a, b), a <= b- Returns true ifais less than or equal tob
Examples
# Basic comparisons
1 == 1
# => true
2 > 1
# => true
"a" <= "b"
# => true
# String comparisons
"hello" == "hello"
# => true
"xyz" > "abc"
# => true
# Numeric comparisons
5.5 >= 5.0
# => true
-1 < 0
# => true
# Logical operations
and(true, false)
# => false
or(true, false)
# => true
not(false)
# => true
# Complex conditions
and(x > 0, x < 10)
# => true if 0 < x < 10
try-catch
The try-catch expression allows you to handle errors gracefully by providing a fallback value when an expression fails.
Syntax
try <expr> catch <expr>
Behavior
- If the
tryexpression succeeds, its result is returned - If the
tryexpression fails (produces an error), thecatchexpression is evaluated instead - The
catchexpression receives the same input as thetryexpression
Examples
Basic Error Handling
# When the expression succeeds
try: "value" catch: "unknown"
# When the expression fails
try: get("missing") catch: "default"
Chaining with Pipe
# Try to parse as JSON, fallback to raw string
try: from_json() catch: self
# Complex fallback logic
try: do get("data") | from_json(); catch: []
Nested Try-Catch
# Multiple fallback levels
try: get("primary") catch: try: get("secondary") catch: "default"
Error Suppression (?)
The error suppression operator ? provides a concise way to handle errors by returning None when an expression fails, instead of raising an error. This is equivalent to using a regular try-catch with a default fallback.
Examples
# Equivalent to a regular try-catch with a default value
get("missing")?
In this example, if get("missing") fails, the result will be None rather than an error.
Syntax
Syntax
This section outlines the syntax rules in mq, providing a clear reference for writing valid code.
Comments
Similar to jq, comments starting with # are doc-comments.
# doc-comment
let value = add(2, 3);
Control flow
If Expression
The if expression evaluates a condition and executes code based on the result:
if (eq(x, 1)):
"one"
elif (eq(x, 2)):
"two"
else:
"other"
if (eq(x, 1)):
do "one" | upcase();
elif (eq(x, 2)):
do "TWO" | downcase();
else:
do
"other" | upcase()
end
if (eq(x, 1)):
"one"
The if expression can be nested and chained with elif and else clauses. The conditions must evaluate to boolean values.
While Expression
The while loop repeatedly executes code while a condition is true:
let x = 5 |
while (x > 0):
let x = x - 1 | x
end
# => 0
You can use break: <expr> to return a value from a while loop:
var x = 10 |
while (x > 0):
x = x - 1 |
if(eq(x, 3)):
break: "Found three!"
else:
x
end
# => "Found three!"
Foreach Expression
The foreach loop iterates over elements in an array:
let items = array(1, 2, 3) |
foreach (x, items):
sub(x, 1)
end
# => array(0, 1, 2)
You can use break: <expr> to exit early and return a specific value instead of an array:
let items = array(1, 2, 3, 4, 5) |
foreach (x, items):
if(x > 3):
break: "Found value greater than 3"
else:
x
end
# => "Found value greater than 3"
Foreach loops are useful for:
- Processing arrays element by element
- Mapping operations across collections
- Filtering and transforming data
Loop Expression
The loop expression creates an infinite loop that continues until explicitly terminated with break:
var x = 0 |
loop:
x = x + 1 |
if(x > 5):
break
else:
x
end
# => 5
The loop can be controlled using break to exit the loop and continue to skip to the next iteration:
var x = 0 |
loop:
x = x + 1 |
if(x < 3):
continue
elif(x > 5):
break
else:
x
end
# => 5
The break statement can return a value from a loop using the break: <expr> syntax. This allows loops to be used as expressions that produce a specific value when exited:
var x = 0 |
loop:
x = x + 1 |
if(x > 5):
break: "Found it!"
else:
x
end
# => "Found it!"
Loop expressions are useful for:
- Implementing infinite loops with conditional exits
- Creating retry mechanisms
- Processing until a specific condition is met
- Complex iteration patterns that don’t fit while or foreach
Pattern Matching
The match expression enables pattern matching on values, providing a powerful way to destructure and handle different data types.
Basic Syntax
match (value):
| pattern: body
end
The match expression evaluates the value and compares it against a series of patterns. The first matching pattern’s body is executed.
Literal Patterns
Match against specific values:
match (x):
| 1: "one"
| 2: "two"
| _: "other"
end
Literal patterns support:
- Numbers:
1,2.5,-10 - Strings:
"hello","world" - Booleans:
true,false - None:
none
Type Patterns
Match based on value type using the :type_name syntax:
match (value):
| :string: "is string"
| :number: "is number"
| :array: "is array"
| :dict: "is dict"
| :bool: "is boolean"
| :none: "is none"
| _: "other type"
end
Available type patterns:
:string- Matches string values:number- Matches numeric values:array- Matches array values:dict- Matches dictionary values:bool- Matches boolean values:markdown- Matches markdown values:none- Matches none value
Array Patterns
Destructure arrays and bind elements to variables:
match (arr):
| []: "empty array"
| [x]: x
| [x, y]: add(x, y)
| [first, second, third]: first
| [first, ..rest]: first
end
Array patter features:
- Match exact length:
[x, y]matches arrays with exactly 2 elements - Rest pattern:
..restcaptures remaining elements - Empty array:
[]matches empty arrays - Variable binding: Elements are bound to named variables
Rest Pattern Example
match (arr):
| [head, ..tail]: tail
end
# array(1, 2, 3, 4) => array(2, 3, 4)
Dict Patterns
Destructure dictionaries and extract values:
match (obj):
| {name, age}: name
| {x, y}: add(x, y)
| {}: "empty dict"
| _: "no match"
end
Dict pattern features:
- Extract specific keys:
{name, age}binds values to variables - Partial matching: Matches dicts that have at least the specified keys
- Empty dict:
{}matches empty dictionaries
Example with Object
let person = {"name": "Alice", "age": 30, "city": "Tokyo"} |
match (person):
| {name, age}: s"${name} is ${age} years old"
| {name}: name
| _: "unknown"
end
# => "Alice is 30 years old"
Variable Binding
Bind the matched value to a variable:
match (value):
| x: x + 1
end
Variable binding captures the entire value and makes it available in the body expression.
Wildcard Pattern
The underscore _ matches any value:
match (x):
| 1: "one"
| 2: "two"
| _: "something else"
end
Use the wildcard pattern as the last arm to handle all remaining cases.
Guards
Add conditions to patterns using if:
match (n):
| x if (x > 0): "positive"
| x if (x < 0): "negative"
| _: "zero"
end
Guards allow you to:
- Add complex conditions to patterns
- Filter matched values
- Combine pattern matching with boolean logic
Guard Examples
# Match even numbers
match (n):
| x if (x % 2 == 0): "even"
| _: "odd"
end
# Match array with positive numbers
match (arr):
| [x, ..] if (x > 0): "starts with positive"
| _: "other"
end
Multiple Arms
Combine multiple patterns for comprehensive matching:
match (value):
| 0: "zero"
| x if (x > 0): "positive"
| x if (x < 0): "negative"
| :string: "text"
| []: "empty array"
| [x, ..rest]: "non-empty array"
| {}: "empty dict"
| _: "something else"
end
Pattern Matching vs If Expressions
Pattern matching provides several advantages over if expressions:
Using If Expressions
if (type_of(x) == "number"):
if (x == 0):
"positive number"
elif (x < 0):
"negative number"
else:
"zero"
elif (type_of(x) == "array"):
if (len(x) == 0):
"empty array"
else:
"non-empty array"
else:
"other"
Using Pattern Matching
match (x):
| n if (n > 0): "positive number"
| n if (n < 0): "negative number"
| 0: "zero"
| []: "empty array"
| [_, ..rest]: "non-empty array"
| _: "other"
end
Practical Examples
Processing Different Data Types
def describe(value):
match (value):
| :none: "nothing"
| :bool: "true or false"
| x if (gt(x, 100)): "big number"
| :number: "small number"
| "": "empty string"
| :string: "text"
| []: "empty list"
| [x]: s"list with one item: ${x}"
| [_, ..rest]: "list with multiple items"
| {}: "empty object"
| _: "dictionary"
end
Extracting Data from Structures
def get_first_name(user):
match (user):
| {name}: name
| _: "unknown"
end
Handling API Responses
def handle_response(response):
match (response):
| {status, data} if (eq(status, 200)): data
| {status, error} if (eq(status, 404)): s"Not found: ${error}"
| {status, error} if (eq(status, 500)): s"Server error: ${error}"
| _: "Unknown response"
end
Operator
Pipe Operator
A functional operator that allows chaining multiple filter operations together.
Usage
The pipe operator (|) enables sequential processing of filters, where the output of one filter becomes the input of the next filter.
Examples
# Basic pipe usage
42 | add(1) | mul(2)
# => 86
# Multiple transformations
let mul2 = def mul2(x): mul(x, 2);
let gt4 = def gt4(x): gt(x, 4);
array(1, 2, 3) | map(mul2) | filter(gt4)
# => [6]
# Function composition
let double = def _double(x): mul(x, 2);
let add_one = def _add_one(x): add(x, 1);
5 | double(self) | add_one(self)
# => 11
.. Operator
The range operator (..) creates sequences of consecutive values between a start and end point.
Usage
The range operator generates arrays of values from a starting point to an ending point (inclusive). It works with both numeric values and characters.
Examples
# Numeric ranges
1..5
# => [1, 2, 3, 4, 5]
# Character ranges
'a'..'e'
# => ["a", "b", "c", "d", "e"]
# Using ranges with other operations
1..3 | map(fn(x): mul(x, 2);)
# => [2, 4, 6]
# Reverse ranges
5..1
# => [5, 4, 3, 2, 1]
# Single element range
3..3
# => [3]
Assignment Operators
Assignment operators are used to assign values to variables and combine assignment with arithmetic or logical operations.
Simple Assignment
The basic assignment operator (=) assigns a value to a variable.
Usage
let x = 10 |
let name = "mq" |
let items = [1, 2, 3]
Update Operator (|=)
The update operator (|=) applies an expression to a selected value and updates it in place.
Usage
<selector.value> |= expr
The left side specifies what to update using a selector, and the right side is the expression that transforms the value.
Examples
# Update a code block
.code.value |= "test" | to_text()
# => test
# Update a header level
.h.depth |= 3 | .h.depth
# => 3
Compound Assignment Operators
Compound assignment operators combine an arithmetic or logical operation with assignment, providing a shorthand for updating variables.
Addition Assignment (+=)
Adds a value to a variable and assigns the result back to the variable.
var x = 10 |
x += 5
# => x is now 15
var count = 0 |
count += 1
# => count is now 1
Subtraction Assignment (-=)
Subtracts a value from a variable and assigns the result back to the variable.
var x = 10 |
x -= 3
# => x is now 7
var balance = 100 |
balance -= 25
# => balance is now 75
Multiplication Assignment (*=)
Multiplies a variable by a value and assigns the result back to the variable.
var x = 5 |
x *= 3
# => x is now 15
var price = 100 |
price *= 1.1
# => price is now 110
Division Assignment (/=)
Divides a variable by a value and assigns the result back to the variable.
var x = 20 |
x /= 4
# => x is now 5
var total = 100 |
total /= 2
# => total is now 50
Modulo Assignment (%=)
Computes the remainder of dividing a variable by a value and assigns the result back to the variable.
var x = 17 |
x %= 5
# => x is now 2
var count = 23 |
count %= 10
# => count is now 3
Floor Division Assignment (//=)
Divides a variable by a value, floors the result (rounds down to the nearest integer), and assigns it back to the variable.
var x = 17 |
x //= 5
# => x is now 3
var count = 23 |
count //= 10
# => count is now 2
Def Expression
The def expression defines reusable functions with parameters:
Syntax
def function_name(parameters):
program;
Examples
# Function that doubles input
def double(x):
mul(x, 2);
# Function with conditional logic
def is_positive(x):
gt(x, 0);
# Composition of functions
def add_then_double(x, y):
add(x, y) | double(self);
Default Parameters
You can define default values for function parameters. Parameters with default values can be omitted when calling the function.
Syntax
def function_name(param1, param2=default_value):
program;
Examples
# Function with default parameter
def greet(name, greeting="Hello"):
greeting + " " + name;
# Using default value
greet("Alice")
# Output: "Hello Alice"
# Overriding default value
greet("Bob", "Hi")
# Output: "Hi Bob"
# Default value can be an expression
def add_with_offset(x, offset=10 + 5):
x + offset;
add_with_offset(20)
# Output: 35
Rules
- Parameters with default values must come after parameters without default values
- Default values are evaluated when the function is called, not when it’s defined
- Default values can be any valid expression
Environment variables
Environment variables can be referenced using $XXX syntax, where XXX represents the name of the environment variable. For example:
$PATH- References the PATH environment variable$HOME- References the HOME environment variable$USER- References the current user’s username
This syntax is commonly used in shell scripts and configuration files to access system-level environment variables.
Fn Expression
Anonymous functions (lambda expressions) allow you to define functions inline without naming them. These functions can be passed as arguments to other functions, assigned to variables, or used directly in expressions.
Syntax
fn(parameters): program;
Examples
# Basic Anonymous Function
nodes | map(fn(x): add(x, "1");)
# Using Anonymous Functions as Callbacks
nodes | .[] | sort_by(fn(x): to_text(x);)
Default Parameters
Anonymous functions also support default parameter values, just like named functions defined with def.
Syntax
fn(param1, param2=default_value): program;
Examples
# Anonymous function with default parameter
let multiply = fn(x, factor=2): x * factor;
# Using default value
multiply(10)
# Multiplies each value by 2 (default factor)
# Overriding default value
multiply(10, 3)
# Multiplies each value by 10
# Using in callbacks
[1, 2] | map(fn(x, prefix="Item: "): prefix + to_text(x);)
Rules
- Parameters with default values must come after parameters without default values
- Default values are evaluated when the function is called
- Default values can be any valid expression
Macros
Macros enable compile-time code generation and transformation in mq. They allow you to define reusable code templates that are expanded before evaluation.
Syntax
macro name(parameters): body
Macros are invoked like functions:
name(arguments)
How Macros Work
Macros differ from functions:
- Compile-time expansion: Macros are expanded before the program executes
- Code substitution: Macro parameters are directly substituted into the macro body
- No runtime overhead: Macro definitions are removed from the final program
Basic Examples
# Simple value transformation
macro double(x) do
x + x
end
| double(5) # Returns 10
# Multiple parameters
macro add_three(a, b, c) do
a + b + c
end
| add_three(1, 2, 3) # Returns 6
# With control flow
macro max(a, b) do
if(a > b): a else: b
end
| max(10, 5) # Returns 10
Advanced Examples
# Nested macro calls
macro double(x): x + x
macro quadruple(x): double(double(x))
| quadruple(3) # Returns 12
# Accepting functions as parameters
macro apply_twice(f, x) do
f(f(x))
end
def inc(n): n + 1;
| apply_twice(inc, 5) # Returns 7
Quote and Unquote
quote and unquote provide advanced metaprogramming capabilities:
quote(expr): Delays evaluation, treating content as code to be generatedunquote(expr): Evaluates the expression immediately and injects the result
Practical Examples
# Basic injection
macro make_expr(x) do
quote: unquote(x) + 1
end
| make_expr(5) # Returns 6
# Pre-computation
macro compute(a, b) do
quote: unquote(a) + unquote(b) * 2
end
| compute(10, 5) # Returns 20
# Conditional code generation
macro conditional_expr(x) do
quote do
if(unquote(x) > 10):
"large"
else:
"small"
end
end
| conditional_expr(15) # Returns "large"
# Complex pre-computation
macro compute_mixed(x) do
let a = x * 2 |
let b = x + 10 |
quote: unquote(a) + unquote(b)
end
| compute_mixed(5) # a=10, b=15, returns 25
# Generating data structures
macro make_array(a, b, c) do
quote: [unquote(a), unquote(b), unquote(c)]
end
| make_array(1, 2, 3) # Returns [1, 2, 3]
Modules and Imports
mq provides several ways to organize and reuse code: module, import, and include.
Module
Defines a module to group related functions and prevent naming conflicts using the syntax module name: ... end.
module module_name:
def function1(): ...
def function2(): ...
end
Functions within a module can be accessed using qualified access syntax:
module_name::function1()
Examples
# Define a math module
module math:
def add(a, b): a + b;
def sub(a, b): a - b;
def mul(a, b): a * b;
end
# Use functions from the module
| math::add(5, 3) # Returns 8
| math::mul(4, 2) # Returns 8
Import
Loads a module from an external file using the syntax import "module_path".
The imported module is available with its defined name and can be accessed using qualified access syntax.
The import directive searches for .mq files in the following locations:
$HOME/.mq- User’s home directory mq folder$ORIGIN/../lib/mq- Library directory relative to the source file$ORIGIN/../lib- Parent lib directory relative to the source file$ORIGIN- Current directory relative to the source file
import "module_name"
Examples
math.mq:
def add(a, b): a + b;
def sub(a, b): a - b;
main.mq:
# Import the math module
import "math"
# Use functions with qualified access
| math::add(10, 5) # Returns 15
| math::sub(10, 5) # Returns 5
Include
Loads functions from an external file directly into the current namespace using the syntax include "module_name".
Unlike import, functions are available without a namespace prefix.
The include directive searches for .mq files in the same locations as import.
include "module_name"
Examples
math.mq:
def add(a, b): a + b;
def sub(a, b): a - b;
main.mq:
# Include math functions
include "math"
# Functions are available directly
| add(2, 3) # Returns 5
| sub(10, 4) # Returns 6
Comparison
| Feature | module | import | include |
|---|---|---|---|
| Purpose | Define a module | Load external module | Load external functions |
| Access | Qualified access (module::func) | Qualified access (module::func) | Direct access (func) |
| Use case | Organize code within a file | Reuse modules across files | Simple function sharing |
Variable Declarations
Let
The let binds an immutable value to an identifier for later use:
# Binds 42 to x
let x = 42
# Uses x in an expression
| let y = x + 1
# Binds `add` function to z
| let z = do let z = fn(x): x + 1; | z(1);
Once a variable is declared with let, its value cannot be changed.
Var
The var declares a mutable variable that can be reassigned:
# Declares a mutable variable
var counter = 0
# Reassigns the value
counter = counter + 1
# counter is now 1
Variables declared with var can be modified using the assignment operator (=):
var total = 100
| total = total - 25
# total is now 75
var message = "Hello"
| message = message + " World"
# message is now "Hello World"
Choosing Between Let and Var
- Use
letwhen you want to create an immutable binding (most cases) - Use
varwhen you need to modify the value after declaration (counters, accumulators, etc.)
Self
The current value being processed can be referenced as self or . (dot). Both self and . behave identically. When there are insufficient arguments provided in a method call, the current value (self) is automatically passed as the first argument.
Examples
# These expressions are equivalent
"hello" | upcase()
"hello" | upcase(self)
"hello" | upcase(.)
String Interpolation
String Interpolation allow embedding expressions directly inside string literals. In mq, an interpolated string is prefixed with s" and variables can be embedded using ${} syntax.
Syntax
s"text ${ident} more text"
Escaping
You can escape the $ character in a string interpolation by using $$.
This allows you to include literal $ symbols in your interpolated strings.
let price = 25
| s"The price is $$${price}"
# => Output: "The price is $25"
Examples
let name = "Alice"
| let age = 30
| s"Hello, my name is ${name} and I am ${age} years old."
# => Output: "Hello, my name is Alice and I am 30 years old."
Nodes
The nodes in mq allows you to access and manipulate all Markdown nodes as a single flat array.
Basic Usage
The nodes filter returns an array of all nodes in a Markdown document:
nodes
Examples
Finding all headings
nodes | select(.h)
Converting all text to uppercase
nodes | map(upcase)
Counting nodes by type
nodes | len()
Builtin selectors and functions
Builtin selectors and functions
This page provides an introduction to the built-in selectors and functions available in mq. These are predefined components that you can use in your queries without having to define them yourself.
Builtin functions
| Function Name | Description | Parameters | Example |
|---|---|---|---|
abs | Returns the absolute value of the given number. | number | abs(number) |
add | Adds two values. | value1, value2 | add(value1, value2) |
all | Returns true if all element in the array satisfies the provided function. | v, f | all(v, f) |
all_symbols | Returns an array of all interned symbols. | all_symbols() | |
and | Performs a logical AND operation on two boolean values. | value1, value2 | and(value1, value2) |
any | Returns true if any element in the array satisfies the provided function. | v, f | any(v, f) |
array | Creates an array from the given values. | values | array(values) |
arrays | Returns array if input is array, None otherwise | a | arrays(a) |
assert | Asserts that two values are equal, returns the value if true, otherwise raises an error. | value1, value2 | assert(value1, value2) |
attr | Retrieves the value of the specified attribute from a markdown node. | markdown, attribute | attr(markdown, attribute) |
base64 | Encodes the given string to base64. | input | base64(input) |
base64d | Decodes the given base64 string. | input | base64d(input) |
between | Checks if a value is between min and max (inclusive). | value, min, max | between(value, min, max) |
booleans | Returns boolean if input is boolean, None otherwise | b | booleans(b) |
breakpoint | Sets a breakpoint for debugging; execution will pause at this point if a debugger is attached. | breakpoint() | |
ceil | Rounds the given number up to the nearest integer. | number | ceil(number) |
coalesce | Returns the first non-None value from the two provided arguments. | value1, value2 | coalesce(value1, value2) |
compact | Removes None values from the given array. | array | compact(array) |
compact_map | Maps over an array and removes None values from the result. | arr, f | compact_map(arr, f) |
contains | Checks if string contains a substring | haystack, needle | contains(haystack, needle) |
count_by | Returns the count of elements in the array that satisfy the provided function. | arr, f | count_by(arr, f) |
debug | Prints the debug information of the given value. | msg | debug(msg) |
decrease_header_level | Decreases the level of a markdown heading node by one, down to a minimum of 1. | heading_node | decrease_header_level(heading_node) |
del | Deletes the element at the specified index in the array or string. | array_or_string, index | del(array_or_string, index) |
dict | Creates a new, empty dict. | dict() | |
div | Divides the first value by the second value. | value1, value2 | div(value1, value2) |
downcase | Converts the given string to lowercase. | input | downcase(input) |
each | v, f | each(v, f) | |
ends_with | Checks if the given string ends with the specified substring. | string, substring | ends_with(string, substring) |
entries | Returns an array of key-value pairs from the dict as arrays. | dict | entries(dict) |
eq | Checks if two values are equal. | value1, value2 | eq(value1, value2) |
error | Raises a user-defined error with the specified message. | message | error(message) |
explode | Splits the given string into an array of characters. | string | explode(string) |
fill | Returns an array of length n filled with the given value. | value, n | fill(value, n) |
filter | Filters the elements of an array based on a provided callback function. | v, f | filter(v, f) |
find_index | Returns the index of the first element in an array that satisfies the provided function. | arr, f | find_index(arr, f) |
first | Returns the first element of an array | arr | first(arr) |
flat_map | Applies a function to each element and flattens the result into a single array | v, f | flat_map(v, f) |
flatten | Flattens a nested array into a single level array. | array | flatten(array) |
floor | Rounds the given number down to the nearest integer. | number | floor(number) |
fold | Reduces an array to a single value by applying a function, starting from an initial value. | arr, init, f | fold(arr, init, f) |
from_date | Converts a date string to a timestamp. | date_str | from_date(date_str) |
get | Retrieves a value from a dict by its key. Returns None if the key is not found. | obj, key | get(obj, key) |
get_or | Safely gets a value from a dict with a default if the key doesn’t exist. | dict, key, default | get_or(dict, key, default) |
get_title | Returns the title of a markdown node. | node | get_title(node) |
get_url | Returns the url of a markdown node. | node | get_url(node) |
get_variable | Retrieves the value of a symbol or variable from the current environment. | symbol_or_string | get_variable(symbol_or_string) |
group_by | Groups elements of an array by the result of applying a function to each element | arr, f | group_by(arr, f) |
gsub | Replaces all occurrences matching a regular expression pattern with the replacement string. | from, pattern, to | gsub(from, pattern, to) |
gt | Checks if the first value is greater than the second value. | value1, value2 | gt(value1, value2) |
gte | Checks if the first value is greater than or equal to the second value. | value1, value2 | gte(value1, value2) |
halt | Terminates the program with the given exit code. | exit_code | halt(exit_code) |
halt_error | Halts execution with error code 5 | halt_error() | |
identity | Returns the input value unchanged. | x | identity(x) |
implode | Joins an array of characters into a string. | array | implode(array) |
in | Returns true if the element is in the array. | v, elem | in(v, elem) |
increase_header_level | Increases the level of a markdown heading node by one, up to a maximum of 6. | heading_node | increase_header_level(heading_node) |
index | Finds the first occurrence of a substring in the given string. | string, substring | index(string, substring) |
index_by | Creates a dictionary indexed by a key extracted from each element. | arr, f | index_by(arr, f) |
infinite | Returns an infinite number value. | infinite() | |
input | Reads a line from standard input and returns it as a string. | input() | |
insert | Inserts a value into an array or string at the specified index, or into a dict with the specified key. | target, index_or_key, value | insert(target, index_or_key, value) |
inspect | Inspects a value by printing its string representation and returning the value. | value | inspect(value) |
intern | Interns the given string, returning a canonical reference for efficient comparison. | string | intern(string) |
is_array | Checks if input is an array | a | is_array(a) |
is_bool | Checks if input is a boolean | b | is_bool(b) |
is_code | Checks if markdown is code block | md | is_code(md) |
is_debug_mode | Checks if the runtime is currently in debug mode, returning true if a debugger is attached. | is_debug_mode() | |
is_dict | Checks if input is a dictionary | d | is_dict(d) |
is_em | Checks if markdown is emphasis | md | is_em(md) |
is_empty | Checks if string, array or dict is empty | s | is_empty(s) |
is_h | Checks if markdown is heading | md | is_h(md) |
is_h1 | Checks if markdown is h1 heading | md | is_h1(md) |
is_h2 | Checks if markdown is h2 heading | md | is_h2(md) |
is_h3 | Checks if markdown is h3 heading | md | is_h3(md) |
is_h4 | Checks if markdown is h4 heading | md | is_h4(md) |
is_h5 | Checks if markdown is h5 heading | md | is_h5(md) |
is_h6 | Checks if markdown is h6 heading | md | is_h6(md) |
is_h_level | Checks if markdown is a heading of the specified level (1-6) | md, level | is_h_level(md, level) |
is_html | Checks if markdown is html | md | is_html(md) |
is_list | Checks if markdown is list | list | is_list(list) |
is_markdown | Checks if input is markdown | m | is_markdown(m) |
is_mdx | Checks if markdown is MDX | mdx | is_mdx(mdx) |
is_mdx_flow_expression | Checks if markdown is MDX Flow Expression | mdx | is_mdx_flow_expression(mdx) |
is_mdx_js_esm | Checks if markdown is MDX Js Esm | mdx | is_mdx_js_esm(mdx) |
is_mdx_jsx_flow_element | Checks if markdown is MDX Jsx Flow Element | mdx | is_mdx_jsx_flow_element(mdx) |
is_mdx_jsx_text_element | Checks if markdown is MDX Jsx Text Element | mdx | is_mdx_jsx_text_element(mdx) |
is_mdx_text_expression | Checks if markdown is MDX Text Expression | mdx | is_mdx_text_expression(mdx) |
is_none | Checks if input is None | n | is_none(n) |
is_number | Checks if input is a number | n | is_number(n) |
is_string | Checks if input is a string | s | is_string(s) |
is_table_header | Checks if markdown is table header | md | is_table_header(md) |
is_text | Checks if markdown is text | text | is_text(text) |
is_toml | Checks if markdown is toml | md | is_toml(md) |
is_yaml | Checks if markdown is yaml | md | is_yaml(md) |
join | Joins the elements of an array into a string with the given separator. | array, separator | join(array, separator) |
keys | Returns an array of keys from the dict. | dict | keys(dict) |
last | Returns the last element of an array | arr | last(arr) |
len | Returns the length of the given string or array. | value | len(value) |
lt | Checks if the first value is less than the second value. | value1, value2 | lt(value1, value2) |
lte | Checks if the first value is less than or equal to the second value. | value1, value2 | lte(value1, value2) |
ltrimstr | Removes prefix string from input if it exists | s, left | ltrimstr(s, left) |
map | Applies a given function to each element of the provided array and returns a new array with the results. | v, f | map(v, f) |
markdowns | Returns markdown if input is markdown, None otherwise | m | markdowns(m) |
matches_url | Checks if markdown node’s URL matches a specified URL | node, url | matches_url(node, url) |
max | Returns the maximum of two values. | value1, value2 | max(value1, value2) |
min | Returns the minimum of two values. | value1, value2 | min(value1, value2) |
mod | Calculates the remainder of the division of the first value by the second value. | value1, value2 | mod(value1, value2) |
mul | Multiplies two values. | value1, value2 | mul(value1, value2) |
nan | Returns a Not-a-Number (NaN) value. | nan() | |
ne | Checks if two values are not equal. | value1, value2 | ne(value1, value2) |
negate | Returns the negation of the given number. | number | negate(number) |
not | Performs a logical NOT operation on a boolean value. | value | not(value) |
now | Returns the current timestamp. | now() | |
numbers | Returns number if input is number, None otherwise | n | numbers(n) |
or | Performs a logical OR operation on two boolean values. | value1, value2 | or(value1, value2) |
partition | Splits an array into two arrays: [matching, not_matching] based on a condition. | arr, f | partition(arr, f) |
pluck | Extracts values from an array of objects based on a specified selector. | pluck_obj, selector | pluck(pluck_obj, selector) |
pow | Raises the base to the power of the exponent. | base, exponent | pow(base, exponent) |
print | Prints a message to standard output and returns the current value. | message | print(message) |
range | Creates an array from start to end with an optional step. | start, end, step | range(start, end, step) |
read_file | Reads the contents of a file at the given path and returns it as a string. | path | read_file(path) |
regex_match | Finds all matches of the given pattern in the string. | string, pattern | regex_match(string, pattern) |
reject | Filters out elements that match the condition (opposite of filter). | arr, f | reject(arr, f) |
repeat | Repeats the given string a specified number of times. | string, count | repeat(string, count) |
replace | Replaces all occurrences of a substring with another substring. | from, pattern, to | replace(from, pattern, to) |
reverse | Reverses the given string or array. | value | reverse(value) |
rindex | Finds the last occurrence of a substring in the given string. | string, substring | rindex(string, substring) |
round | Rounds the given number to the nearest integer. | number | round(number) |
rtrimstr | Removes suffix string from input if it exists | s, right | rtrimstr(s, right) |
second | Returns the second element of an array | arr | second(arr) |
select | Returns value if condition is true, None otherwise | v, f | select(v, f) |
set | Sets a key-value pair in a dict. If the key exists, its value is updated. Returns the modified map. | obj, key, value | set(obj, key, value) |
set_attr | Sets the value of the specified attribute on a markdown node. | markdown, attribute, value | set_attr(markdown, attribute, value) |
set_check | Creates a markdown list node with the given checked state. | list, checked | set_check(list, checked) |
set_code_block_lang | Sets the language of a markdown code block node. | code_block, language | set_code_block_lang(code_block, language) |
set_list_ordered | Sets the ordered property of a markdown list node. | list, ordered | set_list_ordered(list, ordered) |
set_ref | Sets the reference identifier for markdown nodes that support references (e.g., Definition, LinkRef, ImageRef, Footnote, FootnoteRef). | node, reference_id | set_ref(node, reference_id) |
set_variable | Sets a symbol or variable in the current environment with the given value. | symbol_or_string, value | set_variable(symbol_or_string, value) |
skip | Skips the first n elements of an array and returns the rest | arr, n | skip(arr, n) |
skip_while | Skips elements from the beginning of an array while the provided function returns true | arr, f | skip_while(arr, f) |
slice | Extracts a substring from the given string. | string, start, end | slice(string, start, end) |
sort | Sorts the elements of the given array. | array | sort(array) |
sort_by | Sorts an array using a key function that extracts a comparable value for each element. | arr, f | sort_by(arr, f) |
split | Splits the given string by the specified separator. | string, separator | split(string, separator) |
starts_with | Checks if the given string starts with the specified substring. | string, substring | starts_with(string, substring) |
stderr | Prints a message to standard error and returns the current value. | message | stderr(message) |
sub | Subtracts the second value from the first value. | value1, value2 | sub(value1, value2) |
sum_by | Sums elements of an array after applying a transformation function. | arr, f | sum_by(arr, f) |
take | Takes the first n elements of an array | arr, n | take(arr, n) |
take_while | Takes elements from the beginning of an array while the provided function returns true | arr, f | take_while(arr, f) |
tap | Applies a function to a value and returns the value (useful for debugging or side effects). | tap_value, tap_expr | tap(tap_value, tap_expr) |
test | Tests if string matches a pattern | s, pattern | test(s, pattern) |
times | Executes an expression n times and returns an array of results. | t_n, t_expr | times(t_n, t_expr) |
to_array | Converts the given value to an array. | value | to_array(value) |
to_code | Creates a markdown code block with the given value and language. | value, language | to_code(value, language) |
to_code_inline | Creates an inline markdown code node with the given value. | value | to_code_inline(value) |
to_date | Converts a timestamp to a date string with the given format. | timestamp, format | to_date(timestamp, format) |
to_date_iso8601 | Formats a date to ISO 8601 format (YYYY-MM-DDTHH:MM:SSZ) | d | to_date_iso8601(d) |
to_em | Creates a markdown emphasis (italic) node with the given value. | value | to_em(value) |
to_h | Creates a markdown heading node with the given value and depth. | value, depth | to_h(value, depth) |
to_hr | Creates a markdown horizontal rule node. | to_hr() | |
to_html | Converts the given markdown string to HTML. | markdown | to_html(markdown) |
to_image | Creates a markdown image node with the given URL, alt text, and title. | url, alt, title | to_image(url, alt, title) |
to_link | Creates a markdown link node with the given url and title. | url, value, title | to_link(url, value, title) |
to_markdown | Parses a markdown string and returns an array of markdown nodes. | markdown_string | to_markdown(markdown_string) |
to_markdown_string | Converts the given value(s) to a markdown string representation. | value | to_markdown_string(value) |
to_math | Creates a markdown math block with the given value. | value | to_math(value) |
to_math_inline | Creates an inline markdown math node with the given value. | value | to_math_inline(value) |
to_md_list | Creates a markdown list node with the given value and indent level. | value, indent | to_md_list(value, indent) |
to_md_name | Returns the name of the given markdown node. | markdown | to_md_name(markdown) |
to_md_table_row | Creates a markdown table row node with the given values. | cells | to_md_table_row(cells) |
to_md_text | Creates a markdown text node with the given value. | value | to_md_text(value) |
to_mdx | Parses an MDX string and returns an array of MDX nodes. | mdx_string | to_mdx(mdx_string) |
to_number | Converts the given value to a number. | value | to_number(value) |
to_string | Converts the given value to a string. | value | to_string(value) |
to_strong | Creates a markdown strong (bold) node with the given value. | value | to_strong(value) |
to_text | Converts the given markdown node to plain text. | markdown | to_text(markdown) |
transpose | Transposes a 2D array (matrix), swapping rows and columns. | matrix | transpose(matrix) |
trim | Trims whitespace from both ends of the given string. | input | trim(input) |
trunc | Truncates the given number to an integer by removing the fractional part. | number | trunc(number) |
type | Returns the type of the given value. | value | type(value) |
uniq | Removes duplicate elements from the given array. | array | uniq(array) |
unique_by | Returns a new array with duplicate elements removed, comparing by the result of the provided function. | arr, f | unique_by(arr, f) |
unless | Executes the expression only if the condition is false. | unless_cond, unless_expr | unless(unless_cond, unless_expr) |
until | Executes the expression repeatedly until the condition is true. | until_cond, until_expr | until(until_cond, until_expr) |
upcase | Converts the given string to uppercase. | input | upcase(input) |
update | Update the value with specified value. | target_value, source_value | update(target_value, source_value) |
url_encode | URL-encodes the given string. | input | url_encode(input) |
values | Returns an array of values from the dict. | dict | values(dict) |
Builtin selectors
| Selector Name | Description | Parameters | Example |
|---|---|---|---|
.h, .h(depth) | Selects a heading node with the specified depth. | None, depth | .h, .h(6) |
.h1 | Selects a heading node with the 1 depth. | None | .h1 |
.h2 | Selects a heading node with the 2 depth. | None | .h2 |
.h3 | Selects a heading node with the 3 depth. | None | .h3 |
.h4 | Selects a heading node with the 4 depth. | None | .h4 |
.h5 | Selects a heading node with the 5 depth. | None | .h5 |
.h6 | Selects a heading node with the 6 depth. | None | .h6 |
.code | Selects a code block node with the specified language. | lang | .code "rust" |
.code_inline | Selects an inline code node. | None | .code_inline |
.inline_math | Selects an inline math node. | None | .inline_math |
.strong | Selects a strong (bold) node. | None | .strong |
.emphasis | Selects an emphasis (italic) node. | None | .emphasis |
.delete | Selects a delete (strikethrough) node. | None | .delete |
.link | Selects a link node. | None | .link |
.link_ref | Selects a link reference node. | None | .link_ref |
.image | Selects an image node. | None | .image |
.heading | Selects a heading node with the specified depth. | None | .heading 1 |
.horizontal_rule | Selects a horizontal rule node. | None | .horizontal_rule |
.blockquote | Selects a blockquote node. | None | .blockquote |
.[][] | Selects a table cell node with the specified row and column. | row, column | .[1][1] |
.html ,.<> | Selects an HTML node. | None | .html, .<> |
.footnote | Selects a footnote node. | None | .footnote |
.mdx_jsx_flow_element | Selects an MDX JSX flow element node. | None | .mdx_jsx_flow_element |
.list,.[] | Selects a list node with the specified index and checked state. | indent | .list(1), .[1] |
.mdx_js_esm | Selects an MDX JS ESM node. | None | .mdx_js_esm |
.toml | Selects a TOML node. | None | .toml |
.text | Selects a Text node. | None | .text |
.yaml | Selects a YAML node. | None | .yaml |
.break | Selects a break node. | None | .break |
.mdx_text_expression | Selects an MDX text expression node. | None | .mdx_text_expression |
.footnote_ref | Selects a footnote reference node. | None | .footnote_ref |
.image_ref | Selects an image reference node. | None | .image_ref |
.mdx_jsx_text_element | Selects an MDX JSX text element node. | None | .mdx_jsx_text_element |
.math | Selects a math node. | None | .math |
.math_inline | Selects a math inline node. | None | .math_inline |
.mdx_flow_expression | Selects an MDX flow expression node. | None | .mdx_flow_expression |
.definition | Selects a definition node. | None | .definition |
Selectors
Selectors in mq allow you to select specific markdown nodes from a document. You can also access attributes of selected nodes using dot notation.
Basic Selector Usage
Selectors use the . prefix to select markdown nodes. For example:
.h # Selects all heading nodes
.code # Selects all code blocks
.link # Selects all link nodes
Attribute Access
Once you’ve selected a node, you can access its attributes using dot notation. The available attributes depend on the node type.
Common Attributes
value
Most nodes support value to get the text content:
.code.value # Gets the code content
Heading Attributes
Heading nodes support the following attributes:
| Attribute | Type | Description | Example |
|---|---|---|---|
depth, level | Integer | The heading level (1-6) | .h.level |
value | String | The value of the heading | .h.value |
Example:
# Input: # Hello World
.h.level # Returns: 1
.h.value # Returns: "Hello World"
Code Block Attributes
Code block nodes support the following attributes:
| Attribute | Type | Description | Example |
|---|---|---|---|
lang, language | String | The language of the code block | .code.lang |
value | String | The code content | .code.value |
meta | String | Metadata associated with the code block | .code.meta |
fence | Boolean | Whether the code block is fenced | .code.fence |
Example:
# Input: ```rust
# fn main() {}
# ```
.code.lang # Returns: "rust"
.code.value # Returns: "fn main() {}"
Link Attributes
Link nodes support the following attributes:
| Attribute | Type | Description | Example |
|---|---|---|---|
url | String | The URL of the link | .link.url |
title | String | The title of the link | .link.title |
value | String | The link value | .link.value |
Example:
# Input: [Example](https://example.com "Example Site")
.link.url # Returns: "https://example.com"
.link.title # Returns: "Example Site"
.link.value # Returns: "Example"
Image Attributes
Image nodes support the following attributes:
| Attribute | Type | Description | Example |
|---|---|---|---|
url | String | The URL of the image | .image.url |
alt | String | The alt text of the image | .image.alt |
title | String | The title of the image | .image.title |
Example:
# Input: 
.image.url # Returns: "image.png"
.image.alt # Returns: "Alt text"
.image.title # Returns: "Image Title"
List Attributes
List nodes support the following attributes:
| Attribute | Type | Description | Example |
|---|---|---|---|
index | Integer | The index of the list item | .list.index |
level | Integer | The nesting level of the list item | .list.level |
ordered | Boolean | Whether the list is ordered | .list.ordered |
checked | Boolean | The checked state (for task lists) | .list.checked |
value | String | The text content of the list item | .list.value |
Table Cell Attributes
Table cell nodes support the following attributes:
| Attribute | Type | Description | Example |
|---|---|---|---|
row | Integer | The row number of the cell | .[0][0].row |
column | Integer | The column number of the cell | .[0][0].column |
last_cell_in_row | Boolean | Whether this is the last cell in the row | .[0][0].last_cell_in_row |
last_cell_of_in_table | Boolean | Whether this is the last cell in the table | .[0][0].last_cell_of_in_table |
value | String | The text content of the cell | .[0][0].value |
Reference Nodes Attributes
Reference nodes (link references, image references, footnotes) support:
| Node Type | Attributes | Description |
|---|---|---|
.link_ref | ident, label | Identifier and label of link reference |
.image_ref | ident, label, alt | Identifier, label, and alt text |
.footnote_ref | ident, label | Identifier and label of footnote |
.footnote | ident, text | Identifier and content of footnote |
.definition | ident, url, title, label | Link/image definition attributes |
MDX Attributes
MDX nodes support the following attributes:
| Attribute | Type | Description | Example |
|---|---|---|---|
name | String | The name of the MDX element | .mdx_jsx_flow_element.name |
value | String | The content of the MDX node | .mdx_flow_expression.value |
Text Nodes Attributes
Text, HTML, YAML, TOML, Math nodes support:
| Attribute | Type | Description | Example |
|---|---|---|---|
value | String | The text content | .text.value |
Combining Selectors with Functions
You can combine selectors with functions like select(), map(), and filter() for powerful transformations:
Using select()
The select() function filters elements based on a condition:
# Select only code blocks (exclude non-code nodes)
select(.code)
# Select nodes that are not code blocks
select(!.code)
Using map()
Transform each selected node:
# Get all heading levels
.h | map(fn(h): h.level;)
# Get all code block languages
.code | map(fn(c): c.lang;)
Using filter()
Filter nodes based on attribute values:
# Get only level 2 headings
.h | filter(fn(h): h.level == 2;)
# Get only rust code blocks
.code | filter(fn(c): c.lang == "rust";)
Extract Code Languages
.code.lang
Extract All Links
.link.url
Filter High-Level Headings
select(.h.level <= 2)
Setting Attributes
You can also modify node attributes using the set_attr() function:
# Change code block language
.code | set_attr("lang", "javascript")
# Update link URL
.link | set_attr("url", "https://new-url.com")
# Update heading level
.h | set_attr("level", 2)
Note: Not all attributes are settable. Refer to the implementation in mq-markdown/src/node.rs for details on which attributes can be modified.
See Also
- Builtin selectors - Complete list of available selectors
- Builtin functions - Functions to use with selectors
- Nodes - Details about markdown node types
CSV Functions
The CSV module provides functions for parsing, processing, and converting CSV (Comma-Separated Values) and TSV (Tab-Separated Values) data.
Including the CSV Module
To use the CSV functions, include the module at the top of your mq script:
include "csv"
Functions
csv_parse(input, has_header)
Parses CSV content using a comma as the delimiter.
Parameters:
input: String containing the CSV datahas_header: Boolean indicating whether the first row contains headers
Returns:
- If
has_headeristrue: Array of dictionaries where keys are column headers - If
has_headerisfalse: Array of arrays containing raw row data
Example:
include "csv"
# Parse CSV with headers
| "name,age,city\nJohn,30,New York\nJane,25,Boston" | csv_parse(true)
# Returns: [{"name": "John", "age": "30", "city": "New York"}, {"name": "Jane", "age": "25", "city": "Boston"}]
# Parse CSV without headers
| "John,30,New York\nJane,25,Boston" | csv_parse(false)
# Returns: [["John", "30", "New York"], ["Jane", "25", "Boston"]]
csv_parse_with_delimiter(input, delimiter, has_header)
Parses CSV content with a custom delimiter.
Parameters:
input: String containing the CSV datadelimiter: String specifying the field delimiterhas_header: Boolean indicating whether the first row contains headers
Returns:
- If
has_headeristrue: Array of dictionaries where keys are column headers - If
has_headerisfalse: Array of arrays containing raw row data
Example:
include "csv"
# Parse semicolon-separated values
| "name;age;city\nJohn;30;New York\nJane;25;Boston" | csv_parse_with_delimiter(";", true)
# Returns: [{"name": "John", "age": "30", "city": "New York"}, {"name": "Jane", "age": "25", "city": "Boston"}]
tsv_parse(input, has_header)
Parses TSV (Tab-Separated Values) content.
Parameters:
input: String containing the TSV datahas_header: Boolean indicating whether the first row contains headers
Returns:
- If
has_headeristrue: Array of dictionaries where keys are column headers - If
has_headerisfalse: Array of arrays containing raw row data
Example:
include "csv"
# Parse TSV with headers
| "name age city\nJohn 30 New York\nJane 25 Boston" | tsv_parse(true)
# Returns: [{"name": "John", "age": "30", "city": "New York"}, {"name": "Jane", "age": "25", "city": "Boston"}]
csv_stringify(data, delimiter)
Converts data to a CSV string with a specified delimiter.
Parameters:
data: Array of dictionaries or array of arrays to convertdelimiter: String specifying the field delimiter
Returns:
- String containing the formatted CSV data
Example:
include "csv"
# Convert array of dictionaries to CSV
| [{"name": "John", "age": "30"}, {"name": "Jane", "age": "25"}] | csv_stringify(",")
# Returns: "name,age\nJohn,30\nJane,25"
# Convert array of arrays to CSV
| [["name", "age"], ["John", "30"], ["Jane", "25"]] | csv_stringify(",")
# Returns: "name,age\nJohn,30\nJane,25"
csv_to_markdown_table(data)
Converts CSV data to a Markdown table format.
Parameters:
data: Array of dictionaries or array of arrays
Returns:
- String containing the Markdown table
Example:
include "csv"
# Convert to Markdown table
| [{"name": "John", "age": "30"}, {"name": "Jane", "age": "25"}] | csv_to_markdown_table()
# Returns:
# | name | age |
# | --- | --- |
# | John | 30 |
# | Jane | 25 |
csv_to_json(data)
Converts CSV data to a JSON string.
Parameters:
data: Array of dictionaries or array of arrays
Returns:
- String containing the JSON representation
Example:
include "csv"
# Convert to JSON
| [{"name": "John", "age": "30"}, {"name": "Jane", "age": "25"}] | csv_to_json()
# Returns: [{"name":"John","age":"30"},{"name":"Jane","age":"25"}]
CSV Format Support
The CSV parser follows RFC 4180 specifications and supports:
- Quoted fields with embedded commas, newlines, and quotes
- Escaped quotes within quoted fields (double quotes)
- Custom delimiters
- Header row processing
- Mixed quoted and unquoted fields
Fuzzy Functions
The Fuzzy module provides functions for fuzzy string matching and similarity calculations.
Including the Fuzzy Module
To use the Fuzzy functions, include the module at the top of your mq script:
include "fuzzy"
Functions
levenshtein(s1, s2)
Calculates the Levenshtein distance between two strings. The Levenshtein distance is the minimum number of single-character edits (insertions, deletions, or substitutions) required to change one string into the other.
Parameters:
s1: First string to compares2: Second string to compare
Returns:
- Integer representing the Levenshtein distance (0 means strings are identical)
Example:
include "fuzzy"
# Calculate Levenshtein distance
| levenshtein("hello", "hallo")
# Returns: 1
| levenshtein("kitten", "sitting")
# Returns: 3
| levenshtein("identical", "identical")
# Returns: 0
| levenshtein("", "abc")
# Returns: 3
jaro(s1, s2)
Calculates the Jaro distance between two strings. The Jaro distance is a measure of similarity between strings, ranging from 0.0 (no similarity) to 1.0 (exact match).
Parameters:
s1: First string to compares2: Second string to compare
Returns:
- Float between 0.0 and 1.0 (1.0 indicates exact match)
Example:
include "fuzzy"
# Calculate Jaro distance
| jaro("hello", "hallo")
# Returns: 0.866667
| jaro("martha", "marhta")
# Returns: 0.9444444444444444
| jaro("identical", "identical")
# Returns: 1.0
| jaro("", "abc")
# Returns: 0.0
jaro_winkler(s1, s2)
Calculates the Jaro-Winkler distance between two strings. This is a variant of the Jaro distance with a prefix scale that gives more favorable ratings to strings with common prefixes.
Parameters:
s1: First string to compares2: Second string to compare
Returns:
- Float between 0.0 and 1.0 (1.0 indicates exact match)
Example:
include "fuzzy"
# Calculate Jaro-Winkler distance
| jaro_winkler("hello", "hallo")
# Returns: 0.88
| jaro_winkler("martha", "marhta")
# Returns: 0.9611111111111111
| jaro_winkler("prefix_test", "prefix_example")
# Returns: 0.84724
| jaro_winkler("identical", "identical")
# Returns: 1.0
fuzzy_match(candidates, query)
Performs fuzzy matching on an array of strings using the Jaro-Winkler distance algorithm. Returns results sorted by similarity score in descending order.
Parameters:
candidates: Array of strings to search within, or a single stringquery: String to search for
Returns:
- Array of objects with
textandscoreproperties, sorted by best match first
Example:
include "fuzzy"
# Fuzzy match with multiple candidates
| fuzzy_match(["hallo", "hello", "hi", "help"], "hello")
# Returns: [
# {"text": "hello", "score": 1},
# {"text": "hallo", "score": 0.88},
# {"text": "help", "score": 0.848333},
# {"text": "hi", "score": 0.1}
# ]
# Fuzzy match with single candidate
| "testing" | fuzzy_match("test")
# Returns: [{"text": "testing", "score": 0.8095238095238095}]
fuzzy_match_levenshtein(candidates, query)
Performs fuzzy matching using Levenshtein distance. Returns results sorted by distance (lower distance means better match).
Parameters:
candidates: Array of strings to search withinquery: String to search for
Returns:
- Array of objects with
textandscoreproperties, sorted by lowest distance first
Example:
include "fuzzy"
# Fuzzy match using Levenshtein distance
| fuzzy_match_levenshtein(["hallo", "hello", "hi", "help"], "hello")
# Returns: [
# {"text": "hello", "score": 0},
# {"text": "hallo", "score": 1},
# {"text": "help", "score": 2},
# {"text": "hi", "score": 4}
# ]
fuzzy_match_jaro(candidates, query)
Performs fuzzy matching using the Jaro distance algorithm. Returns results sorted by similarity score in descending order.
Parameters:
candidates: Array of strings to search withinquery: String to search for
Returns:
- Array of objects with
textandscoreproperties, sorted by best match first
Example:
include "fuzzy"
# Fuzzy match using Jaro distance
| fuzzy_match_jaro(["hallo", "hello", "hi", "help"], "hello")
# Returns: [
# {"text": "hello", "score": 1.0},
# {"text": "hallo", "score": 0.8666666666666667},
# {"text": "help", "score": 0.7333333333333334},
# {"text": "hi", "score": 0.0}
# ]
fuzzy_filter(candidates, query, threshold)
Filters candidates by minimum fuzzy match score using Jaro-Winkler distance. Only returns matches that meet or exceed the specified threshold.
Parameters:
candidates: Array of strings to search withinquery: String to search forthreshold: Minimum score threshold (0.0 to 1.0)
Returns:
- Array of objects with
textandscoreproperties for matches above threshold
Example:
include "fuzzy"
# Filter matches with minimum threshold
| fuzzy_filter(["hallo", "hello", "hi", "help"], "hello", 0.7)
# Returns: [
# {"text": "hello", "score": 1.0},
# {"text": "hallo", "score": 0.8666666666666667},
# {"text": "help", "score": 0.7333333333333334}
# ]
# Filter with high threshold
| fuzzy_filter(["hallo", "hello", "hi", "help"], "hello", 0.9)
# Returns: [
# {"text": "hello", "score": 1.0}
# ]
fuzzy_best_match(candidates, query)
Finds the best fuzzy match from candidates using Jaro-Winkler distance.
Parameters:
candidates: Array of strings to search withinquery: String to search for
Returns:
- Object with
textandscoreproperties for the best match, orNoneif no matches found
Example:
include "fuzzy"
# Find best match
| fuzzy_best_match(["hallo", "hi", "help"], "hello")
# Returns: {"text": "hallo", "score": 0.88}
# No matches case
| fuzzy_best_match([], "xyz")
# Returns: None
JSON Functions
The JSON module provides functions for parsing, processing, and converting JSON (JavaScript Object Notation) data.
Including the JSON Module
To use the JSON functions, include the module at the top of your mq script:
include "json"
Functions
json_parse(input)
Parses a JSON string and returns the parsed data structure.
Parameters:
input: String containing the JSON data
Returns:
- Parsed data structure (dict, array, or scalar value depending on the JSON content)
Example:
include "json"
# Parse JSON object
| "{\"name\": \"John\", \"age\": 30, \"city\": \"New York\"}" | json_parse()
# Returns: {"name": "John", "age": 30, "city": "New York"}
# Parse JSON array
| "[\"item1\", \"item2\", \"item3\"]" | json_parse()
# Returns: ["item1", "item2", "item3"]
# Parse complex JSON
| "{\"users\": [{\"name\": \"John\", \"age\": 30}, {\"name\": \"Jane\", \"age\": 25}]}" | json_parse()
# Returns: {"users": [{"name": "John", "age": 30}, {"name": "Jane", "age": 25}]}
# Parse JSON with boolean and null values
| "{\"active\": true, \"score\": null, \"verified\": false}" | json_parse()
# Returns: {"active": true, "score": null, "verified": false}
json_stringify(data)
Converts a data structure to a JSON string representation.
Parameters:
data: Data structure to convert (dict, array, or scalar value)
Returns:
- String containing the formatted JSON data
Example:
include "json"
# Convert dict to JSON
| {"name": "John", "age": 30, "city": "New York"} | json_stringify()
# Returns: "{\"name\": \"John\", \"age\": 30, \"city\": \"New York\"}"
# Convert array to JSON
| ["item1", "item2", "item3"] | json_stringify()
# Returns: "[\"item1\", \"item2\", \"item3\"]"
# Convert nested structure to JSON
| {"users": [{"name": "John", "age": 30}, {"name": "Jane", "age": 25}]} | json_stringify()
# Returns: "{\"users\": [{\"name\": \"John\", \"age\": 30}, {\"name\": \"Jane\", \"age\": 25}]}"
# Convert scalar values
| "Hello World" | json_stringify()
# Returns: "\"Hello World\""
| 42 | json_stringify()
# Returns: "42"
| true | json_stringify()
# Returns: "true"
| None | json_stringify()
# Returns: "null"
json_to_markdown_table(data)
Converts a JSON data structure to a Markdown table format.
Parameters:
data: JSON data structure to convert (dict, array, or scalar value)
Returns:
- String containing the Markdown table
Example:
include "json"
# Convert dict to Markdown table
| {"name": "John", "age": 30, "city": "New York"} | json_to_markdown_table()
# Returns:
# | Key | Value |
# | --- | --- |
# | name | John |
# | age | 30 |
# | city | New York |
# Convert array of dicts to Markdown table
| [{"name": "John", "age": 30}, {"name": "Jane", "age": 25}] | json_to_markdown_table()
# Returns:
# | name | age |
# | --- | --- |
# | John | 30 |
# | Jane | 25 |
# Convert scalar value to Markdown table
| "Hello World" | json_to_markdown_table()
# Returns:
# | Value |
# | --- |
# | Hello World |
Type Conversion
The JSON parser automatically converts values to appropriate mq types:
- Strings: JSON strings become mq strings
- Numbers: JSON numbers become mq numbers (integers or floats)
- Booleans: JSON
true/falsebecome mq booleans - Null: JSON
nullbecomes mqNone - Arrays: JSON arrays become mq arrays
- Objects: JSON objects become mq dictionaries
Section Functions
The Section module provides functions for splitting, filtering, and manipulating Markdown documents by section. Sections are defined by headers (H1-H6) and include all content until the next header of the same level.
Including the Section Module
To use the Section functions, include the module at the top of your mq script:
import "section"
Functions
sections(md_nodes)
Splits Markdown nodes into sections at each heading node.
Each section starts with a heading node and includes all subsequent nodes up to the next heading of the same or higher level.
Parameters:
md_nodes: Array of Markdown nodes to split
Returns:
- Array of section objects, where each section has:
type: Always:sectionheader: The heading node that starts the sectionchildren: Array of all nodes in the section (excluding the header)
Example:
import "section"
nodes | section::sections()
split(md_nodes, level)
Splits markdown nodes into sections based on header level. Each section includes a header and all content until the next header of the same level.
Parameters:
md_nodes: Array of markdown nodes to splitlevel: Header level (1-6) to split on
Returns:
- Array of section objects, where each section has:
type: Always:sectionheader: The header nodechildren: Array of all nodes in the section (excluding the header)
Example:
import "section"
nodes | section::split(2)
title_contains(sections, text)
Filters sections by checking if the title contains the specified text.
Parameters:
sections: Array of section objectstext: String to search for in section titles
Returns:
- Array of sections whose titles contain the specified text
Example:
import "section"
# Find sections with "API" in the title
| nodes | section::split(2) | section::title_contains("API")
title_match(sections, pattern)
Filters sections by matching the title against a regular expression pattern.
Parameters:
sections: Array of section objectspattern: Regular expression pattern to match against section titles
Returns:
- Array of sections whose titles match the pattern
Example:
import "section"
# Find sections starting with "Chapter"
| nodes | section:::split(1) | section::title_match("^Chapter")
title(section)
Extracts the title text from a section (header text without the # symbols).
Parameters:
section: A section object
Returns:
- String containing the section title, or empty string if not a valid section
Example:
import "section"
# Get title of first H2 section
| nodes | section::split(2) | section::nth(0) | section::title()
content(section)
Returns the content of a section, excluding the header.
Parameters:
section: A section object
Returns:
- Array of markdown nodes (all nodes except the header)
Example:
import "section"
# Get content of the first section
| nodes | section::split(2) | section::nth(0) | section::content()
all_nodes(section)
Returns all nodes of a section, including both the header and content.
Parameters:
section: A section object
Returns:
- Array of all markdown nodes in the section
Example:
import "section"
# Get all nodes including header
| nodes | section::split(2) | section::nth(0) | section::all_nodes()
level(section)
Returns the header level of a section.
Parameters:
section: A section object
Returns:
- Integer from 1-6 representing the header level, or 0 if not a valid section
Example:
import "section"
# Get the level of each section
| nodes | section::split(2) | map(section::level)
nth(sections, n)
Returns the nth section from an array of sections (0-indexed).
Parameters:
sections: Array of section objectsn: Index of the section to retrieve (0-based)
Returns:
- The section at index
n, orNoneif index is out of bounds
Example:
import "section"
# Get the first section
| nodes | section::split(2) | section::nth(0)
titles(sections)
Extracts titles from all sections in an array.
Parameters:
sections: Array of section objects
Returns:
- Array of title strings
Example:
import "section"
# Get all H2 titles
| nodes | section::split(2) | section::titles()
toc(sections)
Generates a table of contents from sections with proper indentation based on header level.
Parameters:
sections: Array of section objects
Returns:
- Array of strings, each representing a TOC entry with appropriate indentation
Example:
import "section"
# Generate table of contents for all H2 sections
| nodes | section::split(2) | section::toc()
has_content(section)
Checks if a section has any content beyond the header.
Parameters:
section: A section object
Returns:
- Boolean:
trueif the section has content,falseotherwise
Example:
import "section"
# Filter sections that have content
| nodes | section::split(2) | filter(section::has_content)
collect(sections)
Converts section objects back to their original markdown node arrays. This is useful for outputting sections after manipulation.
Parameters:
sections: Array of section objects
Returns:
- Array of markdown nodes with sections collected
Example:
import "section"
# Filter sections and convert back to markdown
| nodes | section::split(2) | section::title_contains("API") | section::collect()
Usage Patterns
Extracting Specific Sections
include "section"
# Get all content from "Installation" section
| h2() | split(2) | title_contains("Installation") | nth(0) | content()
Filtering and Reorganizing Content
include "section"
# Get only API-related sections
| h2() | split(2) | title_match("^API") | collect()
Building Navigation
include "section"
# Create a complete table of contents
| h1() + h2() + h3() | toc()
Finding Empty Sections
include "section"
# List sections without content
| h2() | split(2) | filter(fn(s): !has_content(s);) | titles()
Section Object Structure
Each section object returned by split() has the following structure:
{
type: :section,
header: <header_node>,
children: [<content_nodes>...]
}
type: Always the symbol:sectionheader: The markdown header nodechildren: Array of all nodes including the header and subsequent content
TOML Functions
The TOML module provides functions for parsing, processing, and converting TOML (Tom’s Obvious Minimal Language) data.
Including the TOML Module
To use the TOML functions, include the module at the top of your mq script:
include "toml"
Functions
toml_parse(input)
Parses TOML content and returns the parsed data structure.
Parameters:
input: String containing the TOML data
Returns:
- Dictionary representing the parsed TOML structure
Example:
include "toml"
# Parse TOML configuration
| "[server]
name = \"example\"
port = 8080
enabled = true
[[database]]
host = \"localhost\"
port = 5432" | toml_parse()
# Returns: {"server": {"name": "example", "port": 8080, "enabled": true}, "database": [{"host": "localhost", "port": 5432}]}
toml_stringify(data)
Converts a data structure to a TOML string representation.
Parameters:
data: Dictionary or data structure to convert to TOML
Returns:
- String containing the TOML representation
Example:
include "toml"
# Convert data to TOML
| {"server": {"name": "example", "port": 8080}, "enabled": true} | toml_stringify()
# Returns: "[server]\nname = \"example\"\nport = 8080\nenabled = true"
toml_to_json(data)
Converts TOML data to a JSON string representation.
Parameters:
data: TOML data structure to convert
Returns:
- String containing the JSON representation
Example:
include "toml"
# Convert TOML data to JSON
| {"name": "example", "port": 8080, "enabled": true} | toml_to_json()
# Returns: {"name":"example","port":8080,"enabled":true}
toml_to_markdown_table(data)
Converts TOML data to a Markdown table format.
Parameters:
data: TOML data structure to convert
Returns:
- String containing the Markdown table
Example:
include "toml"
# Convert to Markdown table
| {"name": "example", "port": 8080, "enabled": true} | toml_to_markdown_table()
# Returns:
# | Key | Value |
# | --- | --- |
# | name | example |
# | port | 8080 |
# | enabled | true |
TOML Format Support
The TOML parser follows TOML v1.0.0 specification and supports:
- Basic key/value pairs with various data types
- Nested tables and dotted keys
- Arrays and array of tables
- Inline tables
- Multiline strings (basic and literal)
- Numbers (integers, floats, infinity, NaN)
- Booleans
- Comments
- Quoted and bare keys
- Escape sequences in strings
- RFC 4648 Base64 encoding support
- Mixed quoted and unquoted fields
Data Type Mapping
TOML data types are mapped to mq data types as follows:
- String: Mapped to mq strings with escape sequence support
- Integer: Mapped to mq numbers
- Float: Mapped to mq numbers (including special values like inf, -inf, nan)
- Boolean: Mapped to mq booleans (true/false)
- Array: Mapped to mq arrays
- Table: Mapped to mq dictionaries
- Array of Tables: Mapped to mq arrays containing dictionaries
YAML Functions
The YAML module provides functions for parsing, processing, and converting YAML (YAML Ain’t Markup Language) data.
Including the YAML Module
To use the YAML functions, include the module at the top of your mq script:
include "yaml"
Functions
yaml_parse(input)
Parses a YAML string and returns the parsed data structure.
Parameters:
input: String containing the YAML data
Returns:
- Parsed data structure (dict, array, or scalar value depending on the YAML content)
Example:
include "yaml"
# Parse YAML object
| "name: John\nage: 30\ncity: New York" | yaml_parse()
# Returns: {"name": "John", "age": 30, "city": "New York"}
# Parse YAML array
| "- item1\n- item2\n- item3" | yaml_parse()
# Returns: ["item1", "item2", "item3"]
# Parse complex YAML
| "users:\n - name: John\n age: 30\n - name: Jane\n age: 25" | yaml_parse()
# Returns: {"users": [{"name": "John", "age": 30}, {"name": "Jane", "age": 25}]}
yaml_stringify(data)
Converts a data structure to a YAML string representation.
Parameters:
data: Data structure to convert (dict, array, or scalar value)
Returns:
- String containing the formatted YAML data
Example:
include "yaml"
# Convert dict to YAML
| {"name": "John", "age": 30, "city": "New York"} | yaml_stringify()
# Returns: "name: John\nage: 30\ncity: New York"
# Convert array to YAML
| ["item1", "item2", "item3"] | yaml_stringify()
# Returns: "- item1\n- item2\n- item3"
# Convert nested structure to YAML
| {"users": [{"name": "John", "age": 30}, {"name": "Jane", "age": 25}]} | yaml_stringify()
# Returns: "users:\n - name: John\n age: 30\n - name: Jane\n age: 25"
yaml_keys(data, prefix)
Returns all keys in a YAML data structure, including nested keys, with dot notation.
Parameters:
data: YAML data structure (dict or array)prefix: String prefix to add to the keys (use empty string for no prefix)
Returns:
- Array of strings containing all keys with dot notation for nested structures
Example:
include "yaml"
# Get keys from nested YAML structure
| let data = {"user": {"name": "John", "profile": {"age": 30, "city": "New York"}}}
| data | yaml_keys("")
# Returns: ["user", "user.name", "user.profile", "user.profile.age", "user.profile.city"]
# Get keys with prefix
| data | yaml_keys("root")
# Returns: ["root.user", "root.user.name", "root.user.profile", "root.user.profile.age", "root.user.profile.city"]
yaml_to_json(data)
Converts a YAML data structure to a JSON string representation.
Parameters:
data: YAML data structure to convert
Returns:
- String containing the JSON representation
Example:
include "yaml"
# Convert YAML data to JSON
| {"name": "John", "age": 30, "active": true} | yaml_to_json()
# Returns: "{\"name\": \"John\", \"age\": 30, \"active\": true}"
# Convert array to JSON
| ["item1", "item2", "item3"] | yaml_to_json()
# Returns: "[\"item1\", \"item2\", \"item3\"]"
yaml_to_markdown_table(data)
Converts a YAML data structure to a Markdown table format.
Parameters:
data: YAML data structure to convert (dict, array, or scalar value)
Returns:
- String containing the Markdown table
Example:
include "yaml"
# Convert dict to Markdown table
| {"name": "John", "age": 30, "city": "New York"} | yaml_to_markdown_table()
# Returns:
# | Key | Value |
# | --- | --- |
# | name | John |
# | age | 30 |
# | city | New York |
# Convert array of dicts to Markdown table
| [{"name": "John", "age": 30}, {"name": "Jane", "age": 25}] | yaml_to_markdown_table()
# Returns:
# | name | age |
# | --- | --- |
# | John | 30 |
# | Jane | 25 |
YAML Format Support
The YAML parser supports YAML 1.2 specifications and handles:
- Scalars: strings, numbers, booleans, and null values
- Collections: sequences (arrays) and mappings (dictionaries)
- Nested structures with proper indentation
- Quoted and unquoted strings
- Multi-line strings with literal block scalars (
|) - Boolean values:
true,false,yes,no(case-insensitive) - Null values:
null,~, or empty values - Comments (lines starting with
#) - Proper handling of special characters and escape sequences
Type Conversion
The YAML parser automatically converts values to appropriate types:
- Strings: Quoted or unquoted text
- Numbers: Integers and floating-point numbers
- Booleans:
true/false,yes/no,True/False, etc. - Null:
null,~, or empty values becomeNone - Arrays: YAML sequences become mq arrays
- Objects: YAML mappings become mq dictionaries
XML Functions
The XML module provides functions for parsing, processing, and converting XML (eXtensible Markup Language) data.
Including the XML Module
To use the XML functions, include the module at the top of your mq script:
include "xml"
Functions
xml_parse(input)
Parses an XML string and returns the parsed data structure.
Parameters:
input: String containing the XML data
Returns:
- Parsed data structure representing the XML element with the following structure:
tag: The element tag nameattributes: Dictionary of attributeschildren: Array of child elementstext: Text content of the element (orNoneif empty)
Example:
include "xml"
# Parse simple XML element
| "<person name=\"John\" age=\"30\">Hello World</person>" | xml_parse()
# Returns: {"tag": "person", "attributes": {"name": "John", "age": "30"}, "children": [], "text": "Hello World"}
# Parse self-closing XML element
| "<input type=\"text\" name=\"username\"/>" | xml_parse()
# Returns: {"tag": "input", "attributes": {"type": "text", "name": "username"}, "children": [], "text": None}
# Parse nested XML
| "<book><title>The Great Gatsby</title><author>F. Scott Fitzgerald</author></book>" | xml_parse()
# Returns: {"tag": "book", "attributes": {}, "children": [{"tag": "title", "attributes": {}, "children": [], "text": "The Great Gatsby"}, {"tag": "author", "attributes": {}, "children": [], "text": "F. Scott Fitzgerald"}], "text": None}
# Parse XML with CDATA
| "<description><![CDATA[This is <b>bold</b> text]]></description>" | xml_parse()
# Returns: {"tag": "description", "attributes": {}, "children": [], "text": "This is <b>bold</b> text"}
# Parse XML with declaration
| "<?xml version=\"1.0\" encoding=\"UTF-8\"?><root>Content</root>" | xml_parse()
# Returns: {"tag": "root", "attributes": {}, "children": [], "text": "Content"}
xml_stringify(data)
Converts a data structure to an XML string representation.
Parameters:
data: XML data structure to convert (should have the structure returned byxml_parse)
Returns:
- String containing the formatted XML data
Example:
include "xml"
# Convert element to XML string
| {"tag": "person", "attributes": {"name": "John", "age": "30"}, "children": [], "text": "Hello World"} | xml_stringify()
# Returns: "<person name=\"John\" age=\"30\">Hello World</person>"
# Convert self-closing element to XML
| {"tag": "input", "attributes": {"type": "text", "name": "username"}, "children": [], "text": None} | xml_stringify()
# Returns: "<input type=\"text\" name=\"username\"/>"
# Convert nested structure to XML
| {"tag": "book", "attributes": {}, "children": [{"tag": "title", "attributes": {}, "children": [], "text": "The Great Gatsby"}], "text": None} | xml_stringify()
# Returns: "<book><title>The Great Gatsby</title></book>"
# Convert element with both text and children
| {"tag": "div", "attributes": {"class": "container"}, "children": [{"tag": "span", "attributes": {}, "children": [], "text": "Nested"}], "text": "Text content"} | xml_stringify()
# Returns: "<div class=\"container\">Text content<span>Nested</span></div>"
# Convert scalar values (non-XML data)
| "Plain text" | xml_stringify()
# Returns: "Plain text"
| 42 | xml_stringify()
# Returns: "42"
xml_to_markdown_table(data)
Converts an XML data structure to a Markdown table format.
Parameters:
data: XML data structure to convert (should have the structure returned byxml_parse)
Returns:
- String containing the Markdown table representation
Example:
include "xml"
# Convert simple element to Markdown table
| {"tag": "person", "attributes": {"name": "John", "age": "30"}, "children": [], "text": "Hello World"} | xml_to_markdown_table()
# Returns:
# | Tag | Attributes | Text | Children |
# | --- | --- | --- | --- |
# | person | name=John, age=30 | Hello World | 0 |
# Convert element with children to Markdown table
| {"tag": "book", "attributes": {}, "children": [{"tag": "title", "attributes": {}, "children": [], "text": "The Great Gatsby"}, {"tag": "author", "attributes": {}, "children": [], "text": "F. Scott Fitzgerald"}], "text": None} | xml_to_markdown_table()
# Returns:
# | Index | Tag | Attributes | Text |
# | --- | --- | --- | --- |
# | 0 | title | | The Great Gatsby |
# | 1 | author | | F. Scott Fitzgerald |
#
# ## Children of title:
#
# | Tag | Attributes | Text | Children |
# | --- | --- | --- | --- |
# | title | | The Great Gatsby | 0 |
#
# ## Children of author:
#
# | Tag | Attributes | Text | Children |
# | --- | --- | --- | --- |
# | author | | F. Scott Fitzgerald | 0 |
# Convert scalar value to Markdown table
| "Plain text" | xml_to_markdown_table()
# Returns:
# | Value |
# | --- |
# | Plain text |
Data Structure
The XML parser creates data structures with the following format:
- tag: String containing the XML element tag name
- attributes: Dictionary containing attribute name-value pairs
- children: Array of child elements (each following the same structure)
- text: String containing the text content, or
Noneif empty
Features
- XML Declaration Support: Automatically handles
<?xml version="1.0" encoding="UTF-8"?>declarations - Self-closing Tags: Properly parses elements like
<input type="text"/> - CDATA Support: Handles
<![CDATA[...]]>sections correctly - Comment Removal: Automatically strips XML comments during parsing
- Nested Elements: Full support for deeply nested XML structures
- Attribute Parsing: Handles both single and double-quoted attribute values
- Text Content: Preserves text content while handling mixed content scenarios
Type Conversion
The XML parser preserves the original string values from the XML:
- Attributes: All attribute values are treated as strings
- Text Content: Text content is preserved as strings
- Element Structure: Elements are represented as dictionaries with the standard structure