-
-
Notifications
You must be signed in to change notification settings - Fork 5
Metadata Transforms
Metadata transforms allow you to modify metadata values using the [%key:transform] syntax. Transforms can be chained together, and many accept optional parameters.
Metadata can come from three sources (merged in priority order):
-
Command-line:
--meta KEY=VALUE(highest priority) - Document: Metadata embedded in the document (YAML, MMD, or Pandoc format)
-
External file:
--meta-file FILE(lowest priority)
See Command Line Options for details on --meta-file and --meta flags.
The basic syntax is [%key:transform] where key is a metadata key and transform is one of the available transforms:
---
title: hello world
---
# [%title:upper]
<!-- Outputs: # HELLO WORLD -->Transforms can be chained using colons:
---
title: hello world
---
# [%title:title:split( ):first]
<!-- Outputs: # Hello -->Metadata transforms are enabled by default in unified mode. For other modes, use the --transforms flag:
apex document.md --transformsTo disable transforms (even in unified mode), use --no-transforms.
Converts the value to uppercase.
---
title: hello world
---
[%title:upper]
<!-- Outputs: HELLO WORLD -->Converts the value to lowercase.
---
title: HELLO WORLD
---
[%title:lower]
<!-- Outputs: hello world -->Converts the value to title case (capitalizes first letter of each word).
---
title: hello world
---
[%title:title]
<!-- Outputs: Hello World -->Capitalizes only the first letter of the value.
---
title: hello world
---
[%title:capitalize]
<!-- Outputs: Hello world -->Removes leading and trailing whitespace.
---
title: " hello world "
---
[%title:trim]
<!-- Outputs: hello world -->Converts the value to a URL-friendly slug (lowercase, spaces and special characters replaced with hyphens).
---
title: My Great Post!
---
[%title:slug]
<!-- Outputs: my-great-post -->Replaces occurrences of OLD with NEW. Supports both simple string replacement and regex patterns.
---
url: http://example.com
---
[%url:replace(http:,https:)]
<!-- Outputs: https://example.com -->Regex replacement:
---
text: Hello 123 World
---
[%text:replace(regex:[0-9]+,N)]
<!-- Outputs: Hello N World -->Extracts a substring. Supports negative indices (from end).
---
title: Hello World
---
[%title:substr(0,5)]
<!-- Outputs: Hello -->
[%title:substr(-5)]
<!-- Outputs: World (last 5 characters) -->Truncates the value to the specified length, optionally appending a suffix.
---
title: This is a very long title
---
[%title:truncate(15,...)]
<!-- Outputs: This is a very... -->Reverses the order of characters in the value.
---
text: Hello
---
[%text:reverse]
<!-- Outputs: olleH -->Splits a string into an array using the specified delimiter (default: space).
---
tags: tag1,tag2,tag3
---
[%tags:split(,)]
<!-- Outputs: tag1 (first element as representation) -->
<!-- Use with :first, :last, :slice, or :join to work with the array -->Joins an array into a string using the specified delimiter.
---
tags: tag1,tag2,tag3
---
[%tags:split(,):join( | )]
<!-- Outputs: tag1 | tag2 | tag3 -->Returns the first element of an array.
---
tags: tag1,tag2,tag3
---
[%tags:split(,):first]
<!-- Outputs: tag1 -->Returns the last element of an array.
---
tags: tag1,tag2,tag3
---
[%tags:split(,):last]
<!-- Outputs: tag3 -->Extracts a slice from an array. If applied to a non-array value, splits the string into individual characters.
---
tags: tag1,tag2,tag3
---
[%tags:split(,):slice(0,2):join(,)]
<!-- Outputs: tag1,tag2 -->
---
text: Hello
---
[%text:slice(0,5)]
<!-- Outputs: Hello (characters 0-5) -->Returns the specified default value if the metadata value is empty.
---
desc: ""
---
[%desc:default(No description)]
<!-- Outputs: No description -->Escapes HTML special characters (&, <, >, ", ').
---
title: A & B
---
[%title:html_escape]
<!-- Outputs: A & B -->Extracts the filename from a path.
---
image: /path/to/image.jpg
---
[%image:basename]
<!-- Outputs: image.jpg -->URL-encodes the value.
---
search: hello world
---
[%search:urlencode]
<!-- Outputs: hello%20world -->URL-decodes the value.
---
search: hello%20world
---
[%search:urldecode]
<!-- Outputs: hello world -->Adds a prefix to the value.
---
url: example.com
---
[%url:prefix(https://)]
<!-- Outputs: https://example.com -->Adds a suffix to the value.
---
title: Hello
---
[%title:suffix(!)]
<!-- Outputs: Hello! -->Removes all occurrences of the specified string.
---
title: Hello'World
---
[%title:remove(')]
<!-- Outputs: HelloWorld -->Repeats the value the specified number of times.
---
sep: -
---
[%sep:repeat(3)]
<!-- Outputs: --- -->Formats a numeric value using sprintf-style formatting.
---
price: 42.5
---
[%price:format($%.2f)]
<!-- Outputs: $42.50 -->Returns the length of the value as a string.
---
text: Hello
---
[%text:length]
<!-- Outputs: 5 -->Pads the value to the specified width with the specified character (default: space).
---
number: 42
---
[%number:pad(5,0)]
<!-- Outputs: 00042 -->Returns "true" if the value contains the specified string, "false" otherwise.
---
tags: javascript,html,css
---
[%tags:contains(javascript)]
<!-- Outputs: true -->Formats a date using strftime-style format strings. Parses dates in formats like YYYY-MM-DD, YYYY-MM-DD HH:MM, or YYYY-MM-DD HH:MM:SS.
---
date: 2024-03-15
---
[%date:strftime(%Y)]
<!-- Outputs: 2024 -->
[%date:strftime(%B %d, %Y)]
<!-- Outputs: March 15, 2024 -->Multiple transforms can be chained together using colons. Each transform operates on the result of the previous transform:
---
title: hello world
---
[%title:title:split( ):first]
<!--
1. title -> "Hello World"
2. split( ) -> ["Hello", "World"] (array)
3. first -> "Hello"
-->Example with dates:
---
date: 2024-03-15 14:30
---
[%date:strftime(%Y)]
<!-- Outputs: 2024 -->- Transforms are case-sensitive
- Array transforms (
split,join,first,last,slice) work together - usesplitto create an array, then apply other array transforms - The
slicetransform automatically converts non-array strings into character arrays if needed - Regex patterns in
replacesupport POSIX Extended Regular Expressions and can include character classes like[0-9]+ - Date parsing supports common formats but may not handle all date string formats
- Unknown transforms are ignored and return the original value
Copyright 2025 Brett Terpstra, All Rights Reserved | MIT License
- Getting Started - Your first steps with Apex
- Installation - How to build and install Apex
- Usage - Basic usage examples
- Syntax - Complete syntax reference for unified mode
- Tables - Complete table syntax reference including rowspan, colspan, alignment, and captions
- Inline Attribute Lists - IALs and ALDs guide with examples
- Modes - Understanding processor modes
- Command Line Options - All CLI flags explained
-
Rendering Markdown in the Terminal - Terminal output formats (
-t terminal,-t terminal256),--width,--theme, and theming -
Generating Man Pages - Generate man pages from Markdown using
apex -t man -
Multi-file Documents - Combining multiple files with
--combine,--mmd-merge, and includes - Citations - Citations and bibliography guide
- Indices - Index generation with mmark and TextIndex syntax
-
Metadata Transforms - Transform metadata values with
[%key:transform] - Integrating with Pandoc - Use Apex with Pandoc for DOCX, PDF, and more
- Using Apex with Jekyll - Use the apex-ruby gem as Jekyll’s Markdown converter (untested; feedback welcome)
- Header IDs - How header IDs are generated
- C API - Programmatic API documentation
- Writing Tests - How to add tests for new features
- Xcode Integration - Using Apex in Xcode projects
- Examples - Practical usage examples
- Plugins - Plugin system, examples, and recipes
- Filters - AST filters (Pandoc-style JSON), examples, and usage
- Troubleshooting - Common issues and solutions
- Credits - Acknowledgments and links to related projects