Passed
Push — master ( b74e1d...9ca869 )
by Sergio
03:46
created

XMLParser::extractElement()   C

Complexity

Conditions 7
Paths 5

Size

Total Lines 27
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 16
CRAP Score 7

Importance

Changes 0
Metric Value
cc 7
eloc 17
nc 5
nop 2
dl 0
loc 27
ccs 16
cts 16
cp 1
crap 7
rs 6.7272
c 0
b 0
f 0
1
<?php
2
/**
3
 * Created by PhpStorm.
4
 * User: sergio.rodenas
5
 * Date: 12/5/18
6
 * Time: 0:09
7
 */
8
9
namespace Rodenastyle\StreamParser\Parsers;
10
11
12
use Rodenastyle\StreamParser\Exceptions\IncompleteParseException;
13
use Rodenastyle\StreamParser\StreamParserInterface;
14
use XMLReader;
15
use Illuminate\Support\Collection;
16
17
18
class XMLParser implements StreamParserInterface
19
{
20
	protected $reader,$source;
21
22
	protected $skipFirstElement = true;
23
24 6
	public function from(String $source): StreamParserInterface
25
	{
26 6
		$this->source = $source;
27
28 6
		return $this;
29
	}
30
31
	public function withoutSkippingFirstElement(){
32
		$this->skipFirstElement = false;
33
34
		return $this;
35
	}
36
37 6
	public function each(callable $function)
38
	{
39 6
		$this->start();
40 6
		while($this->reader->read()){
41 6
			$this->searchElement($function);
42
		}
43 6
		$this->stop();
44 6
	}
45
46 6
	private function searchElement(callable $function)
47
	{
48 6
		if($this->isElement() && ! $this->shouldBeSkipped()){
49 6
			$function($this->extractElement($this->reader->name));
50
		}
51 6
	}
52
53 6
	private function extractElement(String $elementName, $couldBeAnElementsList = false)
54
	{
55 6
		$elementCollection = (new Collection())->merge($this->getCurrentElementAttributes());
56
57 6
		while($this->reader->read()){
58 6
			if($this->isEndElement($elementName)){
59 6
				break;
60
			}
61 6
			if($this->isValue()){
62 6
				if($elementCollection->isEmpty()){
63 6
					return trim($this->reader->value);
64
				} else {
65 6
					return $elementCollection->put($elementName, trim($this->reader->value));
66
				}
67
			}
68 6
			if($this->isElement()){
69 6
				if($couldBeAnElementsList){
70 6
					$foundElementName = $this->reader->name;
71 6
					$elementCollection->push(collect($this->extractElement($foundElementName)));
72
				} else {
73 6
					$foundElementName = $this->reader->name;
74 6
					$elementCollection->put($foundElementName, $this->extractElement($foundElementName, true));
75
				}
76
			}
77
		}
78
79 6
		return $elementCollection;
80
	}
81
82 6
	private function getCurrentElementAttributes(){
83 6
		$attributes = new Collection();
84 6
		if($this->reader->hasAttributes)  {
85 6
			while($this->reader->moveToNextAttribute()) {
86 6
				$attributes->put($this->reader->name, $this->reader->value);
87
			}
88
		}
89 6
		return $attributes;
90
	}
91
92 6
	private function start()
93
	{
94 6
		$this->reader = new XMLReader();
95 6
		$this->reader->open($this->source);
96
97 6
		return $this;
98
	}
99
100 6
	private function stop()
101
	{
102 6
		if( ! $this->reader->close()){
103
			throw new IncompleteParseException();
104
		}
105 6
	}
106
107 6
	private function shouldBeSkipped(){
108 6
		if($this->skipFirstElement){
109 6
			$this->skipFirstElement = false;
110 6
			return true;
111
		}
112
113 6
		return false;
114
	}
115
116 6
	private function isElement(String $elementName = null){
117 6
		if($elementName){
118
			return $this->reader->nodeType == XMLReader::ELEMENT && $this->reader->name === $elementName;
119
		} else {
120 6
			return $this->reader->nodeType == XMLReader::ELEMENT;
121
		}
122
	}
123
124 6
	private function isEndElement(String $elementName = null){
125 6
		if($elementName){
126 6
			return $this->reader->nodeType == XMLReader::END_ELEMENT && $this->reader->name === $elementName;
127
		} else {
128
			return $this->reader->nodeType == XMLReader::END_ELEMENT;
129
		}
130
	}
131
132 6
	private function isValue(){
133 6
		return $this->reader->nodeType == XMLReader::TEXT;
134
	}
135
}