/ XmlClient

XmlClient

Miko's XmlClient provides easy XML fetching and parsing from web services. Supports both file_get_contents and cURL methods with SSL verification and timeout options.


XmlClient Methods Summary

Method Description
create($options)Create new XmlClient instance
get($url)Fetch XML using file_get_contents
getWithCurl($url)Fetch XML using cURL

XmlResponse Methods Summary

Method Description
isSuccess()Check if request was successful
xml()Get SimpleXMLElement object
error()Get error message if failed
toArray()Convert XML to array
find($xpath)Find elements by XPath query
first($xpath)Get first matching element
attribute($name)Get attribute value from root
value($path)Get text value by XPath

Basic Usage

use Miko\Core\Http\XmlClient;

// Create client
$client = XmlClient::create();

// Fetch XML
$response = $client->get('https://example.com/feed.xml');

if ($response->isSuccess()) {
    $xml = $response->xml();
    echo $xml->title;
}

Configuration Options

// Create with custom options
$client = XmlClient::create([
    'timeout' => 30,           // Request timeout in seconds
    'user_agent' => 'Miko/1.0', // User agent string
    'verify_ssl' => true        // SSL certificate verification
]);

// Disable SSL for development
$client = XmlClient::create([
    'verify_ssl' => false
]);

Fetching Methods

Using file_get_contents

$client = XmlClient::create();

// Simple GET request
$response = $client->get('https://example.com/data.xml');

if ($response->isSuccess()) {
    $data = $response->toArray();
    print_r($data);
}

Using cURL

$client = XmlClient::create([
    'timeout' => 60
]);

// cURL with follow redirects
$response = $client->getWithCurl('https://example.com/feed.xml');

if ($response->isSuccess()) {
    $xml = $response->xml();
}

Response Handling

Check Success

$response = $client->get('https://example.com/data.xml');

if ($response->isSuccess()) {
    // Process XML
    $xml = $response->xml();
} else {
    // Handle error
    echo "Error: " . $response->error();
}

Get Raw XML

$response = $client->get('https://example.com/data.xml');

// Get SimpleXMLElement
$xml = $response->xml();

// Access elements
echo $xml->title;
echo $xml->description;

// Loop through items
foreach ($xml->item as $item) {
    echo $item->name;
}

Convert to Array

$response = $client->get('https://example.com/data.xml');

// Convert entire XML to array
$array = $response->toArray();

// Access as array
echo $array['title'];
echo $array['items'][0]['name'];

XPath Queries

Find Elements

$response = $client->get('https://example.com/catalog.xml');

// Find all products
$products = $response->find('//product');

foreach ($products as $product) {
    echo $product->name . ': ' . $product->price . "\n";
}

// Find products with specific attribute
$activeProducts = $response->find('//product[@status="active"]');

Get First Match

$response = $client->get('https://example.com/catalog.xml');

// Get first product
$firstProduct = $response->first('//product');

if ($firstProduct) {
    echo $firstProduct->name;
}

// Get specific element
$title = $response->first('//channel/title');

Get Value

$response = $client->get('https://example.com/rss.xml');

// Get text value directly
$title = $response->value('//channel/title');
$description = $response->value('//channel/description');

// Get root element value
$rootValue = $response->value();

Get Attribute

$response = $client->get('https://example.com/data.xml');

// Get attribute from root element
$version = $response->attribute('version');
$encoding = $response->attribute('encoding');

Practical Examples

RSS Feed Reader

class RssFeedReader
{
    private XmlClient $client;
    
    public function __construct()
    {
        $this->client = XmlClient::create([
            'timeout' => 30,
            'user_agent' => 'MyApp RSS Reader/1.0'
        ]);
    }
    
    public function getFeed(string $url): array
    {
        $response = $this->client->get($url);
        
        if (!$response->isSuccess()) {
            throw new Exception("Failed to fetch feed: " . $response->error());
        }
        
        $items = [];
        foreach ($response->find('//item') as $item) {
            $items[] = [
                'title' => (string)$item->title,
                'link' => (string)$item->link,
                'description' => (string)$item->description,
                'pubDate' => (string)$item->pubDate
            ];
        }
        
        return [
            'title' => $response->value('//channel/title'),
            'description' => $response->value('//channel/description'),
            'items' => $items
        ];
    }
}

// Usage
$reader = new RssFeedReader();
$feed = $reader->getFeed('https://example.com/rss.xml');

echo "Feed: " . $feed['title'] . "\n";
foreach ($feed['items'] as $item) {
    echo "- " . $item['title'] . "\n";
}

Currency Exchange Rate

class CurrencyService
{
    private XmlClient $client;
    
    public function __construct()
    {
        $this->client = XmlClient::create(['timeout' => 15]);
    }
    
    public function getRates(string $base = 'USD'): array
    {
        $url = "https://api.example.com/rates.xml?base={$base}";
        $response = $this->client->getWithCurl($url);
        
        if (!$response->isSuccess()) {
            return [];
        }
        
        $rates = [];
        foreach ($response->find('//rate') as $rate) {
            $currency = (string)$rate['currency'];
            $value = (float)$rate;
            $rates[$currency] = $value;
        }
        
        return $rates;
    }
    
    public function convert(float $amount, string $from, string $to): float
    {
        $rates = $this->getRates($from);
        
        if (!isset($rates[$to])) {
            throw new Exception("Currency {$to} not found");
        }
        
        return $amount * $rates[$to];
    }
}

// Usage
$currency = new CurrencyService();
$rates = $currency->getRates('EUR');
$usdAmount = $currency->convert(100, 'EUR', 'USD');

Product Catalog Import

use Miko\Core\Http\XmlClient;
use Miko\Log\Logger;

class CatalogImporter
{
    private XmlClient $client;
    
    public function __construct()
    {
        $this->client = XmlClient::create([
            'timeout' => 120,
            'verify_ssl' => true
        ]);
    }
    
    public function import(string $url): array
    {
        $response = $this->client->getWithCurl($url);
        
        if (!$response->isSuccess()) {
            Logger::error("Catalog import failed", ['error' => $response->error()]);
            return [];
        }
        
        $products = [];
        
        foreach ($response->find('//product') as $product) {
            $products[] = [
                'sku' => (string)$product->sku,
                'name' => (string)$product->name,
                'price' => (float)$product->price,
                'stock' => (int)$product->stock,
                'category' => (string)$product->category,
                'active' => (string)$product['status'] === 'active'
            ];
        }
        
        Logger::general('Imported products', ['count' => count($products)], 'INFO');
        
        return $products;
    }
}

// Usage
$importer = new CatalogImporter();
$products = $importer->import('https://supplier.com/catalog.xml');

foreach ($products as $product) {
    // Save to database
    Product::updateOrCreate(
        ['sku' => $product['sku']],
        $product
    );
}

Sitemap Parser

class SitemapParser
{
    private XmlClient $client;
    
    public function __construct()
    {
        $this->client = XmlClient::create();
    }
    
    public function getUrls(string $sitemapUrl): array
    {
        $response = $this->client->get($sitemapUrl);
        
        if (!$response->isSuccess()) {
            return [];
        }
        
        $urls = [];
        
        // Handle sitemap index
        $sitemaps = $response->find('//sitemap/loc');
        if (!empty($sitemaps)) {
            foreach ($sitemaps as $loc) {
                $urls = array_merge($urls, $this->getUrls((string)$loc));
            }
            return $urls;
        }
        
        // Handle regular sitemap
        foreach ($response->find('//url') as $url) {
            $urls[] = [
                'loc' => (string)$url->loc,
                'lastmod' => (string)$url->lastmod ?: null,
                'priority' => (float)($url->priority ?: 0.5)
            ];
        }
        
        return $urls;
    }
}

// Usage
$parser = new SitemapParser();
$urls = $parser->getUrls('https://example.com/sitemap.xml');

foreach ($urls as $url) {
    echo $url['loc'] . " (Priority: " . $url['priority'] . ")\n";
}

Error Handling

$client = XmlClient::create();
$response = $client->get('https://example.com/data.xml');

if (!$response->isSuccess()) {
    $error = $response->error();
    
    // Log the error
    Logger::error("XML fetch failed", [
        'url' => 'https://example.com/data.xml',
        'error' => $error
    ]);
    
    // Handle specific errors
    if (str_contains($error, 'Failed to fetch')) {
        // Network error
    } elseif (str_contains($error, 'Failed to parse')) {
        // Invalid XML
    }
}

Comparison: get() vs getWithCurl()

Feature get() getWithCurl()
Methodfile_get_contentscURL
Follow RedirectsNoYes
PerformanceFaster for simple requestsBetter for complex requests
Error DetailsBasicDetailed
RecommendedSimple XML feedsAPIs, authenticated requests
// Use get() for simple feeds
$response = $client->get('https://example.com/simple.xml');

// Use getWithCurl() for APIs with redirects
$response = $client->getWithCurl('https://api.example.com/data.xml');