# XML to CSV and Excel Converter (`automation-lab/xml-to-csv-excel-converter`) Actor

Flatten XML text, uploaded files, and public XML URLs into CSV- and Excel-ready rows with record selection, namespaces, attributes, nested fields, columns, and parse errors.

- **URL**: https://apify.com/automation-lab/xml-to-csv-excel-converter.md
- **Developed by:** [Stas Persiianenko](https://apify.com/automation-lab) (community)
- **Categories:** Developer tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per event

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/platform/actors/running/actors-in-store#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## XML to CSV and Excel Converter

Turn XML documents into clean, spreadsheet-ready rows without maintaining a conversion script.
This **XML to CSV converter** accepts pasted XML, uploaded files, public XML URLs, and mixed batches.
It detects repeated records or follows your chosen record-node path, then flattens attributes and nested values into dataset columns.

The default Apify dataset can be downloaded as CSV, Excel, JSON, XML, and other supported formats.
The same rows are available through the Dataset API for scheduled pipelines.

### What does this XML converter do?

For each source, the Actor:

1. validates the XML before conversion;
2. selects records from `recordPath`, or detects the first repeated object node;
3. optionally removes namespace prefixes;
4. includes or excludes XML attributes;
5. flattens nested elements into columns;
6. joins repeated scalar values;
7. applies an ordered column list when supplied;
8. saves successful records to the default dataset; and
9. saves a diagnostic error row when one source cannot be parsed or downloaded.

Valid sources continue even when another source in the same batch fails.
A run in which every source fails exits with a non-zero status.

### Who is it for?

- **Analysts** converting vendor or ERP XML exports before opening them in Excel.
- **Data engineers** normalizing XML feeds for warehouses, ETL tools, or scheduled imports.
- **Operations teams** turning recurring catalog, inventory, order, or report files into stable columns.
- **Developers** who need an API-based XML to CSV conversion step without hosting parser code.
- **Automation builders** connecting XML-producing systems to Make, Zapier, webhooks, or Apify schedules.

### Why use this Actor?

Unlike a one-off browser converter, the Actor supports repeatable runs, mixed batches, schedules, API access, and dataset integrations.
You can control the row node and output columns instead of accepting an opaque automatic mapping.
Source metadata stays attached to every row, which helps trace batch results.

No browser or proxy is used.
Conversion happens in the Actor container, while public or uploaded files are downloaded directly over HTTP or HTTPS.

### Supported XML inputs

Choose any combination of these routes:

| Input route | Best for |
| --- | --- |
| `xmlText` | One pasted document or an API request containing XML |
| `xmlFile` | One file uploaded through Apify Console or a public file URL |
| `xmlUrls` | Several public XML files in one run |
| `sources` | A named mixed batch of inline XML and public URLs |

Each object in `sources` must contain exactly one of `xml` or `url`.
Use `name` to give its output rows a recognizable `_sourceName`.

Public downloads are limited to 20 MB per source.
Only HTTP and HTTPS URLs that resolve to public addresses are accepted.
Authenticated URLs, embedded URL credentials, local hosts, and private network addresses are not supported.

### Select the XML nodes that become rows

Set `recordPath` to a dot- or slash-separated path such as:

```text
catalog.product
orders/order
feed.entries.entry
```

When namespace removal is enabled, use names without prefixes.
For example, `erp:orders/erp:order` becomes `orders.order`.

If `recordPath` is blank, the Actor selects the first repeated object node it finds.
If there is no repeated object node, the root value becomes one row.
For production pipelines, set `recordPath` explicitly so a source-structure change cannot alter row selection silently.

### Flatten attributes, nested fields, and arrays

With the default settings, this XML:

```xml
<product sku="P-100">
  <name>Travel Mug</name>
  <price currency="USD">18.5</price>
  <tags>
    <tag>travel</tag>
    <tag>kitchen</tag>
  </tags>
</product>
```

produces columns like:

```json
{
  "@sku": "P-100",
  "name": "Travel Mug",
  "price.@currency": "USD",
  "price.#text": 18.5,
  "tags.tag": "travel | kitchen"
}
```

Change `attributePrefix`, `nestedSeparator`, or `arraySeparator` to match your downstream naming convention.
Set `includeAttributes` to `false` when attributes are not needed.

### Keep a stable column set

Use `columns` to define the order and names of XML-derived columns:

```json
{
  "columns": [
    "@id",
    "customer.name",
    "customer.region",
    "total.@currency",
    "total.#text"
  ]
}
```

A missing selected value becomes `null`.
Leaving `columns` empty preserves every detected flattened field.
Names beginning with `_` are reserved for source metadata and cannot be selected as XML columns.

### Input parameters

| Field | Type | Default | Description |
| --- | --- | --- | --- |
| `xmlText` | string | — | One inline XML document |
| `xmlFile` | string | — | Uploaded file URL or public XML URL |
| `xmlUrls` | string\[] | `[]` | Public XML files to process |
| `sources` | object\[] | `[]` | Named objects containing exactly one `xml` or `url` |
| `recordPath` | string | automatic | Dot or slash path to the node used as each row |
| `maxRows` | integer | `1000` | Successful-row limit across all sources, from 1 to 100,000 |
| `removeNamespaces` | boolean | `true` | Remove prefixes such as `ns:` from element and attribute names |
| `includeAttributes` | boolean | `true` | Include XML attributes as flattened columns |
| `attributePrefix` | string | `@` | Prefix applied to attribute names |
| `nestedSeparator` | string | `.` | Separator used in nested column names |
| `arraySeparator` | string | `|` | Separator used for repeated scalar values |
| `columns` | string\[] | `[]` | Optional ordered output column list |

At least one XML source is required.

### Output fields

XML-derived fields vary by document.
Every row also includes these stable metadata fields:

| Field | Meaning |
| --- | --- |
| `_sourceName` | Input label or generated source name |
| `_sourceType` | `text`, `file`, or `url` |
| `_sourceUrl` | Download URL, otherwise `null` |
| `_recordPath` | Selected or detected row path |
| `_recordIndex` | One-based row number within the source |
| `_error` | Parse or download error, otherwise `null` |

Error rows contain metadata and `_error`, have a null `_recordIndex`, and are not charged as converted items.

### Example output

```json
{
  "@sku": "P-100",
  "name": "Travel Mug",
  "category": "Kitchen",
  "price.#text": 18.5,
  "price.@currency": "USD",
  "_sourceName": "Inline XML",
  "_sourceType": "text",
  "_sourceUrl": null,
  "_recordPath": "catalog.product",
  "_recordIndex": 1,
  "_error": null
}
```

Open the default dataset to download all dynamic XML columns.
The overview view focuses on source metadata and errors.

### How much does it cost to convert XML to spreadsheet rows?

Pricing has two parts: one `start` event per run and one `item` event per successfully converted row.
Error rows have no item charge.
The current event prices and volume tiers are shown in Apify Console before every run.

At the Bronze rate of **$0.00005 per run plus $0.00018 per converted row**:

| Successful rows | Example cost |
| ---: | ---: |
| 10 | $0.00185 |
| 100 | $0.01805 |
| 1,000 | $0.18005 |

Larger usage tiers reduce the per-row price.
Actual charges follow the active pricing shown on the Actor page; the examples exclude unrelated platform storage or compute charges that may apply under your Apify plan.

### Get started

1. Open the Actor in Apify Console.
2. Paste XML into **XML text**, upload a file, or add public XML URLs.
3. Leave **Record node path** blank for automatic detection, or set an explicit path.
4. Adjust namespace, attribute, and flattening options.
5. Add `columns` if your spreadsheet import requires a stable schema.
6. Set `maxRows` for the run.
7. Click **Start**.
8. Open the default dataset and export it as CSV or Excel.

The prefilled catalog input is ready to run and returns two product rows.

### Schedule recurring XML to CSV conversion

Create an Apify Schedule using the same input whenever a public XML feed updates.
Explicit `recordPath` and `columns` settings keep the destination schema stable between runs.

Common workflows include:

- nightly supplier catalog conversion;
- weekly inventory or price imports;
- recurring ERP order extracts;
- XML feed normalization before warehouse loading; and
- conversion followed by dataset webhooks.

For change detection, pass the resulting exports to a downstream comparison step rather than treating the converter itself as a monitoring service.

### Integrations

The default dataset works with:

- Apify schedules and webhooks;
- Make and Zapier;
- Google Sheets and Microsoft Excel exports;
- Python, JavaScript, or shell scripts using the Dataset API;
- cloud storage and database loaders; and
- Apify's MCP server.

Use `_sourceName` and `_sourceUrl` to preserve lineage when merging several inputs.

### Run with the API using cURL

Replace `YOUR_APIFY_TOKEN` with your token:

```bash
curl -X POST \
  "https://api.apify.com/v2/acts/automation-lab~xml-to-csv-excel-converter/runs?token=YOUR_APIFY_TOKEN&waitForFinish=300" \
  -H "Content-Type: application/json" \
  -d '{
    "xmlText": "<catalog><item id=\"1\"><name>Sample item</name></item></catalog>",
    "recordPath": "catalog.item",
    "maxRows": 100
  }'
```

Read the run's `defaultDatasetId`, then request `/v2/datasets/DATASET_ID/items?format=csv` or `format=xlsx`.

### Run with JavaScript

```javascript
import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('automation-lab/xml-to-csv-excel-converter').call({
    xmlUrls: ['https://www.w3schools.com/xml/plant_catalog.xml'],
    recordPath: 'CATALOG.PLANT',
    columns: ['COMMON', 'BOTANICAL', 'ZONE', 'PRICE'],
    maxRows: 100,
});

const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items);
```

### Run with Python

```python
import os
from apify_client import ApifyClient

client = ApifyClient(os.environ["APIFY_TOKEN"])
run = client.actor("automation-lab/xml-to-csv-excel-converter").call(run_input={
    "xmlText": "<orders><order id='1'><total>42</total></order></orders>",
    "recordPath": "orders.order",
    "columns": ["@id", "total"],
})

items = client.dataset(run["defaultDatasetId"]).list_items().items
print(items)
```

### Use with MCP and AI assistants

Add this Actor to Claude Code:

```bash
claude mcp add --transport http apify \
  "https://mcp.apify.com?tools=automation-lab/xml-to-csv-excel-converter"
```

#### Claude Desktop, Cursor, and VS Code setup

Claude Desktop, Cursor, and VS Code can use this MCP configuration:

```json
{
  "mcpServers": {
    "apify": {
      "url": "https://mcp.apify.com?tools=automation-lab/xml-to-csv-excel-converter"
    }
  }
}
```

Example prompts:

- “Convert this product XML into rows and keep SKU, name, category, and price columns.”
- “Download this public XML feed, use `catalog.item` as the record path, and return 500 rows.”
- “Flatten these namespaced order documents and explain any parse-error rows.”

Never place secrets or private authenticated URLs in prompts sent to an AI assistant.

### Limits and failure behavior

- Each downloaded file is limited to 20 MB.
- A run returns at most 100,000 successful rows.
- Public URL downloads time out after 30 seconds per attempt.
- Network failures, HTTP 429, and HTTP 5xx responses receive bounded retries.
- Stable client errors are not retried.
- DTD validation and XSD schema validation are not provided.
- The Actor does not fetch authenticated, private-network, FTP, or local files.
- Complex mixed-content XML is flattened according to the parser's object representation.
- Repeated objects become indexed nested columns when they are inside, rather than equal to, the selected record node.
- Automatic record detection chooses the first repeated object node; use `recordPath` when ambiguity matters.

A failed source writes an error row so batch diagnostics remain inspectable.
When all sources fail, the run also exits non-zero.

### Legality and responsible use

Only process XML that you are authorized to access and transform.
Respect source terms, privacy rules, retention requirements, and intellectual-property rights.
Do not use signed file URLs beyond their intended audience or lifetime.

The Actor does not need source credentials and rejects URLs with embedded credentials.
Apify stores run inputs and datasets according to your platform storage settings, so choose retention settings appropriate for sensitive business exports.

### Troubleshooting

**Why did I get “record path was not found”?**

Check capitalization and namespace handling.
XML names are case-sensitive.
When `removeNamespaces` is enabled, omit prefixes from the path.
Run once without `recordPath` and inspect `_recordPath` to see the automatically detected value.

**Why are my desired fields missing?**

Remove `columns` to inspect every detected field, then copy the exact flattened names into your ordered list.
Attributes use `attributePrefix`, and element text paired with attributes commonly appears under `#text`.

**Why is there one row instead of many?**

The selected node may be the container rather than the repeated child.
For `<orders><order>...</order></orders>`, use `orders.order`, not `orders`.

**Why did a URL fail?**

Confirm it is a public HTTP or HTTPS URL, resolves to public addresses, returns the XML directly, is no larger than 20 MB, and does not require cookies or login.
The `_error` field contains the specific download or parse message.

### Frequently asked questions

**Does it create a physical `.csv` or `.xlsx` file?**

The Actor writes normalized rows to the default Apify dataset.
Use the dataset Export button or API format parameter to download CSV or Excel, avoiding duplicate stored output files.

**Can I convert several XML documents in one run?**

Yes. Use `xmlUrls` or `sources`, and use meaningful source names for lineage.

**Are parse errors charged as items?**

No. Error rows are preserved for diagnosis but only successfully converted rows emit the `item` charge event.

**Can I preserve namespace prefixes?**

Yes. Set `removeNamespaces` to `false`, then use prefixed element names in `recordPath` and columns.

**Can I choose my own delimiter?**

Yes. `nestedSeparator` controls nested column names and `arraySeparator` controls repeated scalar values.
The final CSV delimiter is selected when exporting the Apify dataset.

### Related automation-lab Actors

- [XML JSON Converter](https://apify.com/automation-lab/xml-json-converter) for bidirectional XML and JSON conversion.
- [JSON to CSV Converter](https://apify.com/automation-lab/json-to-csv-converter) when the source format is already JSON.
- [CSV Diff Tool](https://apify.com/automation-lab/csv-diff-tool) for comparing two tabular exports after conversion.

### Support

If a valid XML structure does not flatten as expected, include a small anonymized XML sample, the input options, and the expected row columns in your Apify issue.
Remove personal data, credentials, private URLs, and confidential business values before sharing a sample.

# Actor input Schema

## `xmlText` (type: `string`):

Paste one XML document. Use Sources for multiple inline documents.

## `xmlFile` (type: `string`):

Upload an XML file or provide its public URL. Files are limited to 20 MB.

## `xmlUrls` (type: `array`):

Public HTTP or HTTPS URLs of XML files to convert in one run.

## `sources` (type: `array`):

Optional mixed batch. Each object needs exactly one of xml or url; name is used in output metadata.

## `recordPath` (type: `string`):

Optional dot or slash path to each row, for example catalog.book or orders/order. Leave blank to select the first repeated object node automatically.

## `maxRows` (type: `integer`):

Maximum successful rows across all XML sources. Error rows do not count toward this limit.

## `removeNamespaces` (type: `boolean`):

Turn names such as ns:order into order so record paths and column names are easier to use.

## `includeAttributes` (type: `boolean`):

Include attributes as columns using the configured attribute prefix.

## `attributePrefix` (type: `string`):

Prefix for attribute columns, for example @ turns id="42" into @id.

## `nestedSeparator` (type: `string`):

Separator used in flattened columns such as customer.name.

## `arraySeparator` (type: `string`):

Separator used when one XML field contains several scalar values.

## `columns` (type: `array`):

Optional ordered list of flattened column names. Missing values become null; omit this list to keep every detected column.

## Actor input object example

```json
{
  "xmlText": "<catalog><book id=\"bk-101\"><title>Practical Data Pipelines</title><price currency=\"USD\">29.95</price></book><book id=\"bk-102\"><title>XML in Practice</title><price currency=\"USD\">24.50</price></book></catalog>",
  "xmlUrls": [],
  "sources": [],
  "maxRows": 20,
  "removeNamespaces": true,
  "includeAttributes": true,
  "attributePrefix": "@",
  "nestedSeparator": ".",
  "arraySeparator": " | ",
  "columns": []
}
```

# Actor output Schema

## `dataset` (type: `string`):

Open the default dataset to export the rows as CSV, Excel, JSON, XML, or other supported formats.

## `overview` (type: `string`):

Open the source metadata and error overview.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "xmlText": "<catalog><book id=\"bk-101\"><title>Practical Data Pipelines</title><price currency=\"USD\">29.95</price></book><book id=\"bk-102\"><title>XML in Practice</title><price currency=\"USD\">24.50</price></book></catalog>",
    "maxRows": 20
};

// Run the Actor and wait for it to finish
const run = await client.actor("automation-lab/xml-to-csv-excel-converter").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "xmlText": "<catalog><book id=\"bk-101\"><title>Practical Data Pipelines</title><price currency=\"USD\">29.95</price></book><book id=\"bk-102\"><title>XML in Practice</title><price currency=\"USD\">24.50</price></book></catalog>",
    "maxRows": 20,
}

# Run the Actor and wait for it to finish
run = client.actor("automation-lab/xml-to-csv-excel-converter").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "xmlText": "<catalog><book id=\\"bk-101\\"><title>Practical Data Pipelines</title><price currency=\\"USD\\">29.95</price></book><book id=\\"bk-102\\"><title>XML in Practice</title><price currency=\\"USD\\">24.50</price></book></catalog>",
  "maxRows": 20
}' |
apify call automation-lab/xml-to-csv-excel-converter --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,automation-lab/xml-to-csv-excel-converter"
        }
    }
}

```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/9kx7dfko1p8l5Dm5P/builds/v7fUI0GeWFnWRLvj5/openapi.json
