264 lines
5.9 KiB
PHP
264 lines
5.9 KiB
PHP
<?php
|
|
|
|
class stTaskSchedulerImportXmlReader implements stTaskSchedulerImportReaderInterface
|
|
{
|
|
const BOOL_VALUES = [
|
|
'true' => true,
|
|
'yes' => true,
|
|
'false' => false,
|
|
'no' => false,
|
|
];
|
|
|
|
/**
|
|
*
|
|
* @var XMLReader
|
|
*/
|
|
protected $xmlReader;
|
|
|
|
/**
|
|
*
|
|
* @var string
|
|
*/
|
|
protected $file;
|
|
|
|
/**
|
|
*
|
|
* @var string
|
|
*/
|
|
protected $filterNode;
|
|
|
|
/**
|
|
*
|
|
* @var null|int
|
|
*/
|
|
protected $filterNodeDepth;
|
|
|
|
/**
|
|
*
|
|
* @var null|int
|
|
*/
|
|
protected $count = null;
|
|
|
|
/**
|
|
*
|
|
* @var int
|
|
*/
|
|
protected $offset = 0;
|
|
|
|
public function __clone()
|
|
{
|
|
$this->xmlReader = new XMLReader();
|
|
$this->open($this->file);
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @param string $filterNode
|
|
* @param null|int $filterNodeDepth
|
|
* @return void
|
|
*/
|
|
public function __construct(string $filterNode, ?int $filterNodeDepth = null)
|
|
{
|
|
$this->xmlReader = new \XMLReader();
|
|
$this->setNodeFilterCriteria($filterNode, $filterNodeDepth);
|
|
}
|
|
|
|
public function getFiletypeExtension(): string
|
|
{
|
|
return 'xml';
|
|
}
|
|
|
|
public function setNodeFilterCriteria(string $node, ?int $depth = null)
|
|
{
|
|
$this->filterNode = $node;
|
|
$this->filterNodeDepth = $depth;
|
|
}
|
|
|
|
public function open(string $file): bool
|
|
{
|
|
$this->file = $file;
|
|
$this->offset = 0;
|
|
|
|
return $this->xmlReader->open($file);
|
|
}
|
|
|
|
public function isValid(): bool
|
|
{
|
|
$result = $this->getNextNode();
|
|
|
|
$this->rewind();
|
|
|
|
return $result;
|
|
}
|
|
|
|
public function rewind(): void
|
|
{
|
|
if ($this->offset > 0)
|
|
{
|
|
$this->close();
|
|
$this->open($this->file);
|
|
}
|
|
}
|
|
|
|
public function count(): int
|
|
{
|
|
if (null === $this->count)
|
|
{
|
|
$this->rewind();
|
|
|
|
$this->count = 0;
|
|
|
|
while ($this->getNextNode())
|
|
{
|
|
$this->count++;
|
|
}
|
|
|
|
$this->rewind();
|
|
}
|
|
|
|
return $this->count;
|
|
}
|
|
|
|
public function setOffset(int $offset): void
|
|
{
|
|
if ($this->offset != $offset)
|
|
{
|
|
if ($offset < $this->offset)
|
|
{
|
|
$this->rewind();
|
|
}
|
|
|
|
while ($this->offset < $offset && $this->getNextNode())
|
|
{
|
|
}
|
|
}
|
|
}
|
|
|
|
public function getOffset(): int
|
|
{
|
|
return $this->offset;
|
|
}
|
|
|
|
public function read(\Closure $callback): bool
|
|
{
|
|
return $this->getNextNode($callback);
|
|
}
|
|
|
|
public function close(): void
|
|
{
|
|
if ($this->xmlReader)
|
|
{
|
|
$this->xmlReader->close();
|
|
}
|
|
}
|
|
|
|
public function getNextNode(?\Closure $callback = null): bool
|
|
{
|
|
while($this->xmlReader->read())
|
|
{
|
|
if ($this->xmlReader->nodeType == XMLReader::ELEMENT && (null === $this->filterNodeDepth || $this->xmlReader->depth == $this->filterNodeDepth) && (null === $this->filterNode || $this->xmlReader->name == $this->filterNode))
|
|
{
|
|
$this->offset++;
|
|
|
|
if (null === $this->filterNodeDepth)
|
|
{
|
|
$this->filterNodeDepth = $this->xmlReader->depth;
|
|
}
|
|
|
|
if (null !== $callback)
|
|
{
|
|
$xml = $this->xmlReader->readOuterXml();
|
|
$dom = new DOMDocument('1.0', 'UTF-8');
|
|
$dom->preserveWhiteSpace = false;
|
|
$dom->loadXml($xml);
|
|
|
|
$data = $this->parseNodeToArray($dom->documentElement);
|
|
$callback($data);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
private function parseNodeToArray(\DOMNode $node, ?array &$output = null): array
|
|
{
|
|
$value = [
|
|
'@attributes' => [],
|
|
'@value' => null,
|
|
];
|
|
|
|
if (null === $output)
|
|
{
|
|
$output = array();
|
|
}
|
|
|
|
if ($node->hasAttributes())
|
|
{
|
|
$attributes = array();
|
|
/**
|
|
* @var \DOMNode $attribute
|
|
*/
|
|
foreach ($node->attributes as $attribute)
|
|
{
|
|
$attributes[$attribute->nodeName] = $this->convertValue($attribute->nodeValue);
|
|
}
|
|
|
|
$value['@attributes'] = $attributes;
|
|
}
|
|
|
|
if ($node->hasChildNodes())
|
|
{
|
|
if ($node->childNodes->length == 1 && in_array($node->childNodes->item(0)->nodeType, array(XML_CDATA_SECTION_NODE, XML_TEXT_NODE)))
|
|
{
|
|
$value['@value'] = trim($node->textContent);
|
|
}
|
|
else
|
|
{
|
|
/**
|
|
* @var \DOMNode
|
|
*/
|
|
foreach ($node->childNodes as $child)
|
|
{
|
|
$this->parseNodeToArray($child, $value);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!isset($output[$node->nodeName]))
|
|
{
|
|
$output[$node->nodeName] = $value;
|
|
}
|
|
else
|
|
{
|
|
if (is_string($output[$node->nodeName]))
|
|
{
|
|
$output[$node->nodeName] = array(0 => $output[$node->nodeName]);
|
|
}
|
|
elseif (!isset($output[$node->nodeName][0]))
|
|
{
|
|
$output[$node->nodeName] = array(0 => $output[$node->nodeName]);
|
|
}
|
|
|
|
$output[$node->nodeName][] = $value;
|
|
}
|
|
|
|
return $output;
|
|
}
|
|
|
|
/**
|
|
* Funkcja pomocnicza konwertująca wartość string na odpowiadające im wartości bool
|
|
*
|
|
* @param string $value
|
|
* @return string|bool
|
|
*/
|
|
private function convertValue(string $value)
|
|
{
|
|
$value = trim($value);
|
|
|
|
return isset(self::BOOL_VALUES[$value]) ? self::BOOL_VALUES[$value] : $value;
|
|
}
|
|
}
|