Passed
Pull Request — master (#16)
by
unknown
01:31
created

XmlToArray::isHomogenous()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 10
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 1 Features 0
Metric Value
cc 3
eloc 5
c 1
b 1
f 0
nc 3
nop 1
dl 0
loc 10
rs 10
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Vyuldashev\XmlToArray;
6
7
use DOMAttr;
8
use DOMCdataSection;
9
use DOMDocument;
10
use DOMElement;
11
use DOMNamedNodeMap;
12
use DOMText;
13
14
class XmlToArray
15
{
16
    protected $document;
17
18
    public function __construct(string $xml)
19
    {
20
        $this->document = new DOMDocument();
21
        $this->document->loadXML($xml);
22
    }
23
24
    public static function convert(string $xml): array
25
    {
26
        $converter = new static($xml);
27
28
        return $converter->toArray();
29
    }
30
31
    protected function convertAttributes(DOMNamedNodeMap $nodeMap): ?array
32
    {
33
        if ($nodeMap->length === 0) {
34
            return null;
35
        }
36
37
        $result = [];
38
39
        /** @var DOMAttr $item */
40
        foreach ($nodeMap as $item) {
41
            $result[$item->name] = $item->value;
42
        }
43
44
        return ['_attributes' => $result];
45
    }
46
47
    protected function convertDomElement(DOMElement $element)
48
    {
49
        $sameNames = [];
50
        $result = $this->convertAttributes($element->attributes);
0 ignored issues
show
Bug introduced by
It seems like $element->attributes can also be of type null; however, parameter $nodeMap of Vyuldashev\XmlToArray\Xm...ay::convertAttributes() does only seem to accept DOMNamedNodeMap, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

50
        $result = $this->convertAttributes(/** @scrutinizer ignore-type */ $element->attributes);
Loading history...
51
52
        // Creates an index which counts each key, starting at zero, e.g. ['foo' => 2, 'bar' => 0]
53
        $childNodeNames = [];
0 ignored issues
show
Unused Code introduced by
The assignment to $childNodeNames is dead and can be removed.
Loading history...
54
        foreach ($element->childNodes as $key => $node) {
55
            if (array_key_exists($node->nodeName, $sameNames)) {
56
                $sameNames[$node->nodeName] += 1;
57
            } else {
58
                $sameNames[$node->nodeName] = 0;
59
            }
60
        }
61
62
        foreach ($element->childNodes as $key => $node) {
63
            if (is_null($result)) {
64
                $result = [];
65
            }
66
67
            if ($node instanceof DOMCdataSection) {
68
                $result['_cdata'] = $node->data;
69
70
                continue;
71
            }
72
            if ($node instanceof DOMText) {
73
                if (empty($result)) {
74
                    $result = $node->textContent;
75
                } else {
76
                    $result['_value'] = $node->textContent;
77
                }
78
                continue;
79
            }
80
            if ($node instanceof DOMElement) {
81
                if ($sameNames[$node->nodeName]) { // Truthy — When $sameNames['foo'] > 0
82
                    if (! array_key_exists($node->nodeName, $result)) { // Setup $result['foo']
83
                        $result[$node->nodeName] = [];
84
                    }
85
86
                    $result[$node->nodeName][$key] = $this->convertDomElement($node); // Store as $result['foo'][*]
87
                } else {
88
                    $result[$node->nodeName] = $this->convertDomElement($node); // Store as $result['foo']
89
                }
90
91
                continue;
92
            }
93
        }
94
95
        return $result;
96
    }
97
98
    public function toArray(): array
99
    {
100
        $result = [];
101
102
        if ($this->document->hasChildNodes()) {
103
            $children = $this->document->childNodes;
104
105
            foreach ($children as $child) {
106
                $result[$child->nodeName] = $this->convertDomElement($child);
107
            }
108
        }
109
110
        return $result;
111
    }
112
}
113