1
|
|
|
<?php |
2
|
|
|
/** |
3
|
|
|
* Created by PhpStorm. |
4
|
|
|
* User: kaylv <[email protected]> |
5
|
|
|
* Date: 2019/9/4 |
6
|
|
|
* Time: 13:22 |
7
|
|
|
*/ |
8
|
|
|
|
9
|
|
|
namespace Kaylyu\Alipay\Kernel\Support; |
10
|
|
|
|
11
|
|
|
use DOMDocument; |
12
|
|
|
use DOMElement; |
13
|
|
|
use DOMNode; |
14
|
|
|
|
15
|
|
|
class XML |
16
|
|
|
{ |
17
|
|
|
const NAME_ATTRIBUTES = '@attributes'; |
18
|
|
|
|
19
|
|
|
const NAME_CONTENT = '@content'; |
20
|
|
|
|
21
|
|
|
const NAME_ROOT = '@root'; |
22
|
|
|
|
23
|
|
|
/** |
24
|
|
|
* XML to array. |
25
|
|
|
* |
26
|
|
|
* @param string $xml XML string |
27
|
|
|
* @param array $forceArrayKeys |
28
|
|
|
* |
29
|
|
|
* @return array|false |
30
|
|
|
*/ |
31
|
|
|
public static function parse($xml, $forceArrayKeys = []) |
32
|
|
|
{ |
33
|
|
|
$doc = new DOMDocument(); |
34
|
|
|
|
35
|
|
|
$load = @$doc->loadXML($xml); |
36
|
|
|
|
37
|
|
|
if ($load === false) { |
38
|
|
|
return false; |
39
|
|
|
} |
40
|
|
|
|
41
|
|
|
$root = $doc->documentElement; |
42
|
|
|
|
43
|
|
|
$output = self::DOMDocumentToArray($root, $forceArrayKeys); |
44
|
|
|
|
45
|
|
|
$output[self::NAME_ROOT] = $root->tagName; |
46
|
|
|
|
47
|
|
|
return $output; |
48
|
|
|
} |
49
|
|
|
|
50
|
|
|
/** |
51
|
|
|
* 请求 |
52
|
|
|
* @param array $data |
53
|
|
|
* |
54
|
|
|
* @return string |
55
|
|
|
*/ |
56
|
|
|
public static function buildRequest(array $data = []) |
57
|
|
|
{ |
58
|
|
|
return self::build($data, 'request'); |
59
|
|
|
} |
60
|
|
|
|
61
|
|
|
/** |
62
|
|
|
* 响应 |
63
|
|
|
* @param array $data |
64
|
|
|
* |
65
|
|
|
* @return string |
66
|
|
|
*/ |
67
|
|
|
public static function buildResponse(array $data = []) |
68
|
|
|
{ |
69
|
|
|
return self::build($data, 'response'); |
70
|
|
|
} |
71
|
|
|
|
72
|
|
|
/** |
73
|
|
|
* XML encode. |
74
|
|
|
* |
75
|
|
|
* @param array $data |
76
|
|
|
* @param string $method |
77
|
|
|
* |
78
|
|
|
* @return string |
79
|
|
|
*/ |
80
|
|
|
public static function build(array $data = [], string $method) |
81
|
|
|
{ |
82
|
|
|
// create a new XML document |
83
|
|
|
$document = new DomDocument('1.0', 'UTF-8'); |
84
|
|
|
|
85
|
|
|
// create body node |
86
|
|
|
$body = $document->createElement($method); |
87
|
|
|
$body = $document->appendChild($body); |
88
|
|
|
self::buildNode($data, $body, $document); |
89
|
|
|
|
90
|
|
|
return $document->saveXML($document, LIBXML_NOEMPTYTAG); |
91
|
|
|
} |
92
|
|
|
|
93
|
|
|
/** |
94
|
|
|
* @param DOMDocument $document |
95
|
|
|
* @param array $rootOptions |
96
|
|
|
* |
97
|
|
|
* @return DOMNode |
98
|
|
|
*/ |
99
|
|
|
protected static function buildRoot(DomDocument $document, array $rootOptions = []) |
100
|
|
|
{ |
101
|
|
|
$root = $document->createElementNS($rootOptions['namespace'], $rootOptions['name']); |
102
|
|
|
|
103
|
|
|
return $document->appendChild($root); |
104
|
|
|
} |
105
|
|
|
|
106
|
|
|
/** |
107
|
|
|
* @param array $data |
108
|
|
|
* @param DOMNode $node |
109
|
|
|
* @param DOMDocument $DOMDocument |
110
|
|
|
*/ |
111
|
|
|
protected static function buildNode(array $data, DOMNode &$node, DOMDocument $DOMDocument) |
112
|
|
|
{ |
113
|
|
|
foreach ($data as $key => $value) { |
114
|
|
|
if (is_array($value)) { |
115
|
|
|
if (is_numeric($key)) { |
116
|
|
|
if ($key === 0 && count($data) > 1) { |
117
|
|
|
$node->parentNode->appendChild($child = $DOMDocument->createElement($node->nodeName)); |
118
|
|
|
} else { |
119
|
|
|
$child = $node; |
120
|
|
|
} |
121
|
|
|
} else { |
122
|
|
|
$node->appendChild($child = $DOMDocument->createElement($key)); |
123
|
|
|
} |
124
|
|
|
self::buildNode($value, $child, $DOMDocument); |
125
|
|
|
} else { |
126
|
|
|
$node->appendChild($DOMDocument->createElement($key, $value)); |
127
|
|
|
} |
128
|
|
|
} |
129
|
|
|
} |
130
|
|
|
|
131
|
|
|
/** |
132
|
|
|
* Convert DOMDocument->documentElement to array |
133
|
|
|
* |
134
|
|
|
* @param DOMElement $documentElement |
135
|
|
|
* @param array $forceArrayKeys |
136
|
|
|
* |
137
|
|
|
* @return array |
138
|
|
|
*/ |
139
|
|
|
protected static function DOMDocumentToArray($documentElement, $forceArrayKeys = []) |
140
|
|
|
{ |
141
|
|
|
$return = []; |
142
|
|
|
|
143
|
|
|
switch ($documentElement->nodeType) { |
144
|
|
|
|
145
|
|
|
case XML_CDATA_SECTION_NODE: |
146
|
|
|
$return = trim($documentElement->textContent); |
147
|
|
|
break; |
148
|
|
|
case XML_TEXT_NODE: |
149
|
|
|
$return = trim($documentElement->textContent); |
150
|
|
|
break; |
151
|
|
|
case XML_ELEMENT_NODE: |
152
|
|
|
|
153
|
|
|
for ($count = 0, $childNodeLength = $documentElement->childNodes->length; $count < $childNodeLength; $count++) { |
154
|
|
|
$child = $documentElement->childNodes->item($count); |
155
|
|
|
$childValue = self::DOMDocumentToArray($child, $forceArrayKeys); |
156
|
|
|
if (isset($child->tagName)) { |
157
|
|
|
$tagName = $child->tagName; |
158
|
|
|
if (!isset($return[$tagName])) { |
159
|
|
|
$return[$tagName] = []; |
160
|
|
|
} |
161
|
|
|
$return[$tagName][] = $childValue; |
162
|
|
|
} elseif ($childValue || $childValue === '0' || $child->nodeName === '#cdata-section') { |
163
|
|
|
$return = (string)$childValue; |
164
|
|
|
} |
165
|
|
|
} |
166
|
|
|
|
167
|
|
|
if ($documentElement->attributes->length && !is_array($return)) { |
|
|
|
|
168
|
|
|
$return = [self::NAME_CONTENT => $return]; |
169
|
|
|
} |
170
|
|
|
|
171
|
|
|
if (is_array($return)) { |
172
|
|
|
if ($documentElement->attributes->length) { |
173
|
|
|
$attributes = []; |
174
|
|
|
foreach ($documentElement->attributes as $attrName => $attrNode) { |
175
|
|
|
$attributes[$attrName] = (string)$attrNode->value; |
176
|
|
|
} |
177
|
|
|
$return[self::NAME_ATTRIBUTES] = $attributes; |
178
|
|
|
} |
179
|
|
|
foreach ($return as $key => $value) { |
180
|
|
|
if (is_array($value) && count($value) == 1 && $key != self::NAME_ATTRIBUTES && !in_array($key, |
181
|
|
|
$forceArrayKeys)) { |
182
|
|
|
$return[$key] = $value[0]; |
183
|
|
|
} |
184
|
|
|
} |
185
|
|
|
} |
186
|
|
|
break; |
187
|
|
|
} |
188
|
|
|
|
189
|
|
|
return $return; |
190
|
|
|
} |
191
|
|
|
} |
An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.
If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.