$additionalArgs * * @throws ResponseParserException */ public function parseXmlString(MessageType $type, string $xml, array $additionalArgs = []): mixed { $crawler = XmlCrawlerFactory::create($xml); if (0 === $crawler->count()) { throw new ResponseParserException('Unable to parse XML response: '.XmlCrawlerFactory::diagnose($xml)); } // The type in the XML wins, to catch error responses. BusPro may send one we don't know. $typeAttribute = $this->getStringOrNullValue($crawler->filterXPath('//ergebnis/satz/@typ')); $responseType = null === $typeAttribute ? $type : MessageType::tryFrom($typeAttribute); if (null === $responseType) { throw new ResponseParserException(sprintf('Unrecognised BusProNet response type "%s"', $typeAttribute)); } $resultNode = $crawler->filterXPath('//ergebnis'); try { switch ($responseType) { case MessageType::Notification: return (new NotificationParser())->parse($crawler); case MessageType::CustomerData: $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 'Newsletter': return (new PersonalDataParser())->parse($resultNode); case 'Adressdaten_Ändern': return (new PersonalDataUpdateParser())->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); } throw new ResponseParserException(sprintf('Unrecognised customer data subtype "%s"', $subType)); case MessageType::Countries: return (new CountriesParser())->parse($resultNode); case MessageType::MutableData: return (new MutableDataParser())->parse($resultNode); case MessageType::Availability: return (new AvailabilitiesParser())->parseServices($resultNode); case MessageType::AvailabilityExtended: return (new ExtendedAvailabilitiesParser())->parseServices($resultNode); case MessageType::AvailabilityHotel: return (new AvailabilitiesParser())->parseRooms($resultNode); case MessageType::BookingUpdate: return (new BookingUpdateParser())->parse($resultNode); case MessageType::Booking: return (new BookingResponseParser())->parse($resultNode); case MessageType::Products: return (new ProductsParser())->parse($resultNode); case MessageType::ProductData: $travelNode = $crawler->filterXPath('//reise/termin'); if (0 === $travelNode->count()) { throw new ResponseParserException('No travel data node found in product data response'); } return $this->travelParser->parse($travelNode->first(), ...$additionalArgs); case MessageType::Agencies: return (new AgencyParser())->parse($resultNode); case MessageType::PurchaseVoucher: return (new PurchaseVoucherParser())->parse($resultNode); case MessageType::PromoVoucher: return (new PromoVoucherParser())->parse($resultNode); case MessageType::VoucherTemplates: return (new VoucherTemplatesParser())->parse($resultNode); case MessageType::VoucherPaymentMethods: return (new VoucherPaymentMethodsParser())->parse($resultNode); case MessageType::VoucherPreview: return (new VoucherPreviewParser())->parse($resultNode); case MessageType::VoucherSale: return (new VoucherSaleResponseParser())->parse($resultNode); } } catch (\InvalidArgumentException $e) { throw new ResponseParserException('Invalid XML response structure: '.$e->getMessage(), 0, $e); } } }