Completed
Push — master ( c3a867...9157af )
by Michele
04:29
created

Tree::parseParentElement()   D

Complexity

Conditions 9
Paths 9

Size

Total Lines 27
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 90

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 27
ccs 0
cts 19
cp 0
rs 4.909
cc 9
eloc 20
nc 9
nop 3
crap 90
1
<?php
2
3
namespace CHMLib\TOCIndex;
4
5
use CHMLib\CHM;
6
use CHMLib\Map;
7
use DOMDocument;
8
use DOMElement;
9
use DOMXpath;
10
use Exception;
11
12
/**
13
 * A list of items in the TOC or in the Index of an CHM file.
14
 */
15
class Tree
16
{
17
    /**
18
     * List of Item instances children of this tree.
19
     *
20
     * @var Item[]
21
     */
22
    protected $items;
23
24
    /**
25
     * Initializes the instance.
26
     */
27
    public function __construct()
28
    {
29
        $this->items = array();
30
    }
31
32
    /**
33
     * Get the items contained in this tree.
34
     *
35
     * @return Item[]
36
     */
37
    public function getItems()
38
    {
39
        return $this->items;
40
    }
41
42
    /**
43
     * Append to the children of this tree the children of another tree.
44
     *
45
     * @param Tree $tree
46
     */
47
    public function mergeItems(Tree $tree)
48
    {
49
        $this->items = array_merge($this->items, $tree->items);
50
    }
51
52
    /**
53
     * Resolve the items contained in other CHM files.
54
     *
55
     * @param Map $map
56
     *
57
     * @throws Exception Throw an Exception in case of errors.
58
     */
59
    public function resolve(Map $map)
60
    {
61
        $result = array();
62
        foreach ($this->items as $item) {
63
            $merge = $item->getMerge();
64
            if ($merge === null) {
65
                $result[] = $item;
66
            } else {
67
                $result = array_merge($result, $item->resolve($map));
68
            }
69
        }
70
71
        $this->items = $result;
72
    }
73
74
    /**
75
     * Create a new instance starting from the whole TOC/Index source 'HTML'.
76
     *
77
     * @param CHM $chm The parent CHM instance.
78
     * @param string $data The contents of the .hhc/.hhk file.
79
     *
80
     * @throws Exception Throw an Exception in case of errors.
81
     *
82
     * @return static
83
     */
84
    public static function fromString(CHM $chm, $data)
85
    {
86
        if (!class_exists('DOMDocument', false) || !class_exists('DOMXpath', false)) {
87
            throw new Exception('Missing PHP extension: php-xml');
88
        }
89
        $result = new static();
90
        $data = trim((string) $data);
91
        if (stripos($data, '<object') !== false) {
92
            $doc = new DOMDocument();
93
            $charset = 'UTF-8';
94
            if (preg_match('%^<\?xml\s+encoding\s*=\s*"([^"]+)"%i', $data, $m)) {
95
                $charset = $m[1];
0 ignored issues
show
Unused Code introduced by
$charset is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
96
            } else {
97
                if (preg_match('%<meta\s+http-equiv\s*=\s*"Content-Type"\s+content\s*=\s*"text/html;\s*charset=([^"]+)">%i', $data, $m)) {
98
                    $charset = $m[1];
99
                }
100
                $data = '<?xml encoding="'.$charset.'">'.$data;
101
            }
102
            // LI elements are very often malformed/misplaced: let's remove them
103
            $data = preg_replace('$</?li((\\s+[^>]*)|\\s*)>$i', '', $data);
104
            if (@$doc->loadHTML($data) !== true) {
105
                throw new Exception('Failed to parse the .hhc/.hhk file contents');
106
            }
107
            $result->parseParentElement($chm, $doc->documentElement, 0);
108
        }
109
110
        return $result;
111
    }
112
113
    /**
114
     * Depth of the found child items.
115
     *
116
     * @var int
117
     */
118
    protected $depth;
119
120
    /**
121
     * Parse a DOMElement and read the items/sub trees.
122
     *
123
     * @param CHM $chm
124
     * @param DOMElement $parentElement
125
     * @param int $depth
126
     */
127
    protected function parseParentElement(CHM $chm, DOMElement $parentElement, $depth)
128
    {
129
        foreach ($parentElement->childNodes as $node) {
130
            if ($node->nodeType === XML_ELEMENT_NODE) {
131
                switch (strtolower($node->tagName)) {
132
                    case 'object':
133
                        if (strtolower($node->getAttribute('type')) === 'text/sitemap') {
134
                            $this->depth = $depth;
135
                            $this->items[] = new Item($chm, $node);
136
                        }
137
                        break;
138
                    case 'ul':
139
                    case 'ol':
140
                        $n = count($this->items);
141
                        if ($n > 0 && $depth >= $this->depth) {
142
                            $this->items[$n - 1]->getChildren()->parseParentElement($chm, $node, $depth + 1);
143
                        } else {
144
                            $this->parseParentElement($chm, $node, $depth + 1);
145
                        }
146
                        break;
147
                    default:
148
                        $this->parseParentElement($chm, $node, $depth + 1);
149
                        break;
150
                }
151
            }
152
        }
153
    }
154
}
155