Worked example

CSV to XML content conversion, step by step

CSV to XML is the job most people are actually configuring content conversion for. This walks a real file through it: the source, the recordset structure that parses it, and the XML you should expect on the other side.

CSV to XML is the conversion most interfaces actually need, and it is a good one to learn the parameters on because the failure modes are visible. Here is the whole thing: a source file, the configuration that parses it, and the XML that comes out.

The source file

A typical order export, comma-separated, with a header row:

orderId,customer,sku,qty,price
1001,ACME,BR-220,4,19.90
1002,Globex,BR-221,1,24.50
1003,Initech,BR-222,12,8.75

Four things about this file drive the configuration: it is comma-delimited, it is line-terminated, the first line is a header rather than data, and there is exactly one kind of record.

Configuring the channel

In the sender file adapter channel, with content conversion enabled:

  • Document Offset: 1 — skip the header row.
  • Recordset Structure: Order,* — one node, repeating without limit.
  • Order.fieldSeparator: ,
  • Order.endSeparator: nl
  • Order.fieldNames: orderId,customer,sku,qty,price

Nothing else is needed for this file. There is no key field, because there is only one record type — a key field becomes mandatory only once a node has unlimited cardinality and the file mixes structures.

The field names are supplied in the configuration rather than read from the header row on purpose. A header row is a line of the file that the sending system can change without telling you, and when it does, the element names in your XML change with it and the mapping fails downstream. Naming them explicitly costs one line of configuration.

The XML you should get

The adapter produces one element per record, with the field names as child elements. The root is whatever the Recordset Name is set to — Recordset unless you change it.

<Recordset>
  <Order>
    <orderId>1001</orderId>
    <customer>ACME</customer>
    <sku>BR-220</sku>
    <qty>4</qty>
    <price>19.90</price>
  </Order>
  <Order>
    <orderId>1002</orderId>
    <customer>Globex</customer>
    <sku>BR-221</sku>
    <qty>1</qty>
    <price>24.50</price>
  </Order>
  <!-- ... -->
</Recordset>

Two things worth noticing. Every value is a string — qty is not a number and price is not a decimal, because a flat file has no types to carry across. Typing is mapping work, and it happens after this step.

And the element names are exactly the names you configured. They are a contract with the mapping, not a description of the file, which is why they deserve a moment's thought before go-live rather than after.

When fields are quoted

Real CSV quotes fields that contain the delimiter. Consider a customer named "Smith, John":

1004,"Smith, John",BR-223,2,15.00

With no enclosure configured, the adapter splits on every comma and this record yields six fields instead of five — "Smith and  John" in place of one customer, and everything after it shifted by one position. The record still parses cleanly, which is what makes this one expensive: the XML is well-formed, the mapping runs, and the error appears as wrong values in the target system.

The fix is the enclosure parameters — enclosureSign, and the escape setting for a quote inside a quoted field. They are covered in the parameter reference.

Worth deciding early: a file that has never contained a quoted field can start containing one the first time somebody's name has a comma in it.

Line endings

A CSV written on Windows ends its lines with \r\n; one written on Unix uses \n. They look identical in most editors, which is the problem.

Configure endSeparator as nl and you are usually fine, because it handles the newline. But if the carriage return is not accounted for, it stays attached to the final field of each record — so price holds 19.90\r rather than 19.90. It displays normally and fails any comparison, lookup or numeric conversion downstream.

If the last field of every record misbehaves and the others are fine, this is why. Compare the raw bytes rather than the rendered text.

Encoding and the BOM

The adapter's encoding setting has to match the file, not the other way round. UTF-8, ISO-8859-1 and platform-specific character sets produce different results from the same configuration, and non-ASCII characters are where it shows: accented letters arrive as mojibake, or the conversion fails outright on a byte it cannot map.

Watch for a byte order mark. A UTF-8 file saved with a BOM begins with three bytes that are invisible in an editor but become part of the first field name — so the first element in your XML has a name that looks correct and does not match the mapping.

Verifying before go-live

Test with a real file from the sending system, not a hand-written sample. Then check:

  • The first element name, for a BOM.
  • The last field of each record, for a trailing carriage return.
  • A record containing a quoted field, for correct field counts.
  • A record with an empty field in the middle, to confirm it is preserved rather than dropped.
  • A file larger than anything you tested with, to see where it stops working.

Most of what goes wrong in production is in that last bullet or the encoding setting — not in the mapping. When something does fail, the error guide works through what each symptom means.

FAQ

Questions, answered

How do I convert CSV to XML in SAP PI/PO?

Enable content conversion in the sender file adapter channel, set the Recordset Structure to a repeating node, set fieldSeparator to a comma and endSeparator to nl, and name the fields. The adapter builds XML from that description as the file is read — no mapping is involved at this stage.

How do I skip the header row of a CSV file?

Set Document Offset to 1. The adapter skips that many lines from the top of the file before it starts parsing records, so the column labels never reach the XML.

Why does the last field of every record have an invisible character?

The file uses Windows line endings (\r\n) but the end separator is configured as \n, so the carriage return stays attached to the final field. Set the end separator to match the file, or normalise the file before it arrives.

Why does a CSV field containing a comma break the conversion?

The field is quoted in the source, but the adapter has no enclosure configured, so it splits on the comma inside the quotes and every later field in that record shifts one position. Configure enclosureSign and its escape variant.

Should I rely on the header row for field names?

Usually not. It makes the conversion depend on a line of the file that a sender can change without telling you. Naming the fields explicitly in the configuration is more work once and considerably less work later.