Completed
Push — master ( 158f00...4ee9ec )
by San
06:17 queued 02:55
created

Dom   A

Complexity

Total Complexity 23

Size/Duplication

Total Lines 107
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 0

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 23
c 1
b 0
f 0
lcom 1
cbo 0
dl 0
loc 107
rs 10

11 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 9 1
A __toString() 0 5 1
A validate() 0 5 1
A validateXsd() 0 5 1
A validateNg() 0 10 2
A xpath() 0 10 2
A registerNamespace() 0 11 4
A fixNamespace() 0 12 4
A hasDefaultNamespace() 0 7 3
A getNamespaces() 0 5 1
A throwError() 0 10 3
1
<?php
2
3
namespace Behatch\Xml;
4
5
class Dom
6
{
7
    private $dom;
8
9
    public function __construct($content)
10
    {
11
        $this->dom = new \DomDocument();
12
        $this->dom->strictErrorChecking = false;
13
        $this->dom->validateOnParse = false;
14
        $this->dom->preserveWhiteSpace = true;
15
        $this->dom->loadXML($content, LIBXML_PARSEHUGE);
16
        $this->throwError();
17
    }
18
19
    public function __toString()
20
    {
21
        $this->dom->formatOutput = true;
22
        return $this->dom->saveXML();
23
    }
24
25
    public function validate()
26
    {
27
        $this->dom->validate();
28
        $this->throwError();
29
    }
30
31
    public function validateXsd($xsd)
32
    {
33
        $this->dom->schemaValidateSource($xsd);
34
        $this->throwError();
35
    }
36
37
    public function validateNg($ng)
38
    {
39
        try {
40
            $this->dom->relaxNGValidateSource($ng);
41
            $this->throwError();
42
        }
43
        catch(\DOMException $e) {
44
            throw new \RuntimeException($e->getMessage());
45
        }
46
    }
47
48
    public function xpath($element)
49
    {
50
        $xpath = new \DOMXpath($this->dom);
51
        $this->registerNamespace($xpath);
52
53
        $element = $this->fixNamespace($element);
54
        $elements = $xpath->query($element);
55
56
        return ($elements === false) ? new \DOMNodeList() : $elements;
57
    }
58
59
    private function registerNamespace(\DOMXpath $xpath)
60
    {
61
        $namespaces = $this->getNamespaces();
62
63
        foreach ($namespaces as $prefix => $namespace) {
64
            if (empty($prefix) && $this->hasDefaultNamespace()) {
65
                $prefix = 'rootns';
66
            }
67
            $xpath->registerNamespace($prefix, $namespace);
68
        }
69
    }
70
71
    /**
72
     * "fix" queries to the default namespace if any namespaces are defined
73
     */
74
    private function fixNamespace($element)
75
    {
76
        $namespaces = $this->getNamespaces();
77
78
        if (!empty($namespaces) && $this->hasDefaultNamespace()) {
79
            for ($i = 0; $i < 2; ++$i) {
80
                $element = preg_replace('/\/(\w+)(\[[^]]+\])?\//', '/rootns:$1$2/', $element);
81
            }
82
            $element = preg_replace('/\/(\w+)(\[[^]]+\])?$/', '/rootns:$1$2', $element);
83
        }
84
        return $element;
85
    }
86
87
    private function hasDefaultNamespace()
88
    {
89
        $defaultNamespaceUri = $this->dom->lookupNamespaceURI(null);
90
        $defaultNamespacePrefix = $defaultNamespaceUri ? $this->dom->lookupPrefix($defaultNamespaceUri) : null;
91
92
        return empty($defaultNamespacePrefix) && !empty($defaultNamespaceUri);
93
    }
94
95
    public function getNamespaces()
96
    {
97
        $xml = simplexml_import_dom($this->dom);
98
        return $xml->getNamespaces(true);
99
    }
100
101
    private function throwError()
102
    {
103
        $error = libxml_get_last_error();
104
        if (!empty($error)) {
105
            // https://bugs.php.net/bug.php?id=46465
106
            if ($error->message != 'Validation failed: no DTD found !') {
107
                throw new \DomException($error->message . ' at line ' . $error->line);
108
            }
109
        }
110
    }
111
}
112