Weave 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 Laravel Package

veewee/xml

veewee/xml provides a type-safe, declarative API for working with XML in PHP, covering DOM, encoding, error handling, memory-safe readers and writers, XSD schemas, and XSLT. It handles errors for you and supports spec compliance on PHP 8.4+.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps

  1. Installation: Add the package via Composer:

    composer require veewee/xml
    
  2. First Use Case: Generate a secure XML file with DOCTYPE disallowed:

    use VeeWee\Xml\Writer\Writer;
    use function VeeWee\Xml\Writer\Builder\document;
    use function VeeWee\Xml\Writer\Builder\element;
    use function VeeWee\Xml\Writer\Builder\value;
    use function VeeWee\Xml\Writer\Configurator\disallow_doctype;
    
    $writer = Writer::forFile('output.xml');
    $writer->configure(disallow_doctype());
    $writer->write(
        document('1.0', 'UTF-8',
            element('root', value('Secure XML without DOCTYPE!'))
        )
    );
    

    This creates output.xml with:

    <?xml version="1.0" encoding="UTF-8"?>
    <root>Secure XML without DOCTYPE!</root>
    
  3. Key Files to Explore:

    • docs/writer.md: For XML generation (security configurators live here).
    • docs/reader.md: For parsing XML.
    • docs/encoding.md: For JSON-like XML encoding/decoding.
    • docs/security.md: For the DOCTYPE policy and libxml-related safety guidance.
  4. v4.14.0 upgrade note: In-memory writes are now faster (Writer::inMemory()), so the common "build an XML string in PHP" pattern — for HTTP responses, tests, and queue payloads — is cheaper. libxml issue detection is also new; see Gotchas.


Implementation Patterns

Common Workflows

1. Generating Secure XML

use VeeWee\Xml\Writer\Writer;
use function VeeWee\Xml\Writer\Builder\{document, element, value};
use function VeeWee\Xml\Writer\Configurator\disallow_doctype;

$writer = Writer::forFile('secure.xml');
$writer->configure(disallow_doctype()); // Enforce no-DOCTYPE policy
$writer->write(
    document('1.0', 'UTF-8',
        element('data',
            element('item', value('Sensitive Data'))
        )
    )
);

2. Building XML Strings In-Memory (Faster in v4.14.0)

The in-memory writer is the right choice when you need the XML as a string rather than a file handle:

use VeeWee\Xml\Writer\Writer;
use function VeeWee\Xml\Writer\Configurator\disallow_doctype;

$writer = Writer::inMemory()->configure(disallow_doctype());
$writer->write($structure);
$xml = $writer->map(memory_output()); // string, no DOCTYPE

Prefer this over Writer::forFile() + re-read when the consumer is an HTTP response, an event payload, or a test assertion.

3. Memory-Safe XML Parsing

Use the Reader for large XML files. Note that reader-side security (entity loading, network access) is a reader concern — disallow_doctype() is a writer configurator and does not protect you when parsing untrusted input:

use VeeWee\Xml\Reader\Reader;

$reader = Reader::fromFile('large_file.xml');
foreach ($reader as $node) {
    // Process node-by-node without loading the whole document
}

For untrusted input, configure the reader to disable external entities and network access, then decode/validate the resulting data.

4. JSON-like XML Encoding/Decoding

use function VeeWee\Xml\encoding\{xml_encode, xml_decode};

$data = ['name' => 'John', 'age' => 30];
$xml = xml_encode($data);   // Converts to XML string
$decoded = xml_decode($xml); // Converts back to array

When the source is untrusted, decode first and validate the resulting data structure rather than trusting the raw string.

5. Namespaced XML

use function VeeWee\Xml\Writer\Builder\{element, namespace_attribute, prefixed_element};
use function VeeWee\Xml\Writer\Configurator\disallow_doctype;

$writer = Writer::forFile('namespaced.xml');
$writer->configure(disallow_doctype());
$writer->write(
    element('root',
        namespace_attribute('http://example.com', 'ex'),
        prefixed_element('ex', 'item', value('Test'))
    )
);

6. XSD Schema Validation

use VeeWee\Xml\XSD\Validator;

$validator = new Validator('schema.xsd');
$isValid = $validator->validate('data.xml');

7. XSLT Transformations

use VeeWee\Xml\XSLT\Transformer;

$transformer = new Transformer('style.xsl');
$result = $transformer->transform('input.xml');

Integration Tips

Laravel Service Providers

Register the package with security defaults in AppServiceProvider:

public function boot()
{
    $this->app->singleton(Writer::class, fn () =>
        Writer::forFile(storage_path('app/xml/output.xml'))
              ->configure(disallow_doctype())
    );
}

Form Request Validation with XML

Validate the parsed data, not the raw string, and enforce reader-side safety on input:

use function VeeWee\Xml\encoding\xml_decode;

public function validateXml(): array
{
    $data = xml_decode($this->input('xml')); // parse untrusted input safely

    return validator($data, [
        'name' => 'required|string',
        // ...
    ])->validate();
}

Remember: disallow_doctype() is a writer configurator. Incoming XML needs reader-side entity/network controls, not the writer.

API Responses

Build the payload in-memory (now faster in v4.14.0) rather than round-tripping through a file:

use VeeWee\Xml\Writer\Writer;
use function VeeWee\Xml\Writer\Configurator\disallow_doctype;

$writer = Writer::inMemory()->configure(disallow_doctype());
$writer->write($structure);
$xml = $writer->map(memory_output());

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

Queue Jobs for XML Processing

use VeeWee\Xml\Writer\Writer;
use function VeeWee\Xml\Writer\Configurator\disallow_doctype;

class GenerateXmlJob implements ShouldQueue
{
    public function handle()
    {
        $writer = Writer::forFile(storage_path('app/xml/report.xml'))
                        ->configure(disallow_doctype());
        $writer->write($this->buildXmlStructure());
    }
}

For jobs that only need the string (e.g. to POST upstream), use Writer::inMemory() and take advantage of the v4.14.0 speedup.


Gotchas and Tips

Pitfalls

  1. PHP 8.4+ Requirement for v4+:

    • If using veewee/xml@^4.0, ensure your project runs on PHP 8.4+.
    • For older PHP versions, stick to ^3.3.
  2. Writer-side vs Reader-side security:

    • disallow_doctype() configures the writer. It prevents you from emitting a DOCTYPE — it does not protect you when parsing untrusted XML.
    • For input, configure the reader (no external entities, no network) and validate the decoded data.
  3. Memory-Safe Reader vs. DOM:

    • The Reader is memory-efficient for large files, but lacks DOM traversal methods.
    • Use the DOM component for complex XPath queries or DOM manipulation.
  4. Namespaces:

    • Forgetting to declare namespaces with namespace_attribute will cause malformed XML.
    • Prefixed attributes require the namespace to be declared first.
  5. Raw XML Injection:

    • The raw() builder bypasses escaping. Only use it for trusted content.
  6. Error Handling:

    • The package throws exceptions on malformed XML. Wrap calls:
      try {
          $validator->validate('data.xml');
      } catch (\Throwable $e) {
          Log::error($e->getMessage());
      }
      
  7. Indentation Quirks:

    • Indentation configurators only work with Writer, not Reader or DOM.
  8. DOCTYPE Security (introduced v4.12.0):

    • DOCTYPE declarations enable XML entity vulnerabilities (XXE, billion laughs).
    • Always use disallow_doctype() for writer output in production:
      $writer->configure(disallow_doctype());
      
    • Audit legacy code paths that generate XML without this configurator.
  9. libxml Issue Detection (new in v4.14.0):

    • The package now surfaces libxml-flagged problems earlier — useful when auditing legacy XML that may have loaded external entities or contains malformed constructs.
    • Treat any libxml issue as a likely security or correctness problem, not just a parse error. Check the exact detection API in the release notes before wiring it into CI; behavior may differ between Writer and Reader entry points.

Debugging Tips

  1. Inspect In-Memory Output:

    $writer = Writer::inMemory()->configure(disallow_doctype());
    $writer->write($xmlStructure);
    $output = $writer->map(memory_output());
    dd($output); // inspect raw XML (should lack DOCTYPE); v4.14.0 makes this cheaper
    
  2. Validate Against a Schema:

    $validator = new Validator('schema.xsd');
    $errors = $validator->validate('data.xml', true); // return errors instead of throwing
    dd($errors);
    
  3. Audit Generated vs Incoming XML Separately:

    • For output, assert no DOCTYPE is present.
    • For input, assert external entity loading is disabled on the reader.
    • v4.14.0's libxml issue detection helps catch either side, but confirm which entry point emits the signal in your version.
  4. Performance with Large Files:

    • Prefer Reader over DOM for files >10MB.
    • Stream where possible, and reserve Writer::inMemory() for cases where you actually need the string (it is faster than ever, but streaming still wins on peak memory).

Extension Points

  1. Custom Builders: Implement your own builder functions that return Builder closures and compose them with the built-ins. Custom builders must honour security configurators — especially DOCTYPE and entity handling — so they do not silently bypass the policy.

  2. Custom Configurators: Wrap libxml options (e.g. LIBXML_NONET, LIBXML_NOENT) for both Writer and Reader via configurators. This is the recommended way to centralise hardening across an application.

  3. Map / Post-Processing Hooks: Use map() to post-process output, add headers, or route generated XML to storage. Combine with Writer::inMemory() for in-request transformations.

  4. Laravel Macros & Container Bindings: Bind Writer / Reader singletons with production defaults (no DOCTYPE, no network) in a service provider so the whole app inherits them. This is the cheapest safeguard against regressions introduced by ad-hoc XML generation in feature code.

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.
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
cgv/localized-resource