saloonphp/xml-wrangler
XML Wrangler is a PHP package that provides a simple, elegant API for reading and writing XML. Built on SimpleXML, it adds namespace support, fluent methods, and clean error handling, and pairs perfectly with Saloon to parse and build XML API responses with ease.
Architecture fit. XML Wrangler is a thin ergonomics layer over veewee/xml: a fluent reader with XPath-style querying, generics for typed results, attribute/CDATA/namespace handling, and a chainable writer for payload generation. It is framework-agnostic, but it is designed to feel native inside a Saloon/Laravel codebase — same maintainer (Sammyjo20), same fluent conventions — so the architectural cost of adoption is close to zero. From a TPM standpoint the important property is that it owns no state, registers no service providers of consequence, and imposes no structural pattern. It can be wrapped in an internal adapter in an afternoon, which means the decision is reversible and does not need to go through a full architecture board cycle. Treat it as a library choice, not a platform commitment.
Integration feasibility. Composer dependency, MIT, stable 1.x line, ~428 stars and growing but with effectively one primary maintainer. The release history is the strongest signal of health: PHP 8.3, 8.4, and 8.5 support landed promptly (v1.3.0, v1.4.0, v1.4.1), and v1.5.0 moved Saloon to v4.0 in dev dependencies, indicating the maintainer keeps pace with the upstream ecosystem. Integration effort is measured in hours, not sprints, for the first endpoint. The realistic work is not adding the package — it is writing and curating contract fixtures from real partner payloads, which is work a team should be doing regardless.
Technical risk. Four things to name explicitly in any plan:
LazyQuery needs a spike against real documents and our memory ceilings before anyone commits to a batch-processing use case.Key questions.
Stack fit. Highest value where XML arrives inside Saloon responses or where a Laravel service must generate partner XML (payments, carriers, ERP/SAP exports, regulatory filings). In that context the package turns "read this partner feed" into CRUD-shaped work: parse, query fluently, map into DTOs, return. On the write side, attributes plus namespace plus standalone-declaration support is exactly where hand-rolled string concatenation degrades fastest, so payload generation is the second-best entry point. If the codebase is not on Saloon, the package still works but the case narrows to generic XML ergonomics, and DOMDocument/SimpleXMLElement may be defensible for a single integration.
Migration path. Do not do a big-bang refactor of existing parsers. Identify one in-flight integration or one low-traffic legacy connector, build it with the package behind an internal adapter (App\Support\Xml\…), and leave existing code untouched. The adapter is the migration seam: it is what makes both adoption and exit cheap, and it is the enforcement point that keeps per-integration snowflakes from reappearing. Legacy connectors migrate opportunistically when touched for other reasons, not on a dedicated rewrite ticket.
Compatibility. Requires PHP 8.3+ and tracks up to 8.5; verify the platform's PHP baseline and upgrade cadence before committing. Underlying dependency is veewee/xml v3.1 — lock both. Saloon v4 alignment in v1.5.0 means teams on Saloon v3 should pin to the matching XML Wrangler line and plan the Saloon upgrade as a paired exercise rather than two independent ones. Pin exactly (or with a tight constraint) and treat minor bumps as a reviewable change, not silent drift.
Sequencing.
Maintenance. Low surface area, but low bus factor. Budget a nominal recurring cost: track upstream releases, review minor bumps, and keep the pinned version current enough that a PHP upgrade does not strand the dependency. The observed release cadence (PHP 8.3 → 8.4 → 8.5 within the same 1.x line) suggests the opposite risk — that the maintainer is more responsive than our internal upgrade cadence. Assign explicit ownership of the internal facade; an unowned adapter is the failure mode here, not the library itself.
Support. No commercial support, no vendor SLA. Internal expertise is the support model, and it is cheap to build: the API is small and the docs are adequate. The mitigations that actually reduce support load are the fixture corpus and the facade — those convert "the parser broke on this partner's payload" from an investigation into a failing contract test. Note for procurement: a few-hundred-star, effectively single-maintainer dependency will fail some security/vendor review processes. Have that conversation at pilot time, not at rollout time, and pre-write the exit rationale.
Scaling. Comfortable for request/response volumes typical of API integrations and webhook consumption. Scaling risk is concentrated in batch and large-document workloads, where per-document memory profile matters and streaming claims are unverified. Two concrete guardrails: (a) run the memory spike before any feed-processing feature is resourced, and (b) if documents are large, design the job around chunking at the transport/queue layer rather than relying on the library's lazy querying. Also note the XML writer is in-memory by nature — very large generated documents should be a deliberate design conversation.
Failure modes.
DOMDocument/SimpleXMLElement. Keeping that true is the entire point of the facade.Ramp-up. Effectively a half-day for a mid-level engineer familiar with PHP arrays; the query API is XPath-flavored, so anyone who has seen XPath transfers quickly, and generics give typed results without ceremony. The actual ramp cost is domain — partner schemas, namespace maps, and fixture curation — which exists with or without this package. For stakeholders, frame the ramp as one day of engineering to pilot, with success criteria agreed in advance: delivery time versus a comparable past integration, defect count in the XML layer, and engineer confidence in extending the pattern. If those hold, standardize across integration teams; the spend is near zero and the reversal cost is a day.
How can I help you explore Laravel packages today?