Blog

Supplier Catalog File Formats in Practice: CSV, Excel, BMEcat and cXML Compared

How CSV, Excel, BMEcat and cXML catalog files actually differ in structure and failure modes, and which one shows up depending on who's asking and what system receives it.

SupplierForge team

Ask five procurement teams what format they want a supplier’s catalog in and there’s a real chance you get five different answers. Unlike PunchOut, where the wire protocol at least narrows down to a small number of well-defined standards, catalog file formats sprawl across flat files, spreadsheets, and two competing XML standards that solve overlapping problems in different ways. Some of this variety comes from genuine differences in what a buyer’s system needs; a lot of it comes from how each format was designed for a different era and a different classification convention and just never got fully displaced. Suppliers sending catalog data via EDI face a related but distinct version of this problem (BoreaTech’s primer on what EDI procurement is covers that channel on its own terms); this guide stays on the file formats a catalog itself gets packaged into: CSV, Excel, BMEcat, and cXML’s catalog document, what each one actually looks like, where each breaks, and where a live PunchOut session replaces the need for a file at all.

What suppliers actually send

In practice, a catalog arrives in whatever format the receiving system’s ingestion path was built to accept, which is rarely a single answer even within one buyer’s organization. A flat CSV or Excel file remains the most common vehicle for a straightforward item list (SKU, description, unit of measure, price, classification code, one row per item) because almost every system on either end can produce and consume it without custom tooling. Buyers running EDI-based procurement instead expect catalog content inside a structured EDI transaction, commonly an X12 832 Price/Sales Catalog or an EDIFACT PRICAT message, which carries the same underlying fields as a flat file but wrapped in EDI’s segment-and-element syntax and typically moved over a dedicated EDI network rather than emailed or uploaded through a portal. Buyers running SAP-centric procurement in Germany, Austria or Switzerland frequently expect BMEcat specifically, and buyers on a cXML-based platform like Ariba may accept a cXML-formatted catalog file as an alternative to a live PunchOut connection. None of these is a supplier’s free choice: the format is set by whatever the buyer’s system was configured to ingest, and a supplier serving several buyers on several platforms should expect to maintain several of these in parallel rather than standardizing on one. Handling that fan-out is largely what a catalog ingestion layer needs to absorb; see how catalog ingestion fits into the rest of the pipeline for how the different input channels connect to what happens after a file arrives.

CSV and the delimiter and encoding traps

CSV’s appeal is that it’s the lowest common denominator: a spreadsheet, a database export, and a hand-written script can all produce it, and nearly every ingestion system can read it. The trouble is that “CSV” describes a loose family of conventions rather than one fixed format, and the gaps between conventions are exactly where catalog uploads fail.

The delimiter itself isn’t universal. A spreadsheet application exporting CSV under a locale where the comma is the decimal separator, much of continental Europe, defaults to a semicolon as the field delimiter instead, so a file a German supplier calls “CSV” and a file a US supplier calls “CSV” can use two different characters to separate columns, and a parser hard-coded to split on commas will read the semicolon-delimited file as one giant column per row. Quoting compounds this: a description field containing a comma needs to be wrapped in quotes for a comma-delimited file to parse correctly, and a literal quotation mark inside a quoted field needs to be escaped by doubling it under the RFC 4180 convention: a rule most spreadsheet exports follow automatically and most hand-written export scripts get wrong at least once.

Encoding is the second recurring trap, and it’s largely invisible to the person generating the file. A CSV saved as UTF-8 with a leading byte-order mark reads correctly in most modern tools but can show a stray  character prepended to the first header name in a parser that doesn’t strip it, silently breaking any code matching on an exact header string. A file saved under a legacy encoding like Windows-1252 instead of UTF-8 will render correctly in the spreadsheet program that produced it and then mangle any accented or non-Latin character (a supplier name with an umlaut, a unit description with a degree symbol) into garbled bytes the moment it’s read by a system that assumes UTF-8. Both failures look identical from the sender’s side: the file opens fine, looks fine, and the sender has no way to see that a receiving system 2,000 miles away is about to choke on it.

sku,description,uom,unit_price,currency,unspsc
WDG-1002,"Widget, 3in, stainless",EA,4.75,USD,31161701
WDG-1003,"Bracket, heavy-duty, zinc-plated",EA,11.20,USD,31161701

That looks unremarkable, and it is, until the delimiter, quoting, or encoding assumption on one side doesn’t match the assumption on the other. (The classification codes in this and later examples are illustrative placeholders, not verified real-world UNSPSC lookups.)

Excel and why merged cells break ingestion

A spreadsheet file carries more structure than CSV, which is precisely why it introduces failure modes CSV doesn’t have. The most common one is the merged cell: when a value is merged across a range of cells for visual tidiness (a category header spanning several columns, or a supplier name merged down a block of rows) most spreadsheet libraries used to read the file programmatically store that value only in the top-left cell of the merged range. Every other cell in the range reads back as empty. A human looking at the spreadsheet sees the value appearing to span the whole block; a parser reading it row by row sees the value once and blank everywhere else, which for a column like unit of measure or classification code produces a catalog where most items appear to have no value at all in that field.

Formulas cause a related but different problem. A price column computed from a base cost and a markup percentage displays a number in Excel, but the underlying cell contains a formula string, not a static value, and a parsing library that reads the raw cell content rather than the last-calculated result can pull back the formula text itself instead of the number it evaluates to. Auto-formatting causes a third: Excel’s default type inference treats a long, digit-only part number as a number rather than text, which can silently drop leading zeros, or worse, render an especially long numeric-looking identifier in scientific notation, permanently losing precision the moment the file is saved: a 16-digit ID becomes 1.23457E+15, and there is no straightforward way to recover the original digits from that string. A part number written as 3-15 can be auto-converted into a date. None of these show up as errors in Excel itself; they show up as corrupted values in whatever system reads the file next.

Two more Excel-specific issues round out the list: a header row that isn’t actually the first row (a title, logo, or “generated on” timestamp above it pushes the real column headers down, and a parser expecting row one to be headers reads garbage instead) and multiple sheets in one workbook, where a supplier updates the visible sheet and a stale second sheet ships along with it, or an ingestion script defaults to reading whichever sheet is first regardless of which one the supplier intended.

BMEcat and where it is mandatory

BMEcat is an XML catalog format maintained by BME, the German association for materials management, purchasing and logistics, and it shows up almost exclusively where a buyer’s procurement system was built around it: predominantly SAP-centric buyers and public-sector procurement in Germany, Austria and Switzerland, where it functions as close to a required format rather than one option among several. Its structure separates catalog-level metadata from the item list: a HEADER block identifies the catalog itself (supplier, buyer, catalog ID, generation date, language) followed by a T_NEW_CATALOG section containing one PRODUCT element per item, each carrying a supplier part ID, description fields, classification, and pricing detail as nested child elements rather than flat columns.

<?xml version="1.0" encoding="UTF-8"?>
<BMECAT version="2005">
  <HEADER>
    <CATALOG>
      <LANGUAGE>eng</LANGUAGE>
      <CATALOG_ID>CAT-2026-09</CATALOG_ID>
      <CATALOG_VERSION>1.0</CATALOG_VERSION>
      <GENERATOR_INFO>SupplierExampleCo Catalog Export</GENERATOR_INFO>
    </CATALOG>
  </HEADER>
  <T_NEW_CATALOG>
    <PRODUCT>
      <SUPPLIER_PID>WDG-1002</SUPPLIER_PID>
      <PRODUCT_DETAILS>
        <DESCRIPTION_SHORT>Widget, 3in, stainless</DESCRIPTION_SHORT>
        <PRODUCT_ORDER_DETAILS>
          <ORDER_UNIT>EA</ORDER_UNIT>
        </PRODUCT_ORDER_DETAILS>
      </PRODUCT_DETAILS>
      <PRODUCT_PRICE_DETAILS>
        <PRODUCT_PRICE price_type="net_customer">
          <PRICE_AMOUNT>4.75</PRICE_AMOUNT>
          <PRICE_CURRENCY>USD</PRICE_CURRENCY>
        </PRODUCT_PRICE>
      </PRODUCT_PRICE_DETAILS>
    </PRODUCT>
  </T_NEW_CATALOG>
</BMECAT>

BMEcat’s classification convention is worth calling out specifically, because it differs from what a supplier coming from a UNSPSC-only world expects: BMEcat is closely associated with eCl@ss, a classification scheme maintained separately from UNSPSC and structured differently, and while later BMEcat versions can carry other classification systems including UNSPSC, a buyer implementing BMEcat on the strength of an SAP or DACH-region procurement configuration is likely expecting eCl@ss codes specifically unless told otherwise. Confirming which classification scheme a given BMEcat-requiring buyer actually consumes is worth doing before mapping a whole catalog against the wrong one.

cXML catalog format

Separately from the PunchOutSetupRequest, PunchOutSetupResponse, PunchOutOrderMessage and OrderRequest documents that make up a live PunchOut session (covered in BoreaTech’s what is cXML primer and in this site’s own PunchOut setup guides), cXML platforms typically also support loading a static hosted catalog as an XML file, as an alternative to or alongside a live PunchOut connection. The item-level content in that kind of file is recognizably cXML in shape: a repeated block of items, each carrying a unit of measure, price, description and classification for one line, structured similarly to the ItemDetail block inside a PunchOut PunchOutOrderMessage even though it’s assembled as a whole-catalog file rather than generated live during a checkout.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE cXML SYSTEM "http://xml.cxml.org/schemas/cXML/1.2.045/cXML.dtd">
<cXML payloadID="[email protected]" timestamp="2026-09-16T09:00:00-05:00">
  <!-- illustrative shape only -- the wrapping message name and exact
       element set for a catalog upload are platform- and version-specific;
       see the note below -->
  <Message>
    <CatalogUpload>
      <ItemEntry>
        <ItemEntryDetail>
          <UnitOfMeasure>EA</UnitOfMeasure>
          <UnitPrice><Money currency="USD">4.75</Money></UnitPrice>
          <Description xml:lang="en">Widget, 3in, stainless</Description>
          <Classification domain="UNSPSC">31161701</Classification>
        </ItemEntryDetail>
      </ItemEntry>
    </CatalogUpload>
  </Message>
</cXML>

The exact wrapping message name, element set, and how it differs from a given vendor’s own hosted-catalog conventions vary enough between platforms and releases that this guide deliberately doesn’t pin one down as canonical: the receiving platform’s own catalog upload documentation is the source of truth on the current schema, the same way it’s the authority on PunchOut credential fields. What’s consistent even where the specifics move is the concept: a structured, versioned XML document carrying the same underlying item data a CSV or BMEcat file would, formatted for a cXML-native platform’s ingestion path instead.

A comparison table

CSV Excel BMEcat cXML catalog
Structure Flat, delimited rows Spreadsheet grid, formulas and formatting Nested XML, header + item blocks Nested XML, index + item blocks
Typical source Database or system export Manual authoring or ad hoc export SAP-centric or DACH-region catalog systems cXML-based procurement platforms
Native classification None: whatever column convention is agreed None: same eCl@ss primarily, other schemes possible UNSPSC or platform-defined schemes
Common failure Delimiter or encoding mismatch Merged cells, formulas, auto-formatting Wrong classification scheme assumed Schema or field-set mismatch by platform/version
Where it’s replaced By EDI or a live feed at higher volume By CSV or a live feed once complexity grows Rarely, often a hard buyer requirement By a live PunchOut session when supported

Where SupplierForge fits

All four of these are static files, and a static file is only ever as current as the last time it was generated and re-uploaded, which is a separate question from which format it’s shaped as. SupplierForge’s catalog ingestion accepts CSV, Excel, structured feeds, direct API submission, SFTP, and EDI, with the supplier onboarding portal validating structure and content automatically as each one comes in, so a delimiter mismatch or a merged-cell gap surfaces as a specific, actionable error during onboarding rather than as a silently corrupted row discovered downstream. Full details are in the feature set. Where a buyer supports a live PunchOut session instead of any file upload at all, that connection (across cXML, OCI and EDI) is handled by the PunchOut Gateway, a separately licensed component built for that specific job rather than an extension of file-based catalog ingestion.

Frequently asked questions

What's the single most common reason a CSV catalog file gets rejected?
An encoding or delimiter mismatch between what the supplier's system exported and what the receiving system expects: a semicolon-delimited export from a European-locale spreadsheet arriving somewhere that assumes commas, or a Windows-1252 file with accented characters arriving somewhere that assumes UTF-8. Both produce a file that opens and looks correct in a spreadsheet program while failing to parse correctly on ingestion, which is what makes this class of error so persistent: the person who generated the file usually can't see the problem from their own screen.
Does BMEcat replace cXML, or do they compete for the same job?
They mostly don't compete, because they're usually chosen by different buyers for different reasons rather than evaluated against each other for the same connection. BMEcat is a static catalog upload format that shows up largely where a German, Austrian or Swiss buyer's procurement system expects it; cXML's catalog document is one option among several for uploading a hosted catalog into a cXML-based platform like Ariba, and the same platform typically also supports PunchOut as a live alternative to any file upload at all. Which one applies to a given relationship is a business and platform decision the buyer makes, not something a supplier picks freely.
Can a production catalog feed run on Excel files long-term, or is that only for one-off uploads?
It works for a stable, moderate-sized catalog with a predictable refresh cadence, and plenty of long-running supplier relationships never move past it. It gets harder to sustain as the catalog grows or the refresh frequency increases, mainly because Excel's spreadsheet-authoring conveniences (merged cells, formulas, auto-formatting) are exactly what breaks programmatic ingestion, and larger files make manual review of every row impractical before each submission.
Why does a catalog file that opens fine in Excel still fail ingestion validation?
Because 'opens fine' and 'is structured the way a parser expects' are different bars. Excel recalculates formulas and reformats values on open, so a file that displays correctly in the spreadsheet program can still contain a formula string instead of a value in an underlying cell, a merged range that reads as blank everywhere except its first cell, or a part number Excel silently reformatted as a number or date the moment the file was saved, all invisible to someone just looking at the grid.
Is there one catalog file format that most buyers agree on?
No, and that's close to the central fact of supplier catalog operations: a supplier selling into several buyers should expect to produce several different formats rather than one that fits all of them. CSV is the closest thing to a universal fallback because almost every system can read it, but 'CSV' still varies enough in delimiter, encoding and quoting convention between buyers that treating it as one fixed format rather than a family of similar ones causes its own failures.