XML conversion

The XMLConverter converts a CSV records collection into a PHP DOMDocument.

Settings

Prior to converting your records collection into XML, you may wish to configure the element and its associated attribute names. To do so, XMLConverter provides methods to set up these settings.

Because we are building a DOMDocument object, the XMLConverter object throws DOMException instead of League\Csv\Exception.

XMLConverter::rootElement

public XMLConverter::rootElement(string $node_name): self

This method sets the XML root name.

The default root element name is csv.

XMLConverter::recordElement

public XMLConverter::recordElement(string $node_name, string $record_offset_attribute_name = ''): self

This method sets the XML record name and optionally the attribute name for the record offset value if you want this information preserved.

The default record element name is row.

The default attribute name is an empty string.

XMLConverter::fieldElement

public XMLConverter::fieldElement(string $node_name, string $fieldname_attribute_name = ''): self

This method sets the XML field name and optionally the attribute name for the field name value.

The default field element name is cell.

The default attribute name is an empty string.

XMLConverter::formatter

New feature introduced in version 9.20.0

public XMLConverter::formatter(?callable $formatter): self

This method allow to apply a callback prior to converting your collection individual item. This callback allows you to specify how each item will be converted. The formatter should return an associative array suitable for conversion.

Conversion

public XMLConverter::convert(iterable $records): DOMDocument

The XMLConverter::convert accepts an iterable which represents the records collection and returns a DOMDocument object.

use League\Csv\XMLConverter;
use League\Csv\Statement;
use League\Csv\Reader;

$csv = Reader::createFromPath('/path/to/prenoms.csv', 'r');
$csv->setDelimiter(';');
$csv->setHeaderOffset(0);

$stmt = (new Statement())
    ->where(function (array $record) {
        return 'Anaïs' === $record['prenoms'];
    })
    ->offset(0)
    ->limit(2)
;

$converter = (new XMLConverter())
    ->rootElement('csv')
    ->recordElement('record', 'offset')
    ->fieldElement('field', 'name')
;

$records = $stmt->process($csv);

$dom = $converter->convert($records);
$dom->formatOutput = true;
$dom->encoding = 'iso-8859-15';

echo '<pre>', PHP_EOL;
echo htmlentities($dom->saveXML());
// <?xml version="1.0" encoding="iso-8859-15"?>
// <csv>
//   <record offset="71">
//     <field name="prenoms">Anaïs</field>
//     <field name="nombre">137</field>
//     <field name="sexe">F</field>
//     <field name="annee">2004</field>
//   </record>
//   <record offset="1099">
//     <field name="prenoms">Anaïs</field>
//     <field name="nombre">124</field>
//     <field name="sexe">F</field>
//     <field name="annee">2005</field>
//   </record>
// </csv>

If needed you can use the CharsetConverter object to correctly encode your CSV records before conversion.

Import

New feature introduced in version 9.3.0

public XMLConverter::import(iterable $records, DOMDocument $doc): DOMElement

Instead of converting your tabular data into a full XML document you can now import it into an already existing DOMDocument object. To do so, you need to specify which document the data should be imported into using the XMLConverter::import method.

This method takes two arguments:

  • the tabular data as defined for the XMLConverter::convert method;
  • a DOMDocument object to import the data into;

Note that the resulting DOMElement is attached to the given DOMDocument object but not yet included in the document tree. To include it, you still need to call a DOM insertion method like appendChild or insertBefore with a node that is currently in the document tree.

use League\Csv\XMLConverter;
use League\Csv\Statement;
use League\Csv\Reader;

$csv = Reader::createFromPath('/path/to/prenoms.csv', 'r');
$csv->setDelimiter(';');
$csv->setHeaderOffset(0);

$stmt = (new Statement())
    ->where(function (array $record) {
        return 'Anaïs' === $record['prenoms'];
    })
    ->offset(0)
    ->limit(2)
;

$converter = (new XMLConverter())
    ->rootElement('csv')
    ->recordElement('record', 'offset')
    ->fieldElement('field', 'name')
;

$records = $stmt->process($csv);

$dom = new DOMDocument('1.0');
$dom->loadXML('<root><header><name>My CSV Document</name></header></root>');

$data = $converter->import($records, $dom);
$dom->appendChild($data);
$dom->formatOutput = true;
$dom->encoding = 'iso-8859-15';

echo '<pre>', PHP_EOL;
echo htmlentities($dom->saveXML());
// <?xml version="1.0" encoding="iso-8859-15"?>
// <root>
//   <header>
//     <name>My CSV Document</name>
//   </header>
//   <csv>
//     <record offset="71">
//       <field name="prenoms">Anaïs</field>
//       <field name="nombre">137</field>
//       <field name="sexe">F</field>
//       <field name="annee">2004</field>
//     </record>
//     <record offset="1099">
//       <field name="prenoms">Anaïs</field>
//       <field name="nombre">124</field>
//       <field name="sexe">F</field>
//       <field name="annee">2005</field>
//     </record>
//   </csv>
// </root>

Download

If you are using the package inside a framework please use the framework recommended way instead of the describe mechanism hereafter.

To download the generated JSON you can use the XMLConverter::download method. The method returns the total number of bytes sent just like the XMLConverter::save method and enable downloading the XML on the fly.

General purpose

new in version 9.18.0

use League\Csv\Reader;
use League\Csv\JsonConverter;

$reader = Reader::createFromPath('file.csv');
$reader->setHeaderOffset(0);

header('Cache-Control: no-cache, no-store, must-revalidate');
header('Pragma: no-cache');
header('Expires: 0');
header('Content-Type: text/xml; charset=UTF-8');
header('Content-Description: File Transfer');
header('Content-Disposition: attachment; filename="name-for-your-file.xml"');

XMLConverter::create()->download($reader);
die;

In this scenario, you have to specify all the headers for the file to be downloaded.

Using a filename

new in version 9.17.0

To download the generated XML on the fly you can use the XMLConverter::download method:

use League\Csv\Reader;
use League\Csv\XMLConverter;

$reader = Reader::createFromPath('file.csv');
$reader->setHeaderOffset(0);

header('Cache-Control: no-cache, no-store, must-revalidate');
header('Pragma: no-cache');
header('Expires: 0');
 //the filename will be the name of the downloaded xml as shown by your HTTP client!
XMLConverter::create()->download($reader, 'name-for-your-file.xml');
die;

The caching headers are given as an example for using additional headers, it is up to the user to decide if those headers are needed or not.

By default, the method will set the encoding to utf-8 and will not format the XML. You can set those values using the method optional arguments.

use League\Csv\Reader;
use League\Csv\XMLConverter;

$reader = Reader::createFromPath('file.csv');
$reader->setHeaderOffset(0);

header('Cache-Control: no-cache, no-store, must-revalidate');
header('Pragma: no-cache');
header('Expires: 0');
XMLConverter::create()->download(
    records: $reader,
    filename: 'generated_file.xml',
    encoding: 'iso-8859-1',
    formatOutput: true,
);
die;

No check is done on the validity of the encoding string provided.