veewee/xml
Type-safe, declarative XML toolkit for PHP. Includes DOM helpers, safe error handling, memory-safe reader/writer, XML encode/decode, plus XSD and XSLT utilities. Spec-compliance ready for PHP 8.4+, with maintained v3 for older PHP.
## Getting Started
### Minimal Steps
1. **Installation**: Add the package via Composer:
```bash
composer require veewee/xml
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>
Key Files to Explore:
docs/writer.md: For XML generation (updated with security configurators).docs/reader.md: For parsing XML.docs/encoding.md: For JSON-like XML encoding/decoding.docs/security.md: New security-focused documentation (hypothetical, but implied by new feature).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'))
)
)
);
Use the Reader for large XML files with security awareness:
use VeeWee\Xml\Reader\Reader;
$reader = Reader::fromFile('large_file.xml');
foreach ($reader as $node) {
if ($node->name === 'item' && !$node->hasDoctype()) {
// Process node (safe from DOCTYPE attacks)
}
}
use function VeeWee\Xml\encoding\{xml_encode, xml_decode};
$data = ['name' => 'John', 'age' => 30];
$xml = xml_encode($data); // Converts to XML string (auto-disallows DOCTYPE if configured)
$decoded = xml_decode($xml); // Converts back to array
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('Secure Test'))
)
);
use VeeWee\Xml\XSD\Validator;
$validator = new Validator('schema.xsd');
$isValid = $validator->validate('data.xml');
use VeeWee\Xml\XSLT\Transformer;
$transformer = new Transformer('style.xsl');
$result = $transformer->transform('input.xml');
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())
);
}
Extend FormRequest to validate XML payloads and enforce security:
use VeeWee\Xml\encoding\xml_decode;
use VeeWee\Xml\Writer\Configurator\disallow_doctype;
public function validateXml()
{
$xml = $this->input('xml');
$data = xml_decode($xml);
// Re-generate XML to enforce DOCTYPE disallowance
$writer = Writer::inMemory()->configure(disallow_doctype());
$writer->write($data);
$secureXml = $writer->map(memory_output());
return validator(['xml' => $secureXml], ['xml' => 'required|string'])->validate();
}
Return XML responses in Laravel with security headers:
use VeeWee\Xml\encoding\xml_encode;
use VeeWee\Xml\Writer\Configurator\disallow_doctype;
return response()->xml(
xml_encode($data),
200,
[
'Content-Type' => 'application/xml',
'X-Content-Security' => 'no-doctype'
]
);
use VeeWee\Xml\Writer\Writer;
use 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());
}
}
PHP 8.4+ Requirement for v4+:
veewee/xml@^4.0, ensure your project runs on PHP 8.4+.^3.3 (supports 8.2-8.5).Memory-Safe Reader vs. DOM:
Reader is memory-efficient for large files, but lacks DOM traversal methods.DOM component for complex XPath queries or DOM manipulation.Namespaces in XML:
namespace_attribute will cause malformed XML.prefixed_attribute) require the namespace to be declared first.Raw XML Injection:
raw() builder bypasses escaping. Only use it for trusted content.Error Handling:
try-catch:
try {
$validator->validate('data.xml');
} catch (XmlException $e) {
Log::error($e->getMessage());
}
Indentation Quirks:
Writer (not DOM or Reader).New: DOCTYPE Security Risk (v4.12.0):
disallow_doctype() in production environments:
$writer->configure(disallow_doctype());
Inspect XMLWriter State:
Use memory_output() to debug:
$writer = Writer::inMemory()->configure(disallow_doctype());
$writer->write($xmlStructure);
$output = $writer->map(memory_output());
dd($output); // Inspect raw XML (should lack DOCTYPE)
Validate XML Against Schema:
$validator = new Validator('schema.xsd');
$errors = $validator->validate('data.xml', true); // Return errors instead of throwing
dd($errors);
Check for DOCTYPE Presence:
use VeeWee\Xml\Reader\Reader;
$reader = Reader::fromFile('data.xml');
if ($reader->hasDoctype()) {
throw new \RuntimeException('DOCTYPE detected! Use disallow_doctype() configurator.');
}
Performance with Large Files:
Reader over DOM for files >10MB.Writer::forStream() and enforce security:
$writer = Writer::forStream($stream)
->configure(disallow_doctype());
How can I help you explore Laravel packages today?