Converting a large collection of XML documents, especially XML with mixed content, can be a real challenge. In many cases, each individual change is relatively easy to understand, but the complications arise because of exceptions and interactions with other changes. And if the collection is large enough, the likelihood of finding out (too) late is high, which then requires costly repairs.
What we need is a framework that allows us to work with issues at the right granularity. This document walks through what that takes: the issue itself, revoke, specialisation, and a second opinion from an LLM.
An issue bundles a problem description, a match rule, a solution (a transform), and additional metadata. The match rule formally describes which documents are targeted. The solution is deterministic code that creates a new version of each document. The old version stays.
Finding issues in the content is a process that can involve domain experts, user reports, queries, etc. In 2026, we can also use LLMs to find issues. This is something that was impossible 10 years ago.
Before applying or running an issue against the content collection, it must be approved. This is non-negotiable. Testing it first is what makes that approval mean something. Thus, the issue is not just the unit of code but also the unit of administration.
Sometimes applying an issue will have unintended side effects. This could be because of a mistake in the transform, or because the original analysis of the issue was incomplete. In such cases, it is essential to be able to revoke the change.
For example, take the bold letters from the previous document. Suppose you wrote the merge rule, tested it, and ran it over the collection. Then someone reports an outlier: a comma sat between two of the bold letters, and the merge pulled it into the bold text. And it turns out this happened in more documents than that one.
You correct the rule so it stops at punctuation. Now you need to run it again on the documents that went wrong. But which documents are they? The XPath that found them looked for runs of single-letter vet elements. Those runs no longer exist: your own fix removed them.
In 2015, there were two ways out, and both were bad. You could fix the documents by hand, one by one, if you could find them. Or you could write a second XSLT that repairs the output of the first, with its own exceptions. That second road is how a pipeline becomes insanely complicated.
The better way out is to do a revoke: return the treated documents to their state from before the merge, and run the corrected issue from there. Going back also brings the handle back. In the earlier state, the runs of single-letter vet elements exist again, so the match rule finds them.
This doesn't come for free. A revoke needs infrastructure: every earlier state must still exist, and every change must be on record. And other issues may have been applied in the meantime, on the same documents. Going back past them undoes their work too, so a revoke needs a replay plan: which issues run again, in which order, and who approved that. However, this is good complexity to have. If we sort this out at the foundation level, we can build upon it.
In the example above, we corrected the issue's transform. But the problem was only ever in the documents with a comma. Correcting the whole transform means that every document the issue treated goes back and runs again, including the 80% that were fine.
The alternative is to specialise the issue. We keep the default transform unchanged, and add a second transform with a match rule that is a subset of the issue's match rule: runs of bold letters with punctuation in between. When the issue is applied, the specialisation's match rule is checked first. If it matches, the new code runs; otherwise it falls back to the default code.
Of course, XSLT can do this inside a single transform. That is what template priority is for. What matters is not where the code lives, but what happens to the collection. A specialisation added after the fact still needs a revoke to reach the documents that were already treated. But it only needs to revoke the subset it matches. The other 80% keep their state, untouched, and so does everything other issues have since built on top of them.
This is where it gets really interesting. Applying an issue produces one or more changed fragments. We know what the issue is supposed to do, because it has a description and code. So it is a small step to write one question and ask an LLM, for each change, whether the change did what it was supposed to do.
This is where a focus on small issues pays off. Smaller issues play much nicer with LLMs. The role of the LLM is still purely advisory, but a small, focused question generally means a higher chance of a good LLM judgement. Also, it enables us to use smaller, cheaper LLMs instead of relying fully on frontier models.
All of this rests on one thing: provenance. Every change is recorded. Nothing is overwritten. Every state a document has ever had can be recovered, along with who decided what, and why.
Provenance is what makes going back possible. But it does more than that. At the end of the project, someone will ask how you know the conversion did not change the meaning of a legal text. With provenance, the answer is not "trust us". It is the record of every issue, every test, every approval and every change, document by document.
This is becoming quite a brief: small issues, each approved before it runs; revoke and specialisation for the exceptions that turn up late; an LLM as a second opinion on every change; and provenance underneath it all.
That means combining a strong traditional foundation with a modern, LLM-driven environment. Luckily, the LLM is not just ready to advise on thorny coding questions; it can also help build that environment. Let's see what this looks like in the next document.
Do you hold a large XML collection, and have good reasons to put AI to work on it, but no safe way to begin? Here is how we would work together. It starts with an hour online, no charge: we look at your own documents, and you see the system running on them.