Weave Code
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

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.

View on GitHub
Deep Wiki
Context7

DOM Component

The DOM Components operate on XML documents through the DOM API. Instead of solely wrapping a XMLDocument with our own class, we embrace the fact that the DOM implementation is leaky. This package provides a set of composable tools that allow you to safely work with the DOM extension.

Since not all code is in one big master class, you will find that it is not too hard to write your own extensions!

Examples

use \Dom\XMLDocument;
use Psl\Type;
use VeeWee\Xml\Dom\Configurator;
use VeeWee\Xml\Dom\Document;
use VeeWee\Xml\Dom\Loader;
use VeeWee\Xml\Dom\Validator;
use VeeWee\Xml\Dom\Xpath;

$doc = Document::fromLoader(
    Loader\xml_file_loader('data.xml', LIBXML_NOBLANKS, 'UTF-8'),
    Configurator\format_output($debug),
    Configurator\validator(
        Validator\internal_xsd_validator()
    ),
    new MyCustomMergeImportsConfigurator(),
);

$xpath = $doc->xpath(
    Xpath\Configurator\namespaces([
        'soap' => 'http://schemas.xmlsoap.org/wsdl/',
        'xsd' => 'http://www.w3.org/1999/XMLSchema',
    ])
);

$currentNode = $xpath->querySingle('//products');
$count = $xpath->evaluate('count(.//item)', Type\int(), $currentNode);

Of course, the example above only gives you a small idea of all the implemented features. Let's find out more by segregating the DOM component into its composable blocks:

  • Assertions: Assert if a Node is of a specific type.
  • Builders: Let you build XML by using a declarative API.
  • Collection: A wrapper for dealing with lists of nodes.
  • Configurators: Specify how you want to configure your DOM document.
  • Loaders: Determine where the XML should be loaded from.
  • Locators: Enables you to locate specific XML elements.
  • Manipulators: Allows you to manipulate any DOM document.
  • Mappers: Converts the DOM document to something else.
  • Predicates: Check if a Node is of a specific type.
  • Traverser: Traverse over a complete DOM tree and perform visitor-based manipulations.
  • Validators: Validate the content of your XML document.
  • XPath: Query for specific elements based on XPath queries.

Assertions

Assert if a Node is of a specific type.

assert_attribute

Assert if a node is of type Dom\Attr.

use Psl\Type\Exception\AssertException;
use function VeeWee\Xml\Dom\Assert\assert_attribute;

try {
    assert_attribute($someNode)
} catch (AssertException $e) {
    // Deal with it
}

assert_cdata

Assert if a node is of type Dom\CDATASection.

use Psl\Type\Exception\AssertException;
use function VeeWee\Xml\Dom\Assert\assert_cdata;

try {
    assert_cdata($someNode)
} catch (AssertException $e) {
    // Deal with it
}

assert_document

Assert if a node is of type Dom\XMLDocument.

use Psl\Type\Exception\AssertException;
use function VeeWee\Xml\Dom\Assert\assert_document;

try {
    assert_document($someNode)
} catch (AssertException $e) {
    // Deal with it
}

assert_dome_node_list

Assert if a variable is of type Dom\NodeList.

use Psl\Type\Exception\AssertException;
use function VeeWee\Xml\Dom\Assert\assert_dom_node_list;

try {
    assert_dom_node_list($someVar)
} catch (AssertException $e) {
    // Deal with it
}

assert_element

Assert if a node is of type Dom\Element.

use Psl\Type\Exception\AssertException;
use VeeWee\Xml\Dom\Document;
use function VeeWee\Xml\Dom\Assert\assert_element;

$doc = Document::fromXmlFile('some.xml');
$item = $doc->xpath()->query('item')->item(0);

use Psl\Type\Exception\AssertException;
use function VeeWee\Xml\Dom\Assert\assert_document;

try {
    assert_element($someNode)
} catch (AssertException $e) {
    // Deal with it
}

Builders

Lets you build XML by using a declarative API.

use VeeWee\Xml\Dom\Document;
use function VeeWee\Xml\Dom\Builder\attribute;
use function VeeWee\Xml\Dom\Builder\children;
use function VeeWee\Xml\Dom\Builder\element;
use function VeeWee\Xml\Dom\Builder\namespaced_element;
use function VeeWee\Xml\Dom\Builder\value;
use function VeeWee\Xml\Dom\Manipulator\append;

$doc = Document::empty();
$doc->manipulate(
    append(...$doc->build(
        element('root', children(
            element('foo',
                attribute('bar', 'baz'),
                value('hello')
            ),
            namespaced_element('http://namespace', 'foo',
                attribute('bar', 'baz'),
                children(
                    element('hello', value('world'))
                )
            )
        ))
    ))
);
<root>
    <foo bar="baz">hello</foo>
    <foo bar="baz" xmlns="http://namespace">
        <hello>world</hello>
    </foo>
</root>

attribute

Operates on a Dom\Element and adds the attribute with specified key and value

use function VeeWee\Xml\Dom\Builder\attribute;
use function VeeWee\Xml\Dom\Builder\element;

element('foo',
    attribute('bar', 'baz')
);
<foo bar="baz" />

attributes

Operates on a Dom\Element and adds multiple attributes with specified key and value

use function VeeWee\Xml\Dom\Builder\attribute;
use function VeeWee\Xml\Dom\Builder\element;

element('foo',
    attributes([
        'hello' => 'world',
        'bar' => 'baz',
    ])
);
<foo hello="world" bar="baz" />

default_xmlns_attribute

Operates on a Dom\Element and adds a default xmlns attribute. Given how XML serialization works in PHP, this function only works on already prefixed + namespaced elements:

use function VeeWee\Xml\Dom\Builder\namespaced_element;
use function VeeWee\Xml\Dom\Builder\default_xmlns_attribute;

namespaced_element('uri://x', x:hello', default_xmlns_attribute(http://default'));

cdata

Operates on a Dom\Node and creates a Dom\CDATASection. It can contain a set of configurators that can be used to dynamically change the cdata's contents.

use function VeeWee\Xml\Dom\Builder\attribute;
use function VeeWee\Xml\Dom\Builder\element;
use function VeeWee\Xml\Dom\Builder\cdata;
use function VeeWee\Xml\Dom\Builder\children;

element('hello', children(
    cdata('<html>world</html>')
));
<hello><![CDATA[<html>world</html>]]></hello>

children

Operates on a Dom\Node and attaches multiple child nodes.

use function VeeWee\Xml\Dom\Builder\element;
use function VeeWee\Xml\Dom\Builder\children;

element('hello',
    children(
        element('world'),
        element('you')
    )
);
<hello>
    <world />
    <you />
</hello>

element

Operates on a Dom\Node and creates a new element. It can contain a set of configurators that can be used to specify the attributes, children, value, ... of the element.

use function VeeWee\Xml\Dom\Builder\element;

element('hello', ...$configurators);
<hello />

escaped_value

Operates on a Dom\Element and sets the node value. All XML entities <>"' will be escaped.

use function VeeWee\Xml\Dom\Builder\element;
use function VeeWee\Xml\Dom\Builder\escaped_value;

element('hello', escaped_value('<"\'>'));
<hello>&lt;&quot;&apos;&gt;</hello>

namespaced_attribute

Operates on a Dom\Element and adds a namespaced attribute with specified key and value

use function VeeWee\Xml\Dom\Builder\element;
use function VeeWee\Xml\Dom\Builder\namespaced_attribute;

element('foo',
    namespaced_attribute('https://acme.com', 'acme:hello', 'world')
);
<foo xmlns:acme="https://acme.com" acme:hello="world" />

namespaced_attributes

Operates on a Dom\Element and adds a namespaced attribute with specified key and value

use function VeeWee\Xml\Dom\Builder\element;
use function VeeWee\Xml\Dom\Builder\namespaced_attributes;

element('foo',
    namespaced_attributes('https://acme.com', [
        'acme:hello' => 'world',
        'acme:foo' => 'bar',
    ])
);
<foo xmlns:acme="https://acme.com" acme:hello="world" acme:foo="bar" />

namespaced_element

Operates on a Dom\Node and creates a new namespaced element. It can contain a set of configurators that can be used to specify the attributes, children, value, ... of the element.

use function VeeWee\Xml\Dom\Builder\namespaced_element;

namespaced_element('http://acme.com', 'hello', ...$configurators);
<hello xmlns="http://acme.com" />

nodes

Operates on a Dom\XMLDocument and is the builder that is being called by the Document::manipulate method. It can return one or more Dom\Node objects

use function VeeWee\Xml\Dom\Builder\element;
use function VeeWee\Xml\Dom\Builder\nodes;

nodes(
    element('item'),
    static fn (XMLDocument $document): array => [
        element('item')($document),
        element('item')($document),
    ],
    element('item'),
    element('item')
)($document);

value

Operates on a Dom\Element and sets the node value.

use function VeeWee\Xml\Dom\Builder\element;
use function VeeWee\Xml\Dom\Builder\value;

element('hello', value('world'));

xmlns_attribute

Operates on a Dom\Element and adds a xmlns namespace attribute.

use function VeeWee\Xml\Dom\Builder\element;
use function VeeWee\Xml\Dom\Builder\xmlns_attribute;

element('hello', xmlns_attribute('ns', 'http://ns.com'));

xmlns_attributes

Operates on a Dom\Element and adds multiple xmlns namespace attributes.

use function VeeWee\Xml\Dom\Builder\element;
use function VeeWee\Xml\Dom\Builder\xmlns_attributes;

element('hello', xmlns_attributes(['ns' => 'http://ns.com']));
<hello>world</hello>

Collection

This package provides a type-safe replacement for Dom\NodeList with few more options. Some examples:

use Dom\Element;
use Psl\Type;
use VeeWee\Xml\Dom\Collection\NodeList;
use function VeeWee\Xml\Dom\Locator\Node\value;

$totalPrice = NodeList::fromNodeList($list)
    ->expectAllOfType(Element::class)
    ->filter(fn(Element $element) => $element->nodeName === 'item')
    ->eq(0)
    ->siblings()
    ->children()
    ->query('./price')
    ->reduce(
        static fn (int $total, Element $price): int
            => $total + value($price, Type\int()),
        0
    );

Most of the functions on the NodeList class are straight forward and documented elsewere. Feel free to scroll through or let your IDE autocomplete the class to find out what is inside there!

Configurators

Specify how you want to configure your DOM document.

canonicalize

The loader runs canonicalization (C14N) on the document and applies some other optimalizations like cdata stripping and basic namespace optimizations.

use VeeWee\Xml\Dom\Document;
use function VeeWee\Xml\Dom\Configurator\canonicalize;

Document::fromXmlString(
    $xml,
    canonicalize()
);

comparable

The loader runs following optimization on the provided XML, in order to make it comparable:

use VeeWee\Xml\Dom\Document;
use function VeeWee\Xml\Dom\Configurator\comparable;

Document::fromXmlFile(
    $file,
    comparable()
);

document_uri

Allows you to keep track of the document uri, even if you are using an in-memory string. Internally, it sets Dom\XMLDocument::$documentURI, which gets used as file in the error-handling issues component.

use VeeWee\Xml\Dom\Document;
use function VeeWee\Xml\Dom\Configurator\document_uri;

$wsdl = 'http://myservice.com?wsdl';
Document::fromXmlString(
    $loadFromHttp($wsdl),
    document_uri($wsdl)
);

format_output

Specify if the saved XML output should be formatted or not. This can make the output of the DOM document human-readable or with trimmed spaces.

use VeeWee\Xml\Dom\Document;
use function VeeWee\Xml\Dom\Configurator\format_output;
use function VeeWee\Xml\Dom\Loader\xml_file_loader;

$debug = true;
$doc = Document::fromLoader(
    // If the input has blank nodes, You'll need to use LIBXML_NOBLANKS in order to change the output format. 
    xml_file_loader('data.xml', LIBXML_NOBLANKS)
    format_output($debug),
);

normalize

This configurator normalizes an XML file to return the XMLDocument back in a "normal" form.

use VeeWee\Xml\Dom\Document;
use function VeeWee\Xml\Dom\Configurator\normalize;

Document::fromUnsafeDocument(
    $document,
    normalize()
);

optimize_namespaces

This configurator detects all and renames all namespaces in order to optimize them. The optimasation itself, must be triggered by using a load function with LIBXML_NSCLEAN. This optimization is included in the comparable() and canonicalize() configurator.

use VeeWee\Xml\Dom\Document;
use function VeeWee\Xml\Dom\Configurator\optimize_namespaces;

Document::fromUnsafeDocument(
    $document,
    optimize_namespaces('prefix')
);

promote_namespaces

This configurator moves all prefixed namespace declarations from child elements to the document root element. Unlike optimize_namespaces, it preserves the original prefix names. This is useful when dealing with servers that require all namespace declarations on the root element.

use VeeWee\Xml\Dom\Document;
use function VeeWee\Xml\Dom\Configurator\promote_namespaces;

Document::fromUnsafeDocument(
    $document,
    promote_namespaces()
);

pretty_print

Makes the output of the DOM document human-readable. This reloads the DOM document and reformats the nodes. Consider using format_output instead if you don't want to re-load the XML document.

use VeeWee\Xml\Dom\Document;
use function VeeWee\Xml\Dom\Configurator\pretty_print;

$doc = Document::fromXmlFile(
    'data.xml',
    pretty_print(),
);

traverse

Takes a list of Visitors as argument and traverses over de DOM tree. The visitors can be used to do DOM manipulations.

use VeeWee\Xml\Dom\Document;
use VeeWee\Xml\Dom\Traverser\Visitor;
use function VeeWee\Xml\Dom\Configurator\traverse;

$doc = Document::fromXmlFile(
    $file,
    traverse(
        new Visitor\SortAttributes(),
    )
);

trim_spaces

Trims all whitespaces from the DOM document in order to make it as small as possible in bytesize. This reloads the DOM document and reformats the nodes. Consider using format_output instead if you don't want to re-load the XML document.

use VeeWee\Xml\Dom\Document;
use function VeeWee\Xml\Dom\Configurator\trim_spaces;

$doc = Document::fromXmlFile(
    'data.xml',
    trim_spaces(),
);

utf8

Marks the DOM document as UTF-8. There are 2 ways to do this: either whilst loading or afterward through a configurator.

use VeeWee\Xml\Dom\Document;
use function VeeWee\Xml\Dom\Configurator\utf8;
use function VeeWee\Xml\Dom\Loader\xml_file_loader;

$doc = Document::fromLoader(
    xml_file_loader('data.xml', override_encoding: 'UTF-8'),
    utf8(),
);

validator

Takes a Validator as argument and validates the DOM. Additionally, you can specify a maximum error level. If this level is reached, an exception is thrown.

use VeeWee\Xml\Dom\Document;
use VeeWee\Xml\ErrorHandling\Issue\Level;
use function VeeWee\Xml\Dom\Configurator\validator;
use function VeeWee\Xml\Dom\Validator\internal_xsd_validator;

$doc = Document::fromXmlFile(
    'data.xml',
    validator(internal_xsd_validator(), Level::warning())
);

Writing your own configurator

A configurator can be any callable that takes a Dom\XMLDocument and configures it:

namespace VeeWee\Xml\Dom\Configurator;

use \Dom\XMLDocument;

interface Configurator
{
    public function __invoke(XMLDocument $document): XMLDocument;
}

You can apply the configurator as followed:

use VeeWee\Xml\Dom\Document;
use VeeWee\Xml\Dom\Configurator;

// On an empty XML document
$document = Document::configure(...$configurators);

// On an existing XML document.
$document = Document::fromLoader($loader, ...$configurators);

Loaders

xml_document_loader

Loads an XML document from an external Dom\XMLDocument. It copies the content of the external document into a new Dom\XMLDocument and re-applies e.g. LIBXML flags.

use VeeWee\Xml\Dom\Document;
use VeeWee\Xml\Dom\Loader\xml_document_loader;

$doc = Document::fromLoader(xml_document_loader($originalDocument, options: LIBXML_NOCDATA, override_encoding: 'UTF-8'));

xml_file_loader

Loads an XML document from a file.

use VeeWee\Xml\Dom\Document;
use function VeeWee\Xml\Dom\Loader\xml_file_loader;

$doc = Document::fromXmlFile('some-xml.xml', ...$configurators);

// or

$doc = Document::fromLoader(xml_file_loader($file, options: LIBXML_NOCDATA, override_encoding: 'UTF-8'));

xml_node_loader

Loads an XML document from an external Dom\Node.

use VeeWee\Xml\Dom\Document;

$doc = Document::fromXmlNode($someExternalNode, ...$configurators);

xml_string_loader

Loads an XML document from a string.

use VeeWee\Xml\Dom\Document;
use function VeeWee\Xml\Dom\Loader\xml_string_loader;

$doc = Document::fromXmlString('<xml />', ...$configurators);

// or

$doc = Document::fromLoader(xml_string_loader($xml, options: LIBXML_NOCDATA, override_encoding: 'UTF-8'));

Writing your own loader

namespace VeeWee\Xml\Dom\Loader;

use \Dom\XMLDocument;

interface Loader
{
    public function __invoke(): XMLDocument;
}

You can apply the loader as followed:

use VeeWee\Xml\Dom\Document;

$document = Document::fromLoader($loader, ...$configurators);

Locators

Locators can be used to search for specific elements inside your DOM document. The locators are split up based on what they are locating.

Attribute

The attributes locators will return attributes and can be called on a Dom\Node.

attributes_list

This function will look for all attributes on a Dom\Node. For nodes that don't support attributes, you will receive an empty NodeList. The result of this function will be of type NodeList<\Dom\Attr>.

use Dom\Attr;
use function VeeWee\Xml\Dom\Locator\Attribute\attributes_list;

$attributes = attributes_list($element)->sort(
    static fn (Attr $a, Attr $b): int => $a->nodeName <=> $b->nodeName
);

xmlns_attributes_list

This function will look for all xmlns attributes on a Dom\Node. For nodes that don't support attributes, you will receive an empty NodeList. The result of this function will be of type NodeList<Dom\Attr>.

use Dom\Attr;
use function VeeWee\Xml\Dom\Locator\Attribute\xmlns_attributes_list;

$attributes = xmlns_attributes_list($element)->sort(
    static fn (Attr $a, Attr $b): int => $a->prefix <=> $b->prefix
);

Document

The Document locators can be called directly from the Document class. It will return the root document element of the provided XML.

document_element

use VeeWee\Xml\Dom\Document;
use function VeeWee\Xml\Dom\Locator\document_element;

$doc = Document::fromXmlFile('some.xml');
$rootElement = $doc->locate(document_element());

// Since this is a common action, there is also a shortcut:
$doc->locateDocumentElement();

elements_with_namespaced_tagname

use VeeWee\Xml\Dom\Document;
use function VeeWee\Xml\Dom\Locator\elements_with_namespaced_tagname;

$doc = Document::fromXmlFile('some.xml');
$products = $doc->locate(elements_with_namespaced_tagname('http://amazon.com', 'product'));

elements_with_tagname

use VeeWee\Xml\Dom\Document;
use function VeeWee\Xml\Dom\Locator\elements_with_tagname;

$doc = Document::fromXmlFile('some.xml');
$products = $doc->locate(elements_with_tagname('product'));

Element

These locators can be run on Dom\Element instances.

Element\ancestors

Fetch all ancestor elements from a specific Dom\Node.

use function VeeWee\Xml\Dom\Locator\Element\ancestors;

$ancestorNodes = ancestors($element);

Element\children

Fetch all child Dom\Element's from a specific Dom\Node. If you only want all types of children (Dom\Text, ...), you can use the Node\children() locator.

use function VeeWee\Xml\Dom\Locator\Element\children;

$childElements = children($element);

locate_by_namespaced_tag_name

use function VeeWee\Xml\Dom\Locator\Element\locate_by_namespaced_tag_name;

$products = locate_by_namespaced_tag_name($element, 'http://amazon.com', 'product');

locate_by_tag_name

use function VeeWee\Xml\Dom\Locator\Element\locate_by_tag_name;

$products = locate_by_tag_name($element, 'product');

Element\parent_element

use function VeeWee\Xml\Dom\Locator\Element\parent_element;

$products = parent_element($element);

Element\siblings

Fetch all sibling elements from a specific Dom\Node.

use function VeeWee\Xml\Dom\Locator\Element\siblings;

$ancestorNodes = siblings($element);

Node

These locators can be run on any Dom\Node instance.

Node\children

Fetch all child nodes from a specific Dom\Node. This can be any kind of node: Dom\Text, Dom\Element, ... If you only want the element children, you can use the Element\children() locator.

use function VeeWee\Xml\Dom\Locator\Node\children;

$childNodes = children($element);

Node\detect_document

Fetch the Dom\XMLDocument to which a node is linked. If the node is not linked to a document yet, it throws a InvalidArgumentException.

use function VeeWee\Xml\Dom\Locator\Node\detect_document;

$document = detect_document($element);

Node\value

Fetch the value from the provided Dom\Node and coerce it to a specific type.

use Psl\Type;
use function...
`...
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.
codifyo/ts-generator-bundle
andydefer/laravel-cluster
testo/fiber
mintobit/jobqueue
a4sex/maintenance-bundle
a4sex/entity-date-update
a4sex/client-identifier
a4sex/base-utilites
a4sex/key-value-storage
a4sex/micro-status
chilldev/dependency-injection-extra
datinglibre/datinglibre-app-api
biberltd/corebundle
bricre/symfony-bundle-test
biberltd/logbundle
dominium/http-adapter-bundle
dominium/google-analytics
a4sex/auto-clean-entity
christhompsontldr/laravel-inky
spatie/mailcoach-vapor