Completed
Push — master ( c52910...66a65c )
by lyu
02:53 queued 47s
created

XML::buildRequest()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 1
dl 0
loc 4
ccs 0
cts 4
cp 0
crap 2
rs 10
c 0
b 0
f 0
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)) {
0 ignored issues
show
Bug introduced by
The property length does not seem to exist in DOMNamedNodeMap.

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.

Loading history...
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
}