Search by

ottosmops / xmltoolkit

ottosmops

Add and remove XML tags and attributes.

Package info

github.com/ottosmops/xmltoolkit

pkg:composer/ottosmops/xmltoolkit

Statistics

Installs: 56

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

v1.2.0 2026-10-29 17:17 UTC

This package is auto-updated.

Last update: 2026-10-29 17:17:38 UTC


README

Build Status License Total Downloads

Xmltoolkit is a PHP class that provides various utilities for manipulating XML documents. It allows loading XML from files or strings, performing XPath queries (with namespace support), and modifying XML elements and attributes.

Installation

Use Composer to install the package:

composer require ottosmops/xmltoolkit

Usage

require 'vendor/autoload.php';

use Ottosmops\Xmltoolkit\Xmltoolkit;

$xml = new Xmltoolkit();
$xml->loadFromFile('example.xml');
$xml->renameTagByXPath('//a', 'ref');
$xml->saveToFile('example.xml', true); // pretty print

// Find elements by attribute value
$elements = $xml->findElementsByAttributeValue('type', 'special');

// Replace attribute value
$xml->replaceAttributeValue('type', 'special', 'normal');

// Find elements by text content
$elements = $xml->findElementsByTextContent('oldtext');

// Replace text content
$xml->replaceElementTextContent('oldtext', 'newtext');

// Save as pretty-printed string
$prettyXml = $xml->saveToString(true);

Namespace Support

You can register XML namespaces for XPath queries:

$xml = new Xmltoolkit();
$xml->registerNamespaces(['ns' => 'http://example.com/ns']);
$xml->loadFromFile('example.xml');
$nodes = $xml->queryXPath('//ns:tag');

Preserve Formatting

When editing source files under version control, keep the diff small:

$xml = new Xmltoolkit();
$xml->preserveFormatting();
$xml->loadFromFile('letter.xml');
// ... edit ...
$xml->saveToFile('letter.xml');

The output keeps the source's XML declaration (or its absence), its final newline (or its absence) and its non-ASCII character references such as &#x200A;. A restored reference replaces every occurrence of that character, including ones the source had written literally. What DOM cannot keep: line breaks and spaces inside start tags, <a></a> (becomes <a/>) and whitespace after the root element.

Wrap Text Matches

Tag names in running text, e.g. persons in TEI, deciding match by match:

$xml = new Xmltoolkit();
$xml->registerNamespaces(['tei' => 'http://www.tei-c.org/ns/1.0']);
$xml->preserveFormatting();
$xml->loadFromFile('letter.xml');

$count = $xml->wrapTextMatches(
    "/(?<!\w)Thurneysen(?:'?e?n?s)?(?!\w)/u",
    function (string $match, \DOMText $node, int $line, int $offset) {
        // ask the user, look up an ID ... or return null to leave the match
        $persName = $node->ownerDocument->createElementNS($node->lookupNamespaceURI(null), 'persName');
        $persName->setAttribute('ref', 'kbga-actors-403');
        return $persName;
    },
    within: '//tei:text',
    exclude: ['tei:bibl', 'tei:note', 'tei:persName'],
);
$xml->saveToFile('letter.xml');

Only text nodes are searched, so matches inside tags, attributes or excluded elements cannot occur, and names spanning element boundaries (Eduard <lb/>Thurneysen) are not found. Create the element in the document's namespace (createElementNS), otherwise it is serialized with xmlns="". $offset is the byte offset of the match in $node->data. $line is the match's line in the source, computed from the parent element's start tag; line breaks inside start tags of preceding siblings shift it, and it is 0 below elements created after loading.

Regex

$elements = $xml->findElementsByAttributeRegex('type', '/^sp.*/');
$xml->replaceAttributeValueRegex('type', '/^sp.*/', 'normal');
$elements = $xml->findElementsByTextRegex('/old.*/');
$xml->replaceElementTextRegex('/old.*/', 'newtext');

Methods

Loading and saving

All other methods throw a LogicException if no document has been loaded successfully.

Load an XML file into the DOM object and ensure it is UTF-8 encoded.

public function loadFromFile(string $filePath): bool

Load an XML string into the DOM object and ensure it is UTF-8 encoded.

public function loadFromString(string $xmlString): bool

Load an XML/HTML fragment. The fragment is wrapped in a <root> element.

public function loadFromFragment(string $xmlFragment): bool

Save the XML document to a file and ensure it is UTF-8 encoded.

public function saveToFile(string $filePath, bool $prettyPrint = false): bool

Return the XML as a string and ensure it is UTF-8 encoded.

public function saveToString(bool $prettyPrint = false): string

Register namespaces for XPath queries (['prefix' => 'namespaceURI']). Can be called before or after loading.

public function registerNamespaces(array $namespaces): void

Keep the source's XML declaration, final newline and character references when saving (see Preserve Formatting). Can be called before or after loading.

public function preserveFormatting(bool $preserve = true): void

Find and replace

Find elements by attribute value.

public function findElementsByAttributeValue(string $attributeName, string $attributeValue): array

Replace attribute value for all elements with a given attribute value.

public function replaceAttributeValue(string $attributeName, string $oldValue, string $newValue): void

Find elements by text content.

public function findElementsByTextContent(string $textContent): array

Replace text content for all elements with a given text content.

public function replaceElementTextContent(string $oldText, string $newText): void

Find and replace with regex

Find elements by attribute value using regex.

public function findElementsByAttributeRegex(string $attributeName, string $pattern): array

Replace attribute value using regex.

public function replaceAttributeValueRegex(string $attributeName, string $pattern, string $replacement): void

Find elements by text content using regex. Only elements without child elements are matched.

public function findElementsByTextRegex(string $pattern): array

Replace text content using regex.

public function replaceElementTextRegex(string $pattern, string $replacement): void

XPath

Run an arbitrary XPath query and return the found nodes as an array of XML strings.

public function queryXPath(string $xpathExpression): array

Rename a tag found by an XPath expression.

public function renameTagByXPath(string $xpathExpression, string $newTagName): void

Rename an attribute found by an XPath expression.

public function renameAttributeByXPath(string $xpathExpression, string $oldAttributeName, string $newAttributeName): void

Add a new attribute to a tag found by an XPath expression.

public function addAttributeByXPath(string $xpathExpression, string $attributeName, string $attributeValue): void

Remove an attribute from a tag found by an XPath expression.

public function removeAttributeByXPath(string $xpathExpression, string $attributeName): void

Append an HTML string to the nodes found by an XPath expression (as last child).

public function appendHtmlToXPath(string $xpathExpression, string $htmlString): void

Wrap regex matches in text nodes with the elements a callback returns (see Wrap Text Matches). Returns the number of wrapped matches.

public function wrapTextMatches(string $pattern, callable $wrapper, string $within = '/', array $exclude = []): int

Remove an element found by an XPath expression.

public function removeElementByXPath(string $xpathExpression): void

Wrap an element found by an XPath expression with a new element.

public function wrapElementByXPath(string $xpathExpression, string $wrapperTagName): void

Remove an element but keep its content (unwrap the element) based on an XPath expression.

public function unwrapElementByXPath(string $xpathExpression): void

Tests

Run the tests with PHPUnit:

vendor/bin/phpunit