$additionalArgs */ public function parseXmlString(string $type, string $xml, array $additionalArgs = []): mixed { $crawler = new Crawler($xml); if (0 === $crawler->count()) { throw new ResponseParserException('Empty response received from server'); } // Override type unless present in XML to catch error responses $responseType = $this ->getStringOrNullValue($crawler->filterXPath('//ergebnis/satz/@typ')) ?? $type; $resultNode = $crawler->filterXPath('//ergebnis'); try { switch ($responseType) { case ApiClient::TYPE_NOTIFICATION: return (new NotificationParser())->parse($crawler); case ApiClient::TYPE_CUSTOMER_DATA: $subType = $this->getStringOrNullValue($resultNode->filterXPath('//art')); if (null === $subType || '' === $subType) { throw new ResponseParserException('Unable to determine customer data subtype from XML response'); } switch ($subType) { case 'Adressdaten': case 'Adressdaten_Ändern': case 'Newsletter': return (new PersonalDataParser())->parse($resultNode); case 'Adresse_Neu': return (new ContactFormResponseParser())->parse($resultNode); case 'SelektionCRM': case 'SelektionCRM_Ändern': return (new CrmAttributesResponseParser())->parse($resultNode); case 'Vorgänge': return (new BookingsParser())->parse($resultNode); case 'Vorgang_Details': return (new BookingParser())->parse($resultNode); case 'Dokumentdruck': return (new DocumentsParser())->parseDocuments($resultNode); case 'Vorgangdruck': return (new DocumentsParser())->parseConfirmation($resultNode); } break; case ApiClient::TYPE_BASE_DATA_COUNTRIES: return (new CountriesParser())->parse($resultNode); case ApiClient::TYPE_MUTABLE_DATA: return (new MutableDataParser())->parse($resultNode); case ApiClient::TYPE_AVAILABILITY: return (new AvailabilitiesParser())->parseServices($resultNode); case ApiClient::TYPE_AVAILABILITY_EXTENDED: return (new ExtendedAvailabilitiesParser())->parseServices($resultNode); case ApiClient::TYPE_AVAILABILITY_HOTEL: return (new AvailabilitiesParser())->parseRooms($resultNode); case ApiClient::TYPE_BOOKING_UPDATE: return (new BookingUpdateParser())->parse($resultNode); case ApiClient::TYPE_BOOKING: return (new BookingResponseParser())->parse($resultNode); case ApiClient::TYPE_PRODUCTS: return (new ProductsParser())->parse($resultNode); case ApiClient::TYPE_PRODUCT_DATA: $travelNode = $crawler->filterXPath('//reise/termin'); if (0 === $travelNode->count()) { throw new ResponseParserException('No travel data node found in product data response'); } return (new TravelParser())->parse($travelNode->first(), ...$additionalArgs); case ApiClient::TYPE_AGENCIES: return (new AgencyParser())->parse($resultNode); case ApiClient::TYPE_PURCHASE_VOUCHER: return (new PurchaseVoucherParser())->parse($resultNode); case ApiClient::TYPE_PROMO_VOUCHER: return (new PromoVoucherParser())->parse($resultNode); } } catch (\InvalidArgumentException $e) { throw new ResponseParserException('Invalid XML response structure: '.$e->getMessage(), 0, $e); } throw new ResponseParserException('Unable to parse XML response'); } }