Skip to content
Search

ETL Adapter: XML

The XML adapter reads and writes XML data in ETL (Extract, Transform, Load) pipelines.

Installation

For the installation instructions, read the installation page.

Extractor

simple_items.xml

<root>
    <items>
        <item><id>1</id></item>
        <item><id>2</id></item>
        <item><id>3</id></item>
    </items>
</root>
<?php

use function Flow\ETL\Adapter\XML\from_xml;
use function Flow\ETL\DSL\{data_frame, ref, to_output};

data_frame()
    ->read(from_xml(__DIR__ . '/simple_items.xml')->withXMLNodePath('root/items/item'))
    ->withColumn('id', ref('node')->xpath('id')->domElementValue())
    ->write(to_output(truncate: false))
    ->run();
+-------------------------+----+
|                    node | id |
+-------------------------+----+
| <item><id>1</id></item> |  1 |
| <item><id>2</id></item> |  2 |
| <item><id>3</id></item> |  3 |
+-------------------------+----+
3 rows

The file is streamed. Each node at withXMLNodePath() is one row with one xml column node. Read it with xpath() (returns a list<xml_element>), domElementValue(), domElementAttributeValue() and the other domElement*() functions.

Loader

<?php

use function Flow\ETL\Adapter\XML\to_xml;
use function Flow\ETL\DSL\{bool_schema, data_frame, datetime_schema, float_schema, from_array, int_schema, json_schema, list_schema, map_schema, schema, structure_schema};
use function Flow\Types\DSL\{type_date, type_integer, type_list, type_map, type_string, type_structure};

data_frame()
    ->read(from_array(
        [
            ['id' => 1, 'active' => true, 'price' => 0.1 + 0.2, 'at' => new DateTimeImmutable('2026-01-02 03:04:05 UTC'), 'days' => [new DateTimeImmutable('2026-01-02')], 'labels' => [0 => 'a', 1 => 'b'], 'size' => ['w' => 1, 'h' => 2], 'meta' => '{"tags": []}'],
            ['id' => 2, 'active' => false, 'price' => 1.0, 'at' => null, 'days' => [], 'labels' => [], 'size' => ['w' => 3, 'h' => 4], 'meta' => '{}'],
        ],
        schema(
            int_schema('id'), bool_schema('active'), float_schema('price'), datetime_schema('at', nullable: true),
            list_schema('days', type_list(type_date())), map_schema('labels', type_map(type_integer(), type_string())),
            structure_schema('size', type_structure(['w' => type_integer(), 'h' => type_integer()])), json_schema('meta'),
        ),
    ))
    ->write(to_xml($path))
    ->run();
<?xml version="1.0" encoding="UTF-8"?>
<rows>
<row><id>1</id><active>true</active><price>0.30000000000000004</price><at>2026-01-02T03:04:05.000000+00:00</at><days><element>2026-01-02</element></days><labels><element><key>0</key><value>a</value></element><element><key>1</key><value>b</value></element></labels><size><w>1</w><h>2</h></size><meta>{"tags": []}</meta></row>
<row><id>2</id><active>false</active><price>1.0</price><at></at><days/><labels/><size><w>3</w><h>4</h></size><meta>{}</meta></row>
</rows>
Column Element
boolean true / false
float the shortest text that reads back as the same float, always with a fraction or an exponent: 1.0, 1.0e+25. Also NAN, INF, -INF
null an empty element
datetime, date withDateTimeFormat() (default Y-m-d\TH:i:s.uP) in the column zone, withDateFormat() (default Y-m-d)
time microseconds
list, map, structure nested elements. Each leaf is written like a column of its type
json the stored text

A column with a name that starts with the attribute prefix (_ by default) is an attribute of its row. A null in such a column is refused.

Floats are rendered under serialize_precision = -1. If the ini has a different value, the writer sets it for the render and then restores it. ini_set() must therefore be allowed. If it is not allowed, the writer throws RuntimeException('Writing floats requires serialize_precision = -1 and ini_set() cannot change it').

Custom writers

XMLWriter renders one column at a time. elements() and attributes() return one string for each value, with the escaping of the writer. A writer that only builds nodes delegates to write():

<?php

use Flow\ETL\Adapter\XML\Abstraction\{XMLAttribute, XMLNode};
use Flow\ETL\Adapter\XML\IO\Loader\XMLWriter;

use function Flow\Types\DSL\type_string;

final class MyWriter implements XMLWriter
{
    public function attributes(string $name, array $values): array
    {
        return array_map(
            fn (?string $value): string => substr($this->write(XMLNode::nested('x', new XMLAttribute($name, type_string()->cast($value)))), 2, -2),
            $values,
        );
    }

    public function elements(string $name, array $values): array
    {
        return array_map(fn (?string $value): string => $this->write(XMLNode::flatNode($name, $value ?? '')), $values);
    }

    public function write(XMLNode $node): string
    {
        // ...
    }
}

Found a typo or an outdated section? Edit this page on GitHub


Contributors

Built in the open.

Join us on GitHub
scroll back to top