Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Xml Wrangler Laravel Package

saloonphp/xml-wrangler

XML Wrangler is a lightweight SaloonPHP plugin for working with XML in HTTP requests and responses. Easily build XML bodies, set the right headers, and parse XML responses into usable data for your Laravel or PHP API integrations.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation:

    composer require saloonphp/xml-wrangler
    

    Ensure your project uses PHP 8.1+ (recommended: 8.3+ for full feature support).

  2. First Use Case: Parsing XML from a Saloon Response

    use Saloon\Saloon;
    use SaloonHttp\SaloonHttpFacade as Http;
    use Saloonphp\XmlWrangler\XmlReader;
    
    // Example: Fetch XML from an API
    $response = Http::get('https://example.com/api/xml-endpoint');
    
    // Parse the response
    $data = XmlReader::fromResponse($response)
        ->query('//items/item') // XPath query
        ->map(fn ($node) => [
            'id' => $node->getAttribute('id'),
            'name' => $node->getContent(),
        ])
        ->all();
    
  3. First Use Case: Generating XML for a Request

    use Saloonphp\XmlWrangler\XmlWriter;
    
    $xml = XmlWriter::make()
        ->root('request')
        ->element('user', [
            'id' => '123',
        ])
        ->element('name', 'John Doe')
        ->element('email', 'john@example.com')
        ->toString();
    
    // Use $xml in a Saloon request
    $response = Http::post('https://example.com/api', [
        'body' => $xml,
        'headers' => ['Content-Type' => 'application/xml'],
    ]);
    
  4. Where to Look First:

    • Documentation: Start with the README.md for quick examples.
    • Source Code: Focus on:
      • src/XmlReader.php (parsing logic).
      • src/XmlWriter.php (generation logic).
      • src/Query.php (XPath and node traversal).
    • Tests: Browse tests/ for real-world usage patterns (e.g., XmlReaderTest.php, XmlWriterTest.php).

Implementation Patterns

Core Workflows

1. Parsing XML Responses (Saloon Integration)

Pattern: Use XmlReader::fromResponse() to parse Saloon responses with XPath queries.

$response = $this->client->send($request);
$items = XmlReader::fromResponse($response)
    ->query('//catalog/item')
    ->each(fn ($node) => [
        'sku' => $node->getAttribute('sku'),
        'price' => (float) $node->query('./price')->first()->getContent(),
    ])
    ->toArray();

Laravel Integration Tip:

  • Register a macro for Http or Saloon to auto-parse XML responses:
    use SaloonHttp\SaloonHttpFacade as Http;
    
    Http::macro('xml', function ($url, $method = 'GET') {
        $response = Http::{$method}($url);
        return XmlReader::fromResponse($response)->toArray();
    });
    
    Usage: Http::xml('https://example.com/feed').

2. Generating XML Requests

Pattern: Build XML dynamically using XmlWriter for API requests.

$xml = XmlWriter::make()
    ->root('soapenv:Envelope', ['xmlns:soapenv' => 'http://schemas.xmlsoap.org/soap/envelope/'])
    ->element('soapenv:Header')
    ->element('soapenv:Body')
        ->element('ns1:GetUserDetails', ['xmlns:ns1' => 'http://example.com'])
            ->element('userId', $userId)
    ->up()
    ->up()
    ->toString();

Tip: Use DTOs or arrays to generate XML:

$user = User::find(1);
$xml = XmlWriter::make()
    ->root('user')
    ->element('id', $user->id)
    ->element('name', $user->name)
    ->element('email', $user->email)
    ->toString();

3. Handling Namespaces (SOAP/XPath)

Pattern: Map namespaces for XPath queries or XML generation.

// Parsing with namespaces
$data = XmlReader::fromString($xml)
    ->mapNamespaces([
        'soap' => 'http://schemas.xmlsoap.org/soap/envelope/',
        'ns1' => 'http://example.com',
    ])
    ->query('//soap:Envelope/soap:Body/ns1:GetUserResponse')
    ->first();

// Generating with namespaces
$xml = XmlWriter::make()
    ->root('soap:Envelope', ['xmlns:soap' => 'http://schemas.xmlsoap.org/soap/envelope/'])
    ->element('soap:Header')
    ->element('soap:Body')
        ->element('ns1:GetUserDetails', ['xmlns:ns1' => 'http://example.com'])
            ->element('userId', '123')
    ->up()
    ->up()
    ->toString();

4. Streaming Large XML Files

Pattern: Use XmlReader::fromStream() to avoid memory issues.

$stream = fopen('large_file.xml', 'r');
$reader = XmlReader::fromStream($stream);

foreach ($reader->query('//item') as $node) {
    // Process each node individually
    $data[] = $node->getContent();
}
fclose($stream);

Laravel Tip: Combine with Laravel’s Storage facade:

$stream = Storage::disk('s3')->readStream('large-export.xml');
$reader = XmlReader::fromStream($stream);

5. Transforming XML to Arrays/Collections

Pattern: Use map() and each() to transform XML nodes into arrays or collections.

$users = XmlReader::fromString($xml)
    ->query('//users/user')
    ->map(fn ($node) => [
        'id' => $node->getAttribute('id'),
        'name' => $node->query('./name')->first()->getContent(),
    ])
    ->toCollection();

Tip: Chain with Laravel Collections for further processing:

$filteredUsers = $users->filter(fn ($user) => $user['id'] > 100);

6. Writing XML to Files or Responses

Pattern: Generate XML and write it to a file or return it in a Laravel response.

// Write to a file
$xml = XmlWriter::make()->root('data')->element('item', 'value')->toString();
Storage::put('export.xml', $xml);

// Return in a Laravel response
return response($xml, 200, ['Content-Type' => 'application/xml']);

Integration Tips

With Saloon

  • Auto-parse XML responses: Extend Saloon’s Concerns\HasResponse to add XML parsing:
    use Saloonphp\XmlWrangler\XmlReader;
    
    class XmlResponse extends SaloonResponse
    {
        public function xml(): array
        {
            return XmlReader::fromResponse($this)->toArray();
        }
    }
    
    Usage:
    $response = $this->client->send($request);
    $data = $response->xml();
    

With Laravel Eloquent

  • Hydrate models from XML:
    $user = XmlReader::fromString($xml)
        ->query('//user')
        ->first()
        ->map(fn ($key, $value) => [
            'attribute' => 'user_' . snake_case($key),
            'value' => $value,
        ])
        ->toArray();
    
    return User::create($user);
    

With Laravel HTTP Clients

  • Parse XML in middleware:
    public function handle($request, Closure $next)
    {
        if ($request->wantsXml()) {
            $request->merge(XmlReader::fromString($request->getContent())->toArray());
        }
        return $next($request);
    }
    

With Testing (Pest/Laravel)

  • Assert XML responses:
    $response = $this->get('/api/export');
    $xml = XmlReader::fromResponse($response);
    expect($xml->query('//items/item')->count())->toBe(3);
    

Gotchas and Tips

Pitfalls

1. Namespace Handling

  • Gotcha: Forgetting to map namespaces in XPath queries will return empty results.
    // ❌ Fails if namespace isn't mapped
    $reader->query('//soap:Envelope');
    
    // ✅ Works with mapped namespace
    $reader->mapNamespaces(['soap' => 'http://schemas.xmlsoap.org/soap/envelope/'])
           ->
    
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
hamzi/corewatch
minionfactory/raw-hydrator
hexters/coinpayment
rjcodes/rjcms
act-training/laravel-permissions-manager
alimarchal/laravel-chart-of-accounts
babenkoivan/elastic-scout-driver
mkwebdesign/filament-watchdog-v5
renatomarinho/laravel-page-speed
zedmagdy/filament-business-hours
renatovdemoura/blade-elements-ui
devgeek/beacon-admin
benjamin-rqt/data-watcher-bundle
atriumphp/atrium
sandermuller/package-boost-laravel
sandermuller/boost-skills
redaxo/core
yusufgenc/filament-api-forge
l3aro/rating-star-for-filament
leek/filament-subtenant-scope