1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace FluentDOM { |
4
|
|
|
|
5
|
|
|
use DOMNode; |
6
|
|
|
|
7
|
|
|
class XMLReader extends \XMLReader { |
8
|
|
|
|
9
|
|
|
/** |
10
|
|
|
* @var Namespaces |
11
|
|
|
*/ |
12
|
|
|
private $_namespaces; |
13
|
|
|
|
14
|
|
|
/** |
15
|
|
|
* Store last used document to avoid early GC |
16
|
|
|
* @var Document |
17
|
|
|
*/ |
18
|
|
|
private $_document; |
19
|
|
|
|
20
|
7 |
|
public function __construct() { |
21
|
7 |
|
$this->_namespaces = new Namespaces(); |
22
|
7 |
|
} |
23
|
|
|
|
24
|
|
|
/** |
25
|
|
|
* register a namespace prefix for the xml reader, it will be used in |
26
|
|
|
* next() and other methods with a tag name argument |
27
|
|
|
* |
28
|
|
|
* @param string $prefix |
29
|
|
|
* @param string $namespace |
30
|
|
|
* @throws \LogicException |
31
|
|
|
*/ |
32
|
4 |
|
public function registerNamespace($prefix, $namespace) { |
33
|
4 |
|
$this->_namespaces[$prefix] = $namespace; |
34
|
4 |
|
} |
35
|
|
|
|
36
|
|
|
/** |
37
|
|
|
* Positions cursor on the next node skipping all subtrees. If $name contains |
38
|
|
|
* a namespace prefix it will be resolved using the registered namespaces. |
39
|
|
|
* |
40
|
|
|
* @param null|string $name The name of the next node to move to. |
41
|
|
|
* @return bool |
42
|
|
|
*/ |
43
|
2 |
|
public function next($name = NULL) { |
44
|
2 |
|
if (isset($name)) { |
45
|
2 |
|
list($prefix, $localName) = QualifiedName::split($name); |
46
|
2 |
|
$namespaceUri = $this->_namespaces->resolveNamespace($prefix); |
|
|
|
|
47
|
2 |
|
$ignoreNamespace = ($prefix === FALSE && $namespaceUri === ''); |
48
|
2 |
|
} else { |
49
|
|
|
$ignoreNamespace = TRUE; |
50
|
|
|
$namespaceUri = ''; |
51
|
|
|
} |
52
|
2 |
|
if ($ignoreNamespace) { |
53
|
1 |
|
return parent::next($name); |
54
|
|
|
} else { |
55
|
1 |
|
while (parent::next($localName)) { |
|
|
|
|
56
|
1 |
|
if ($this->namespaceURI === $namespaceUri) { |
57
|
1 |
|
return TRUE; |
58
|
|
|
} |
59
|
1 |
|
} |
60
|
1 |
|
return FALSE; |
61
|
|
|
} |
62
|
|
|
} |
63
|
|
|
|
64
|
|
|
/** |
65
|
|
|
* Move to next node in document, including subtrees. If $name contains |
66
|
|
|
* a namespace prefix it will be resolved using the registered namespaces. |
67
|
|
|
* |
68
|
|
|
* @param null|string $name The name of the next node to move to. |
69
|
|
|
* @return bool |
70
|
|
|
*/ |
71
|
7 |
|
public function read($name = NULL) { |
72
|
7 |
|
if (isset($name)) { |
73
|
4 |
|
list($prefix, $localName) = QualifiedName::split($name); |
74
|
4 |
|
$namespaceUri = $this->_namespaces->resolveNamespace($prefix); |
|
|
|
|
75
|
4 |
|
$ignoreNamespace = ($prefix === FALSE && $namespaceUri === ''); |
76
|
4 |
|
while (parent::read()) { |
77
|
|
|
if ( |
78
|
4 |
|
$this->nodeType === XML_ELEMENT_NODE && |
79
|
4 |
|
$this->localName === $localName && |
80
|
|
|
( |
81
|
|
|
$ignoreNamespace || |
82
|
2 |
|
$this->namespaceURI === $namespaceUri |
83
|
2 |
|
) |
84
|
4 |
|
) { |
85
|
4 |
|
return TRUE; |
86
|
|
|
} |
87
|
4 |
|
} |
88
|
2 |
|
return FALSE; |
89
|
|
|
} else { |
90
|
3 |
|
return parent::read(); |
91
|
|
|
} |
92
|
|
|
} |
93
|
|
|
|
94
|
|
|
/** |
95
|
|
|
* Return attribute by name, resolve namespace prefix if included. |
96
|
|
|
* |
97
|
|
|
* @param string $name |
98
|
|
|
* @return NULL|string |
99
|
|
|
*/ |
100
|
5 |
|
public function getAttribute($name) { |
101
|
5 |
|
list($prefix, $localName) = QualifiedName::split($name); |
102
|
5 |
|
if (empty($prefix)) { |
103
|
4 |
|
return parent::getAttribute($name); |
104
|
|
|
} else { |
105
|
1 |
|
return parent::getAttributeNs($localName, $this->_namespaces->resolveNamespace($prefix)); |
|
|
|
|
106
|
|
|
} |
107
|
|
|
} |
108
|
|
|
|
109
|
2 |
|
public function expand(DOMNode $baseNode = NULL) { |
110
|
2 |
|
if (isset($baseNode)) { |
111
|
1 |
|
return parent::expand($baseNode); |
112
|
|
|
} else { |
113
|
1 |
|
$this->_document = $document = new Document(); |
114
|
1 |
|
$document->namespaces($this->_namespaces); |
115
|
1 |
|
return parent::expand($document); |
116
|
|
|
} |
117
|
|
|
} |
118
|
|
|
} |
119
|
|
|
} |
This check looks for type mismatches where the missing type is
false
. This is usually indicative of an error condtion.Consider the follow example
This function either returns a new
DateTime
object or false, if there was an error. This is a typical pattern in PHP programming to show that an error has occurred without raising an exception. The calling code should check for this returnedfalse
before passing on the value to another function or method that may not be able to handle afalse
.