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

Dom::getNamespaces()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 5
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 3
nc 1
nop 0
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