OPMLParser   A
last analyzed

Complexity

Total Complexity 17

Size/Duplication

Total Lines 113
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 2

Importance

Changes 3
Bugs 0 Features 0
Metric Value
wmc 17
c 3
b 0
f 0
lcom 1
cbo 2
dl 0
loc 113
rs 10

4 Methods

Rating   Name   Duplication   Size   Complexity  
C __construct() 0 41 8
B parseOutline() 0 18 6
A getResult() 0 4 1
A validate() 0 9 2
1
<?php
2
namespace vipnytt;
3
4
use DOMDocument;
5
use SimpleXMLElement;
6
use vipnytt\OPMLParser\Exceptions;
7
use vipnytt\OPMLParser\OPMLInterface;
8
9
class OPMLParser implements OPMLInterface
10
{
11
    /**
12
     * XML content
13
     * @var string
14
     */
15
    protected $xml;
16
17
    /**
18
     * Array containing the parsed XML
19
     * @var array
20
     */
21
    protected $result = [];
22
23
    /**
24
     * Constructor
25
     *
26
     * @param string $xml is the string we want to parse
27
     * @throws Exceptions\ParseException
28
     */
29
    public function __construct($xml)
30
    {
31
        $this->xml = $xml;
32
        libxml_use_internal_errors();
33
        $dom = new DOMDocument();
34
        $dom->recover = true;
35
        $dom->strictErrorChecking = false;
36
        $dom->loadXML($this->xml, LIBXML_NOCDATA);
37
        $dom->encoding = self::ENCODING;
38
39
        $opml = simplexml_import_dom($dom);
40
41
        if ($opml === false) {
42
            throw new Exceptions\ParseException('Provided XML document is not valid');
43
        }
44
45
        $this->result = [
46
            'version' => (string)$opml['version'],
47
            'head' => [],
48
            'body' => []
49
        ];
50
51
        if (!isset($opml->head)) {
52
            throw new Exceptions\ParseException('Provided XML is not an valid OPML document');
53
        }
54
        // First, we get all "head" elements. Head is required but its sub-elements are optional.
55
        foreach ($opml->head->children() as $key => $value) {
56
            if (in_array($key, self::OPTIONAL_HEAD_ELEMENTS, true)) {
57
                $this->result['head'][$key] = (string)$value;
58
            }
59
        }
60
        if (!isset($opml->body)) {
61
            return;
62
        }
63
        // Then, we get body outlines. Body must contain at least one outline element.
64
        foreach ($opml->body->children() as $key => $value) {
65
            if ($key === 'outline') {
66
                $this->result['body'][] = $this->parseOutline($value);
67
            }
68
        }
69
    }
70
71
    /**
72
     * Parse an XML object as an outline object and return corresponding array
73
     *
74
     * @param SimpleXMLElement $outlineXML the XML object we want to parse
75
     * @return array corresponding to an outline and following format described above
76
     */
77
    protected function parseOutline(SimpleXMLElement $outlineXML)
78
    {
79
        $outline = [];
80
        foreach ($outlineXML->attributes() as $key => $value) {
81
            $outline[$key] = (string)$value;
82
        }
83
        // Bug fix for OPMLs witch contains `title` but not the required `text`
84
        if (empty($outline['text']) && isset($outline['title'])) {
85
            $outline['text'] = $outline['title'];
86
        }
87
        foreach ($outlineXML->children() as $key => $value) {
88
            // An outline may contain any number of outline children
89
            if ($key === 'outline') {
90
                $outline['@outlines'][] = $this->parseOutline($value);
91
            }
92
        }
93
        return $outline;
94
    }
95
96
    /**
97
     * Return the parsed XML as an Array
98
     *
99
     * @return array
100
     */
101
    public function getResult()
102
    {
103
        return $this->result;
104
    }
105
106
    /**
107
     * Validate the parsed XML array
108
     * Note: The parser support parsing of OPMLs with missing content
109
     *
110
     * @return \SimpleXMLElement|false Validated object on success, false on failure
111
     */
112
    public function validate()
113
    {
114
        try {
115
            $render = new OPMLParser\Render($this->result);
116
        } catch (Exceptions\RenderException $e) {
117
            return false;
118
        }
119
        return $render->asXMLObject();
120
    }
121
}
122