XMLTX - XML Transaction Engine
A pure XML + XSLT web application framework with event sourcing
Architecture
- XML Database: All data stored in structured XML files
- XSLT Application Logic: Complete web app logic defined in XSL transforms
- Transactional XPath Updates: Append-only transaction log eliminates file locking and destructive rewrites
- Event Sourcing: All mutations logged to SQLite for replay, auditing, and rollback
- XPath Routing: URL paths become nested XML for elegant template matching
- Zero JavaScript: HTMX for dynamic interactions, semantic HTML + modern CSS
Framework Features
- Efficient XPath Updates: Instead of locking files for destructive rewrites, append precise XPath-based mutations to transaction log
- Semantic Update Operations:
x:put,x:rm,x:mvprovide clear, reversible operations with surgical precision - Nested Route Matching:
/films/123/edit→<route><films><n123><edit/></n123></films></route> - Template Pattern Matching:
route[films/*],route[admin/settings] - Real XML Mutations: Mutations contain actual XML elements, not escaped text strings
- Lock-Free Concurrency: Multiple processes can append mutations simultaneously without blocking
- Clean Architecture: 60 lines of PHP runtime + XSLT transforms
Usage
require_once 'xmltx.php';
$app = new XMLTX('data.xml');
$app->handleRequest();
XSLT Application Logic
The entire web application is defined in XSLT templates. The framework builds a combined XML document containing your data plus HTTP request information:
festival
films
film id "film-1"
title
The Vanishing Coast
director
Anna Bergman
http:request
method
GET
uri
/films/film-1
path
/films/film-1
route
films segment "films"
n1 segment "film-1"
Your XSL templates match routes and generate responses:
xsl:stylesheet version "1.0"
xsl:template match "/"
response
xsl:choose
xsl:when test "$method = 'POST'"
xsl:apply-templates select "$post" mode "post"
xsl:otherwise
xsl:apply-templates select "$request/route" mode "get"
xsl:template match "route[films/*[not(edit)]]" mode "get"
xsl:variable name "id" select "films/*/@segment"
xsl:variable name "film" select "//film[@id=$id]"
html
head
title
xsl:value-of select "$film/title"
body
h1
xsl:value-of select "$film/title"
p
Director:
xsl:value-of select "$film/director"
xsl:template match "post[action='add-film']" mode "post"
x:put target "//films" swap "beforeend"
film id "film-{generate-id()}"
title
xsl:value-of select "title"
director
xsl:value-of select "director"
Key concepts:
- Nested Routes: URL segments become XML elements for pattern matching
- Template Modes:
mode="get"for pages,mode="post"for actions - XPath Data Access:
//film[@id=$id]queries your data directly - Mutation Generation: Templates output
x:put,x:rm,x:mvfor updates - HTML Response: Templates generate XHTML that framework converts to HTML
Routing System
Common routing patterns and their XSLT templates:
templates
xsl:template match "route[root]" mode "get"
html
body
h1
Welcome
xsl:template match "route[films[not(*)]]" mode "get"
html
body
h1
All Films
xsl:for-each select "//film"
p
xsl:value-of select "title"
xsl:template match "route[films/*/edit]" mode "get"
html
body
h1
Edit Film
form method "post" action "/films/{films/*/@segment}"
input name "action" value "update-film" type "hidden"
input name "title" placeholder "Film Title"
button type "submit"
Update
Route matching patterns:
route[root]→/route[films[not(*)]]→/films(no children)route[films/*[not(edit)]]→/films/123(has child, not edit)route[films/*/edit]→/films/123/edit(has edit child)route[admin/settings]→/admin/settings
XML Mutations
Templates generate XML mutations for data updates:
mutations
x:put target "//films" swap "beforeend"
film id "film-new"
title
New Documentary
director
Jane Smith
duration
95
x:put target "//film[@id='film-1']/title" swap "outerHTML"
title
Updated Title
x:rm target "//film[@id='film-old']"
x:mv target "//film[@id='film-2']" destination "//archive"
Mutation operations:
x:put: Insert or replace content withswapattributesx:rm: Remove elements matching XPath targetx:mv: Move elements to new location- Transactional: All mutations logged to SQLite transaction log
- Reversible: Full audit trail and rollback capability
Why XMLTX?
- No File Locking: Concurrent updates via append-only transaction log
- Surgical Precision: XPath targets exact elements for updates
- Event Sourcing: Complete history of all data changes
- Template Pattern Matching: Elegant routing with XSLT patterns
- XML-First: Leverage XML's structure for application logic
- Minimal Runtime: 60 lines of PHP, everything else in XSLT