PHPackages                             lyte/xml - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Parsing &amp; Serialization](/categories/parsing)
4. /
5. lyte/xml

ActiveLibrary[Parsing &amp; Serialization](/categories/parsing)

lyte/xml
========

Safer and simpler XML handling for PHP

1.0.0(8y ago)09.1k2[4 issues](https://github.com/neerolyte/php-lyte-xml/issues)MITPHPPHP &gt;=5.4

Since Jun 21Pushed 8y ago1 watchersCompare

[ Source](https://github.com/neerolyte/php-lyte-xml)[ Packagist](https://packagist.org/packages/lyte/xml)[ RSS](/packages/lyte-xml/feed)WikiDiscussions master Synced 3d ago

READMEChangelogDependencies (3)Versions (2)Used By (0)

php-lyte-xml
============

[](#php-lyte-xml)

[![Build Status](https://camo.githubusercontent.com/f95f45b190a2ede6d73694f1bc6292340f231df4044d43353cb07fdd30d8ee13/68747470733a2f2f6170692e7472617669732d63692e6f72672f6e6565726f6c7974652f7068702d6c7974652d786d6c2e7376673f6272616e63683d6d6173746572)](https://travis-ci.org/neerolyte/php-lyte-xml)[![Test Coverage](https://camo.githubusercontent.com/49147be93146bfe39207ba59f996284e912b15cd768dabe9c697e4337b41e5a4/68747470733a2f2f636f6465636c696d6174652e636f6d2f6769746875622f6e6565726f6c7974652f7068702d6c7974652d786d6c2f6261646765732f636f7665726167652e737667)](https://codeclimate.com/github/neerolyte/php-lyte-xml/coverage)[![Code Climate](https://camo.githubusercontent.com/5f16303a6078e28ea59cfe45574e285c9e4d260a509b0df9dd4bd5a26303da51/68747470733a2f2f636f6465636c696d6174652e636f6d2f6769746875622f6e6565726f6c7974652f7068702d6c7974652d786d6c2f6261646765732f6770612e737667)](https://codeclimate.com/github/neerolyte/php-lyte-xml)[![Issue Count](https://camo.githubusercontent.com/a9d816c47e4bdc0901f2c88cd71fcbc58b66e9e2d6ef7705a0163a59b5d07358/68747470733a2f2f636f6465636c696d6174652e636f6d2f6769746875622f6e6565726f6c7974652f7068702d6c7974652d786d6c2f6261646765732f69737375655f636f756e742e737667)](https://codeclimate.com/github/neerolyte/php-lyte-xml)

The base classes for XML work in php have a few little quirks that annoy me a lot, this is a simple collection of fixes for those annoyances.

Some of what I'm trying to put in is going to be purely experimental, so use at you're own risk :)

Examples
========

[](#examples)

- [Nested CDATA in XMLWriter](#nested-cdata-in-xmlwriter)
- [XMLReader expanded DOMNodes actually have ownerDocuments](#expanding-to-a-domnode-from-xmlreader)
- [Lazy XPaths - XPaths that actually work in a OO manner](#lazy-xpaths)
- [Contextified DOMNode XPath functions](#contextified-domnode-xpath-functions)
- [Key/Value pair iterator](#keyvalue-pair-iterator)
- [saveXML() anywhere](#savexml-anywhere)
- [Translate to UTF8 on the fly](#translate-to-utf8-on-the-fly)

Nested CDATA in XMLWriter
-------------------------

[](#nested-cdata-in-xmlwriter)

There's a [fairly well known](http://en.wikipedia.org/wiki/CDATA#Nesting) method for working around the fact that XML doesn't actually let you nest a CDATA tag inside another one, but XMLWriter doesn't bother to apply this fix for you. Which is a problem if for instance you're transporting HTML fragments within another XML format.

With `XMLWriter`:

```
$writer = new \XMLWriter();
$writer->openMemory();
$writer->writeCData('');
echo $writer->flush()."\n";
```

will result in:

```
]]>

```

which isn't valid XML!

Use `Lyte\XML\XMLWriter` instead and you'll get something that works the way you expect:

```
use Lyte\XML\XMLWriter;
$writer = new XMLWriter();
$writer->openMemory();
$writer->writeCData('');
echo $writer->flush()."\n";
```

will result in:

```
]]>

```

Expanding to a DOMNode from XMLReader
-------------------------------------

[](#expanding-to-a-domnode-from-xmlreader)

With the native `XMLReader` if you call `expand()` you get back a `DOMNode`, which has its `ownerDocument` property set to `null`, which makes things like using a `DOMXPath` or saving it to an XML string snippet quite difficult.

E.g. with the native `XMLReader`:

```
$reader = new \XMLReader();
$reader->xml('bar');
$reader->read();
$node = $reader->expand();
echo $node->ownerDocument->saveXML();
```

results in:

```
PHP Fatal error:  Call to a member function saveXML() on a non-object in - on line 6

```

... oops!

With `Lyte\XML\XMLReader` if you expand a node it creates the `ownerDocument` for you:

```
use Lyte\XML\XMLReader;
$reader = new XMLReader();
$reader->xml('bar');
$reader->read();
$node = $reader->expand();
echo $node->ownerDocument->saveXML();
```

works this time:

```

bar

```

Lazy XPaths
-----------

[](#lazy-xpaths)

PHP has fairly relaible `XPath` support in the form of `DOMXPath`, but it's not directly attached to anything, breaking your nice OO context because now you either need to pass around two objects or continually reinstatiate your `DOMXPath` object.

`Lyte\XML\DOMDocument` will lazily create a `DOMXPath` object for use if you just ask for it, e.g. with the native `DOMDocument`:

```
$doc = new \DOMDocument();
$doc->load('');
$xpath = new \DOMXPath($doc);
// and now I've got to pass around $doc and $xpath or recreate $xpath many times
```

with `Lyte\XML\DOMDocument`:

```
use Lyte\XML\DOMDocument;
$doc = new DOMDocument();
$doc->loadXML('');
// now I can just use the xpath (the xpath property gets instantiated to a Lyte\XML\DOMXPath as it's requested)
$nodes = $doc->xpath->query('/foo');
```

Contextified DOMNode XPath functions
------------------------------------

[](#contextified-domnode-xpath-functions)

Normally to run a XPath in a specific context you have to do a fair bit of set up, e.g.:

```
$doc = new \DOMDocument();
$doc->loadXML('onetwo');
$xpath = new \DOMXPath($doc);
$node = $doc->firstChild;
$nodes = $xpath->query('foo/text()', $node);
```

but `Lyte\XML\DOMNode` provides XPath functions directly that are already contextified:

```
use Lyte\XML\DOMDocument;
$doc = new DOMDocument();
$doc->loadXML('onetwo');
$nodes = $doc->firstChild->xPathQuery('foo/text()');
```

There's also a `Lyte\XML\DOMNode::xPathEvaluate()` function that's synonymous with `DOMXPath::evaluate()` with the context already filled out.

Key/Value pair iterator
-----------------------

[](#keyvalue-pair-iterator)

I seem to have to parse XML with key pairs a lot, e.g:

```

	value1
	value2
	...
	value3

```

With `Lyte\XML\DOMNodeList` I've provided a `toPairs()` function to simplify this operation:

```
// once you have a node with the key/pairs in it:
$node = ...;
// you can just iterate over it:
foreach ($node->childNodes->toPairs() as $k => $v) {
	...
}
```

saveXML() anywhere
------------------

[](#savexml-anywhere)

There's a commonish trick to get the XML just of a subtree of an XML DOM using `ownerDocument` like so:

```
$xml = $node->ownerDocument->saveXML($node);
```

with a `Lyte\XML\DOMNode` you can just ask it to save the XML directly:

```
$xml = $node->saveXML();
```

Translate to UTF8 on the fly
============================

[](#translate-to-utf8-on-the-fly)

Lyte\\XML\\XMLWriter
--------------------

[](#lytexmlxmlwriter)

Simply state what the source encoding is and have it transcoded on the fly, e.g:

```
use Lyte\XML\XMLWriter;
$writer = new Lyte\XML\XMLWriter();
$writer->openMemory();
$writer->setSourceCharacterEncoding('Windows-1252');
$writer->text("Don\x92t you hate word quotes?\n");
echo $writer->flush();
```

Produces:

```
Don’t you hate word quotes?

```

Lyte\\XML\\DOMDocument::loadHTML()
----------------------------------

[](#lytexmldomdocumentloadhtml)

Load HTML from an arbitrary character set:

```
use Lyte\XML\DOMDocument;
$dom = new DOMDocument();
$html = "\x93bendy quotes\x94";
$encoding = 'Windows-1252';
$dom->loadHTML($html, $encoding);

```

Requirements
============

[](#requirements)

PHP 5.4+ or HHVM.

Caveats
=======

[](#caveats)

Most of the classes I've created do not directly inherit from the XML ones, e.g. `new Lyte\XML\DOMDocument() instanceof \DOMDocument` is false. I've currently done this because to avoid duplicating memory all over the place and reserializing too much of the XML, I really need to use the decorator pattern, but even with PHP's [magic methods](http://php.net/manual/en/language.oop5.magic.php) I can't find a way to both inherit and decorate an object. I've even looked in to using the [Reflection API](http://php.net/manual/en/book.reflection.php) to walk the upstream classes and selectively `eval` a new class in to existence, but ran in to problems with many of public properties getting updated at odd times by the base DOM classes.

The net result is a bunch of objects that walk like ducks, talk like ducks, but you might have trouble in weird corner cases convincing PHP that they're ducks, but still send me any bugs when you run in to issues.

If anyone can solve this, lodge an issue :)

###  Health Score

30

—

LowBetter than 64% of packages

Maintenance20

Infrequent updates — may be unmaintained

Popularity20

Limited adoption so far

Community9

Small or concentrated contributor base

Maturity58

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Unknown

Total

1

Last Release

3250d ago

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/64971?v=4)[futuristicvlad](/maintainers/lyte)[@lyte](https://github.com/lyte)

---

Top Contributors

[![neerolyte](https://avatars.githubusercontent.com/u/1070702?v=4)](https://github.com/neerolyte "neerolyte (49 commits)")

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/lyte-xml/health.svg)

```
[![Health](https://phpackages.com/badges/lyte-xml/health.svg)](https://phpackages.com/packages/lyte-xml)
```

###  Alternatives

[mtdowling/jmespath.php

Declaratively specify how to extract elements from a JSON document

2.0k472.8M135](/packages/mtdowling-jmespathphp)[opis/closure

A library that can be used to serialize closures (anonymous functions) and arbitrary data.

2.6k230.0M284](/packages/opis-closure)[masterminds/html5

An HTML5 parser and serializer.

1.8k242.8M229](/packages/masterminds-html5)[sabberworm/php-css-parser

Parser for CSS Files written in PHP

1.8k191.2M65](/packages/sabberworm-php-css-parser)[michelf/php-markdown

PHP Markdown

3.5k52.4M345](/packages/michelf-php-markdown)[jms/metadata

Class/method/property metadata management in PHP

1.8k152.8M88](/packages/jms-metadata)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
