Rockwell L5X Import & Export (Studio 5000 Exchange)
June 2026 | ControlForge v1.0.1069
L5X is Rockwell Studio 5000's XML program-exchange format. ControlForge can import an L5X — converting its UDTs, Add-On Instructions, and program routines into Structured Text — and export a ControlForge program back out as an L5X download for round-tripping into Studio 5000. A third endpoint validates ST against the RLL (ladder-export) subset so you know up front whether a program will export cleanly to ladder.
There are no L5X_* ST functions — this is an HTTP-only project-exchange surface (tag l5x). Get a token first:
TOKEN=$(curl -s -X POST http://localhost:8302/api/auth/login \
-H 'Content-Type: application/json' \
-d '{"username":"goplc","password":"goplc"}' | python3 -c 'import sys,json;print(json.load(sys.stdin)["token"])')
Import an L5X
POST /api/l5x/import takes the raw L5X XML in a JSON body and converts it to ST. UDTs are loaded as a combined l5x_types library, each AOI as its own library, and every program routine as a ControlForge program. The converted project is saved as a side effect.
curl -s -X POST http://localhost:8302/api/l5x/import \
-H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
-d '{"content":"<?xml version=\"1.0\"?><RSLogix5000Content>...</RSLogix5000Content>"}'
To send a file from disk, fold it into the content field:
python3 -c 'import json,sys; print(json.dumps({"content": open(sys.argv[1]).read()}))' MyProgram.L5X \
| curl -s -X POST http://localhost:8302/api/l5x/import \
-H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' --data-binary @-
The response summarizes the conversion:
| Field | Meaning |
|---|---|
success | true when the L5X parsed and converted |
summary | Human-readable summary of what the L5X contained |
udts | Count of user-defined types loaded as the l5x_types library |
aois | Count of Add-On Instructions loaded as individual libraries |
programs | Count of program routines imported as ST programs |
warnings | Non-fatal conversion notes (unsupported constructs, load issues) |
errors | Conversion errors from the converter |
A body with no content returns 400 {"error":"content is required"}; an XML that won't parse returns 400 with the parse error. Always read warnings — a converted-but-lossy import lands its caveats there rather than failing.
Export a program as L5X
POST /api/l5x/export renders one ControlForge program to a Rockwell L5X and streams it back as an application/xml attachment. program is the program name (required); controller_name is an optional controller label written into the L5X.
curl -s -X POST http://localhost:8302/api/l5x/export \
-H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
-d '{"program":"Main","controller_name":"Line3"}' \
-o Main.L5X
On success you get the XML file (Content-Disposition: attachment; filename="Main.L5X"). The failure cases come back as JSON instead: missing program → 400, unknown program → 404 {"error":"Program 'X' not found"}, export failure → 400 with the reason.
Validate RLL (ladder-export) compatibility
POST /api/l5x/validate-rll checks whether ST source stays inside the RLL-compatible subset — the constructs that survive a clean export to ladder logic. Run it before exporting if the destination is ladder rather than ST routines.
curl -s -X POST http://localhost:8302/api/l5x/validate-rll \
-H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
-d '{"source":"PROGRAM Main\nVAR x : BOOL; END_VAR\nx := TRUE;\nEND_PROGRAM"}'
# → {"valid":true}
The result is:
| Field | Meaning |
|---|---|
valid | true when the source is fully RLL-compatible |
errors | Array of {line, message, hint} for unsupported constructs (omitted when none) |
warnings | Array of {line, message, hint} for constructs that export but lose fidelity |
A body with no source returns 400 {"error":"source is required"}; ST that won't parse returns 400 with the parse error. A valid:true with no errors means the program will export to ladder cleanly; entries in errors point at the exact lines to rework.
Notes & limits
- Import is destructive to the project state — it loads converted programs/libraries and saves. Take a snapshot first if you want to roll back.
- Export is one program at a time — pass a single
programname; there's no whole-project L5X export on this surface. - Validate before exporting to ladder. ST that's perfectly valid as a ControlForge program can still contain constructs RLL can't represent;
validate-rllis the gate, and itserrors[].hinttells you how to bring a line into the subset. - Conversion is best-effort, not bit-perfect. Studio 5000 and ControlForge are different runtimes — read
warningson import and treat the result as a starting point to review, not a guaranteed equivalent.