Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

circleback's avatar

Transforming API Resources for XML Output in Laravel

Hi, I want to convert my API JSON response to XML in Laravel. I’m using the Spatie ArrayToXml package, which works great when I pass a plain Eloquent result’s toArray() to it. However, when I try to use Eloquent API Resources (UserResource) to shape the data, I get an error when calling toArray() before converting to XML.

Example:

php artisan make:resource UserResource
  • UserResource.php
public function toArray(Request $request): array
{
   return [
       'name_data' => $this->name,
       'email_address' => $this->email,
   ];
}
  • api.php
return \Spatie\ArrayToXml\ArrayToXml::convert(
    \App\Http\Resources\UserResource::collection(
        \App\Models\User::paginate(10))->toArray($request)
); // DOMException Invalid Character Error

But this works:

return \Spatie\ArrayToXml\ArrayToXml::convert(
    \App\Models\User::paginate(10)->toArray()
); // Works

How can I use API Resources with ArrayToXml successfully?
Has anyone done this before, or is there a recommended approach?
Thanks!

0 likes
3 replies
LaryAI's avatar

Certainly! The issue arises because when you use UserResource::collection($users)->toArray($request), the resulting array is nested differently compared to a plain Eloquent collection's toArray(). Spatie's ArrayToXml expects a simple associative array, but Laravel API Resources wrap collections in a data key and may include pagination meta.

Example of what you get from a resource collection:

[
    'data' => [
        ['name_data' => '...', 'email_address' => '...'],
        // ...
    ],
    'links' => [/* ... */],
    'meta' => [/* ... */],
]

This structure causes issues with XML conversion, especially if the root element is not a valid XML tag (e.g., data, links, meta).


How to Fix

Option 1: Pass Only the Data Array

If you only want the user data, extract the data key before passing it to ArrayToXml:

$users = \App\Models\User::paginate(10);
$userResource = \App\Http\Resources\UserResource::collection($users)->toArray(request());

return \Spatie\ArrayToXml\ArrayToXml::convert(
    $userResource['data'], // Only the user data array
    'users' // Root element name
);

Option 2: Customize the Resource Collection

If you want to include pagination meta, you can restructure the array to have valid XML keys:

$users = \App\Models\User::paginate(10);
$userResource = \App\Http\Resources\UserResource::collection($users)->toArray(request());

$arrayForXml = [
    'users' => $userResource['data'],
    'pagination' => $userResource['meta'] ?? [],
];

return \Spatie\ArrayToXml\ArrayToXml::convert($arrayForXml, 'response');

Option 3: Use response()->xml() Macro (Optional)

If you want to return XML responses frequently, consider creating a response macro or helper to handle this conversion.


Summary

  • Extract the data key from the resource collection before passing to ArrayToXml.
  • Optionally include pagination/meta info under valid XML keys.
  • Always specify a valid root element in ArrayToXml.

Example Controller Method:

use App\Models\User;
use App\Http\Resources\UserResource;
use Spatie\ArrayToXml\ArrayToXml;

public function index(Request $request)
{
    $users = User::paginate(10);
    $userResource = UserResource::collection($users)->toArray($request);

    return ArrayToXml::convert(
        $userResource['data'],
        'users'
    );
}

This will output valid XML for your API resource collection.

circleback's avatar

@LaryAI

$userResource = \App\Http\Resources\UserResource::collection($users)->toArray(request());

$arrayForXml = [
    'users' => $userResource['data'],
    'pagination' => $userResource['meta'] ?? [],
];

This doesn't work because $userReource neither has $userResource['data'] nor $userResource['meta'].

AddWebContribution's avatar

@circleback try this

$data = \App\Http\Resources\UserResource::collection(\App\Models\User::paginate(5))
        ->response()
        ->getData(true);

    return \Spatie\ArrayToXml\ArrayToXml::convert([
        'users' => $data['data'],
        'pagination' => $data['meta'],
    ]);

Please or to participate in this conversation.