Skip to content

Commit

Permalink
2.0.0
Browse files Browse the repository at this point in the history
  • Loading branch information
bupy7 committed Jan 6, 2023
1 parent 0701e7c commit d6fc192
Show file tree
Hide file tree
Showing 5 changed files with 241 additions and 110 deletions.
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
xml-constrcutor
===

v2.0.0 [2023-01-06]
---

- Now `bupy7\xml\constructor\XmlConstructor` is a plain PHP class which doesn't extend the `XMLWriter`.
- Call `bupy7\xml\constructor\XmlConstructor::fromArray()` or `bupy7\xml\constructor\XmlConstructor::toOutput()` more
than once is not supported and will throw an exception.
- Some small fixes and enhancements.

v1.3.5 [2022-12-12]
---

Expand Down
11 changes: 11 additions & 0 deletions src/ExceptionInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?php

namespace bupy7\xml\constructor;

/**
* @since 2.0.0
*/
interface ExceptionInterface
{

}
13 changes: 13 additions & 0 deletions src/RuntimeException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php

namespace bupy7\xml\constructor;

use RuntimeException as BaseRuntimeException;

/**
* @since 2.0.0
*/
class RuntimeException extends BaseRuntimeException implements ExceptionInterface
{

}
239 changes: 138 additions & 101 deletions src/XmlConstructor.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,10 @@
use XMLWriter;

/**
* Creating XML document from array.
* Creating an XML document from an array.
*
* Example:
*
* ~~~
* Usage:
*
* $xml = new XmlConstructor();
* $in = [
* [
Expand Down Expand Up @@ -45,149 +44,187 @@
* ];
* $xml->fromArray($in);
* echo $xml->toOutput();
* ~~~
*
* @see http://php.net/manual/ru/ref.xmlwriter.php
* @since 1.0.0
*/
class XmlConstructor extends XMLWriter
class XmlConstructor
{
/**
* @var boolean Flag of completed preparing.
* @var boolean
*/
private $_prepared = false;
private $hasDocumentStart = false;
/**
* @var boolean Flag of added start document tag.
* @since 1.2.0
* @var XMLWriter
*/
private $_startDocument = false;
private $document;

/**
* Constructor of XML document structure.
* @param array $config name-value pairs that will be used to initialize the object
*/
public function __construct(array $config = [])
{
$this->openMemory();
$this->configure($config);
$this->document = new XMLWriter();
$this->document->openMemory();

// see XMLWriter::setIndent() and XMLWriter::setIndentString()
if (isset($config['indentString'])) {
if (is_string($config['indentString'])) {
$this->setIndent($config['indentString']);
}
} else {
$this->setIndent(str_repeat(' ', 4));
}
// see XMLWriter::startDocument()
if (isset($config['startDocument'])) {
if (is_array($config['startDocument'])) {
call_user_func_array([$this, 'setDocumentStart'], $config['startDocument']);
}
} else {
$this->setDocumentStart('1.0', 'UTF-8');
}
}

/**
* Construct elements and texts from an array.
* The array should contain an attribute's name in index part.
* and an attribute's text in value part.
* Make XML document from an array.
* The array should contain an attribute name in index part and an attribute text in value part.
*
* Example:
*
* $xml->fromArray([
* [
* 'tag' => 'root',
* 'elements' => [
* [
* 'tag' => 'tag1',
* 'attributes' => [
* 'attr1' => 'val1',
* 'attr2' => 'val2',
* ],
* ],
* [
* 'tag' => 'tag2',
* 'content' => 'content2',
* ],
* [
* 'tag' => 'tag3',
* 'elements' => [
* [
* 'tag' => 'tag4',
* 'content' => 'content4',
* ],
* ],
* ],
* [
* 'tag' => 'tag4',
* 'content' => '<b>content4</b>',
* 'cdata' => true, // by default - false
* ],
* ],
* ],
* ]);
*
* @param array $in Contains tags, attributes and texts.
* @param array $in XML document structure as PHP array.
* @return static
* @throws RuntimeException
*/
public function fromArray($in)
public function fromArray(array $in)
{
foreach ($in as $element) {
if (!is_array($element) || !isset($element['tag'])) {
continue;
}
$tag = $element['tag'];
$attributes = [];
if (isset($element['attributes']) && is_array($element['attributes'])) {
$attributes = $element['attributes'];
}
$content = null;
if (isset($element['content'])) {
$content = $element['content'];
} elseif (isset($element['elements']) && is_array($element['elements'])) {
$content = $element['elements'];
}
$this->startElement($tag);
if (is_array($attributes)) {
foreach ($attributes as $attribute => $value) {
$this->writeAttribute($attribute, $value);
}
}
if (isset($content)) {
if (is_array($content)) {
$this->fromArray($content);
} else {
if (isset($element['cdata']) && $element['cdata']) {
$this->writeCdata($content);
} else {
$this->text($content);
}
}
}
$this->endElement();
if ($this->document === null) {
throw new RuntimeException('The constructor is closed. You have to create new one to create an XML document'
. ' again.');
}

$this->_fromArray($in);

return $this;
}

/**
* Return the content of a current xml document.
* @return string XML document.
* @throws RuntimeException
* @since 1.1.0
*/
public function toOutput()
{
return $this->preparing()->outputMemory();
}

/**
* Preparing document to output.
* @return static
*/
protected function preparing()
{
if (!$this->_prepared) {
if ($this->_startDocument) {
$this->endDocument();
}
$this->_prepared = true;
if ($this->document === null) {
throw new RuntimeException('The constructor is closed. You have to create new one to flush its again.');
}
return $this;

if ($this->hasDocumentStart) {
$this->document->endDocument();
}

$output = $this->document->outputMemory();

$this->document = null;

return $output;
}

/**
* Configures an object with the initial property values.
* @param array $config name-value pairs that will be used to initialize the object
* @since 1.2.0
* @param string $indent
* @return void
* @see XMLWriter::setIndent()
* @see XMLWriter::setIndentString()
*/
protected function configure(array $config)
private function setIndent($indent)
{
if (isset($config['indentString'])) {
$this->configIndentString($config['indentString']);
} else {
$this->configIndentString(str_repeat(' ', 4));
}

if (isset($config['startDocument'])) {
$this->configStartDocument($config['startDocument']);
} else {
$this->configStartDocument(['1.0', 'UTF-8']);
}
$this->document->setIndent(true);
$this->document->setIndentString($indent);
}

/**
* Toggle indentation on.
* @param string|false $string String used for indenting.
* @since 1.2.0
* @param string $version
* @param string|null $encoding
* @param string|null $standalone
* @return void
* @see XMLWriter::startDocument()
*/
protected function configIndentString($string)
private function setDocumentStart($version = '1.0', $encoding = null, $standalone = null)
{
if ($string !== false) {
$this->setIndent(true);
$this->setIndentString($string);
}
$this->document->startDocument($version, $encoding, $standalone);
$this->hasDocumentStart = true;
}

/**
* Create document tag.
* @param array|false $arguments Arguments of method `startDocument()`.
* @since 1.2.0
* @param array $in
* @return void
*/
protected function configStartDocument($arguments)
private function _fromArray(array $in)
{
if (is_array($arguments)) {
if (call_user_func_array([$this, 'startDocument'], $arguments)) {
$this->_startDocument = true;
foreach ($in as $element) {
if (!is_array($element) || !isset($element['tag'])) {
continue;
}
$tag = $element['tag'];
$attributes = [];
if (isset($element['attributes']) && is_array($element['attributes'])) {
$attributes = $element['attributes'];
}
$content = null;
if (isset($element['content'])) {
$content = $element['content'];
} elseif (isset($element['elements']) && is_array($element['elements'])) {
$content = $element['elements'];
}
$this->document->startElement($tag);
foreach ($attributes as $attribute => $value) {
$this->document->writeAttribute($attribute, $value);
}
if (isset($content)) {
if (is_array($content)) {
$this->_fromArray($content);
} else {
if (isset($element['cdata']) && $element['cdata']) {
$this->document->writeCdata($content);
} else {
$this->document->text($content);
}
}
}
$this->document->endElement();
}
}
}

0 comments on commit d6fc192

Please sign in to comment.