JSON & XML field converter
Paste a document, tell it which fields to rename or move, and take the converted result away. It reads JSON or XML and works out which one you gave it. The result you get back is always JSON.
Every bit of this happens inside your own browser. Nothing you paste, upload, copy or download is ever sent to us, before or after. There is nothing to buy and nothing to sign up for.
Detect Fields builds one row per field found in your document, JSON or XML, indented to show nesting up to three levels deep. Edit any Target field to rename it, or remove rows you do not need.
- Load a source. Paste or type JSON directly into the Source box, click Upload .json or .xml file to load a file from disk, or click Load Sample to load a working example you can experiment with before pointing the tool at your own data.
- Two ready-made addresses to test with, so you do not have to find a file of your own.
Both hold the very same made-up customer, one written each way, so you can run the same field changes
against both and compare what comes out:
easylifeagents.com/samples/customer.json— the JSON one.easylifeagents.com/samples/customer.xml— the XML one.
- XML is accepted in the same box. You are never asked which kind you have: if the first
real character is a
<it is read as XML, and otherwise as JSON. XML is turned into the same shape JSON would have had, by these rules, so that every mapping row below works identically either way. The outermost element is unwrapped, exactly as a JSON document's own outer braces are not a field name, so<person><city>London</city></person>gives you the pathcity, notperson.city. An element holding only text becomes that text. The same tag repeated under one parent becomes a list, in the order it appeared, so Detect Fields treats it exactly like a JSON array. An attribute becomes a field whose name starts with@, and text sitting next to attributes or child elements is kept under#text. A namespace prefix is dropped, sons:titleis addressed astitle. Every value arrives as text, because XML itself has no idea which of its values were meant to be numbers. Two things are refused outright rather than half-handled: a document beginning with aDOCTYPEline, which is the known way to attack a program that reads XML, and a document larger than two million characters, which your browser should not be asked to hold. A tag whose name contains a dot cannot be reached by a dot-path, which is a real limit of paths rather than of the reader. - Click Detect Fields From Source. This parses whatever is currently in the Source JSON
box and generates one mapping row per leaf it finds — a leaf being any field whose value isn't itself an
object or array worth expanding further. Rows are indented to show nesting depth, and detection stops at
depth 3 (the engine's own
MAX_DETECT_DEPTHconstant) — a leaf nested deeper than three levels is not expanded any further, and instead renders as a single row standing in for its entire remaining subtree. An array gets one extra row beyond its own leaves: a row for the array itself, since detection only samples the array's first element for its individual leaf rows, and keeping just those would silently drop every other element the array actually held. Keep that row to carry the whole array through to the output unchanged, keep the per-leaf rows for field-level renames within the sampled element, or keep both. - The Source field is pre-filled with the dot-path to that leaf, for example
address.geo.latfor a leaf three levels deep. It is a normal, editable text box, not a locked label: typing a different path into it changes which leaf that row actually reads from, the same way editing Target changes where the value is written. - The Target field is the dot-path the leaf will have in the output. Leaving it identical to the Source field is a no-op — the value passes through unchanged at the same path. Typing a bare key with no dot in it promotes that leaf to the root of the output, regardless of how deeply it was nested in the source. Typing a dotted path nests the value under that path in the output instead, and the engine builds any intermediate objects along that path that don't already exist.
- The Transform column controls how the value is written once its Target path has been
decided. Rename and Copy behave identically today — both perform a direct assignment of the source value
at the Target path, so the choice between them is purely about which label better describes your intent
for that row. Flatten requires the source value to be an object; when it is, every one of that object's
own keys is spread one level under the Target path instead of the object being copied as a whole — an
addressobject flattened to a Target offlatproducesflat.city,flat.zip, and so on for every key the source object held. Stringify runs the source value through a realJSON.stringify()call before writing the result to the Target path, which is useful when a downstream system expects a nested structure to arrive as one string field instead of as nested JSON. - If two rows end up targeting the same output path, the row that appears later in the list wins, and whatever the earlier row would have written is silently overwritten rather than merged. A row whose Source field does not match anything in the parsed JSON is skipped without raising an error, which means a mapping set built against one document also works, minus the missing rows, against a similar document that happens not to include every field.
- Click the small ✕ button on any row to remove it from the current mapping set. This only changes the mapping table — it never touches the Source JSON box, so you can always rebuild the full set from scratch by clicking Detect Fields From Source again. Click + Add Mapping to append one blank, unindented row for a mapping you would rather type by hand than have auto-detected.
- The Preview box re-renders automatically about 150 milliseconds after your most recent edit to any row. What it shows is the literal result of applying every mapping currently in the table to the parsed source, in row order, so it always reflects exactly what you would receive if you unlocked the result at that moment.
- There is nothing to buy to use this. Converting a document here is free, with no account, and with no limit on how many you convert. The work itself always did happen inside your own browser, and now the whole result is shown, copied and downloaded without paying for anything.
- What the $9.99 a month subscription adds, now that the tool itself is free. Two things, and both are about never building the same mapping twice. The first is Conversion Templates: save the mapping table you have just built under a real name, and it is waiting to be reopened and reused the next time the same shape of document arrives, instead of pressing Detect Fields and filling in every row again. The second is an address a program can call: a saved template can be run by your own computer, on a timer if you want one, sending a document and getting the converted result straight back, with no browser open and nobody sitting there. Both of those need the subscription, and both are checked on our own server every time they are used, never here in this page.
All reading, mapping and rendering runs entirely in your own browser. Nothing you type or upload here is ever sent anywhere.
What costs money, said plainly, so nothing here is a surprise. Converting a document on this page is free and always will be on this page. Two other things are not free, and both are about not doing this by hand every time.
Saving a template. A Conversion Template is the table of field changes you have just built, saved under a name so you can open it again next week instead of building it a second time. That needs the $9.99 a month subscription.
Calling it from a program. A saved template has its own address that your own computer can send a document to and get the converted result straight back, with no browser open and nobody sitting there — on a timer, if you want it to run at the same time every morning. That also needs the $9.99 a month subscription, and it is checked on our own server on every single call, not in this page.