This engagement is under NDA. We were subcontracted by another agency, so we cannot name them or the council. The end client was a UK local authority moving off Adobe Experience Manager onto LocalGov Drupal, the open-source distribution used by councils.
The problem
AEM does not speak Drupal. Content came out as XML, not as entities LocalGov could use. A straight migrate source against AEM would have mixed parsing, mapping and Drupal entity creation in one brittle step. Councils also need LocalGov's content model (pages, services, directories, news) rather than a generic dump of whatever AEM happened to store.
Two-stage import
We wrote custom Drupal modules to read the AEM XML and load it into middleware database tables on Drupal: a staging layer we controlled, with the XML broken into rows we could inspect, re-run and fix without touching the live LocalGov site.
From those tables, Drupal's Migrate API pulled the data into LocalGov. Migrate owned the mapping to LocalGov content types and entities, rollbacks, and updates. The custom modules owned getting AEM out of XML and into SQL. Each layer did one job.
Why middleware tables
AEM XML is rarely a clean 1:1 with LocalGov fields. Staging it in Drupal tables meant we could normalise structure, catch bad records, and re-run Migrate without parsing the export again. It also kept the LocalGov site itself closer to a standard distribution: the messy extract lived in the pipeline, not in one-off hacks on the council CMS.
Outcome
The council's content moved from Experience Manager into LocalGov Drupal through a pipeline the agency could run: XML in, tables in the middle, Migrate into LocalGov. We cannot show the site or name the authority.

