Skip to content

Commit 397ba56

Browse files
committed
Refactorización para dejar API expuesta limpia. Se cambia cómo funciona XmlDocument (ahora es estándar UTF-8(. Este cambio rompe cosas, pero es un cambio menor. Ahora se debe usar XmlDocument::setEncoding() antes de XmlDocument::saveXml() (o getXml()) sino se indicó (o pudo indicar, como en encoder) el encoding mediante el constructor del XmlDocument.
1 parent 5e914e8 commit 397ba56

13 files changed

Lines changed: 258 additions & 177 deletions

src/Contract/XmlDecoderInterface.php

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,14 +25,9 @@ interface XmlDecoderInterface
2525
* @param XmlDocumentInterface|DOMElement $documentElement XML document that
2626
* we want to convert to a PHP array or the element where we will make the
2727
* conversion if it is not the complete XML document.
28-
* @param array|null $data The array where the results will be stored.
29-
* @param bool $twinsAsArray Indicates if we should treat twins nodes as an
30-
* array.
3128
* @return array The PHP array with the XML representation.
3229
*/
3330
public function decode(
34-
XmlDocumentInterface|DOMElement $documentElement,
35-
?array &$data = null,
36-
bool $twinsAsArray = false
31+
XmlDocumentInterface|DOMElement $documentElement
3732
): array;
3833
}

src/Contract/XmlDocumentInterface.php

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,14 @@
2222
*/
2323
interface XmlDocumentInterface extends DOMDocumentInterface, JsonSerializable
2424
{
25+
/**
26+
* Sets the encoding of the XML document.
27+
*
28+
* @param string $encoding The encoding of the XML document.
29+
* @return static
30+
*/
31+
public function setEncoding(string $encoding): static;
32+
2533
/**
2634
* Returns the name of the root tag of the XML.
2735
*
@@ -47,9 +55,6 @@ public function getSchema(): ?string;
4755
/**
4856
* Loads an XML string into the XML document instance.
4957
*
50-
* Must encode the XML to ISO-8859-1 if is UTF-8 and whas created the
51-
* instance with the encoding ISO-8859-1 (default behavior).
52-
*
5358
* @param string $source The string with the XML to load.
5459
* @param int $options The options for loading the XML.
5560
* @return bool `true` if the XML was loaded correctly.
@@ -144,9 +149,10 @@ public function getNodes(string $query, array $params = []): DOMNodeList;
144149
* Queries the XML array using a selector.
145150
*
146151
* @param string $selector The selector for the query to the XML array.
152+
* @param mixed $default The default value to return if the selector is not found.
147153
* @return mixed The result of the selector query to the array.
148154
*/
149-
public function get(string $selector): mixed;
155+
public function get(string $selector, mixed $default = null): mixed;
150156

151157
/**
152158
* Returns the data of the XML in an array structure.

src/Contract/XmlEncoderInterface.php

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,6 @@
1212

1313
namespace Derafu\Xml\Contract;
1414

15-
use DOMElement;
16-
1715
/**
1816
* Interface for the class that encodes a PHP array to XML.
1917
*/
@@ -25,17 +23,7 @@ interface XmlEncoderInterface
2523
*
2624
* @param array $data The array with the data that will be used to generate
2725
* XML.
28-
* @param array|null $namespace The namespace for the XML (URI and prefix).
29-
* @param DOMElement|null $parent The parent element for the nodes, or null
30-
* to be the root.
31-
* @param XmlDocumentInterface $doc The root XML document that will be
32-
* generated.
3326
* @return XmlDocumentInterface
3427
*/
35-
public function encode(
36-
array $data,
37-
?array $namespace = null,
38-
?DOMElement $parent = null,
39-
?XmlDocumentInterface $doc = null
40-
): XmlDocumentInterface;
28+
public function encode(array $data): XmlDocumentInterface;
4129
}

src/Service/XmlDecoder.php

Lines changed: 33 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -26,29 +26,42 @@ final class XmlDecoder implements XmlDecoderInterface
2626
/**
2727
* {@inheritDoc}
2828
*/
29-
public function decode(
30-
XmlDocumentInterface|DOMElement $documentElement,
31-
?array &$data = null,
32-
bool $twinsAsArray = false
33-
): array {
34-
// If no tagElement is passed, search one, if not one is obtained, stop
35-
// the generation.
29+
public function decode(XmlDocumentInterface|DOMElement $documentElement): array
30+
{
3631
$tagElement = $documentElement instanceof DOMElement
3732
? $documentElement
3833
: $documentElement->getDocumentElement()
3934
;
35+
4036
if ($tagElement === null) {
4137
return [];
4238
}
4339

44-
// Index in the array that represents the tag. Also it is a shorter
45-
// variable name :)
40+
$data = [$tagElement->tagName => null];
41+
42+
$this->decodeNode($tagElement, $data, false);
43+
44+
return $data;
45+
}
46+
47+
/**
48+
* Recursively decodes a DOM element into a PHP array.
49+
*
50+
* @param DOMElement $tagElement The element to decode.
51+
* @param array &$data The array being populated.
52+
* @param bool $twinsAsArray Whether to insert children at the current level
53+
* instead of nesting them under the element key (used internally when
54+
* processing items inside a list of twin nodes).
55+
* @return void
56+
*/
57+
private function decodeNode(
58+
DOMElement $tagElement,
59+
array|null &$data,
60+
bool $twinsAsArray,
61+
): void {
4662
$key = $tagElement->tagName;
4763

48-
// If there is no destination array for the data, create an array with
49-
// the index of the main node with an empty value.
5064
if ($data === null) {
51-
//$data = [$key => self::getEmptyValue()];
5265
$data = [$key => null];
5366
}
5467

@@ -63,16 +76,13 @@ public function decode(
6376

6477
// If the tagElement has child nodes, add them to the value of the tag.
6578
if ($tagElement->hasChildNodes()) {
66-
self::arrayAddChilds(
79+
$this->arrayAddChilds(
6780
$data,
6881
$tagElement,
6982
$tagElement->childNodes,
7083
$twinsAsArray
7184
);
7285
}
73-
74-
// Return the data of the XML document as an array.
75-
return $data;
7686
}
7787

7888
/**
@@ -103,19 +113,19 @@ private function arrayAddChilds(
103113
} elseif ($childs->length === 1 && empty($data[$key])) {
104114
$data[$key] = $textContent;
105115
} else {
106-
$array[$key]['@value'] = $textContent;
116+
$data[$key]['@value'] = $textContent;
107117
}
108118
}
109119
} elseif ($child instanceof DOMElement) {
110-
$n_twinsNodes = self::nodeCountTwins(
120+
$n_twinsNodes = $this->nodeCountTwins(
111121
$tagElement,
112122
$child->tagName
113123
);
114124
if ($n_twinsNodes === 1) {
115125
if ($twinsAsArray) {
116-
self::decode($child, $data);
126+
$this->decodeNode($child, $data, false);
117127
} else {
118-
self::decode($child, $data[$key]);
128+
$this->decodeNode($child, $data[$key], false);
119129
}
120130
} else {
121131
// Create a list for the child node, because it has several
@@ -130,13 +140,12 @@ private function arrayAddChilds(
130140
$textContent = trim($child->textContent);
131141
$data[$key][$child->tagName][] = $textContent;
132142
}
133-
// If the child node is scalar, not a list of nodes, it is
134-
// built as if it were a normal array with the call to
135-
// decode().
143+
// If the child node is not scalar, it is built as if it
144+
// were a normal array with the recursive call to decodeNode().
136145
else {
137146
$nextIndex = count($data[$key][$child->tagName]);
138147
$data[$key][$child->tagName][$nextIndex] = [];
139-
self::decode(
148+
$this->decodeNode(
140149
$child,
141150
$data[$key][$child->tagName][$nextIndex],
142151
true

src/Service/XmlEncoder.php

Lines changed: 26 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -43,26 +43,28 @@ final class XmlEncoder implements XmlEncoderInterface
4343
/**
4444
* {@inheritDoc}
4545
*/
46-
public function encode(
47-
array $data,
48-
?array $namespace = null,
49-
?DOMElement $parent = null,
50-
?XmlDocumentInterface $doc = null
51-
): XmlDocumentInterface {
52-
// If there is no complete XML document (from root, not a node), then
53-
// it is created, since it will be needed to create the future nodes.
54-
if ($doc === null) {
55-
$doc = new XmlDocument();
56-
}
46+
public function encode(array $data): XmlDocumentInterface
47+
{
48+
$doc = new XmlDocument();
5749

58-
// If there is no parent element, then it is being requested to create
59-
// the XML document from 0 (from the root node).
60-
if ($parent === null) {
61-
$parent = $doc;
62-
}
50+
$this->encodeNode($data, $doc, $doc);
6351

64-
// Iterate the first level of the array to find the tags that must be
65-
// added to the XML document.
52+
return $doc;
53+
}
54+
55+
/**
56+
* Recursively encodes an array into XML nodes and appends them to a parent.
57+
*
58+
* @param array $data The array with the data to encode.
59+
* @param XmlDocumentInterface $doc The root XML document.
60+
* @param DOMNode $parent The parent node to append nodes to.
61+
* @return void
62+
*/
63+
private function encodeNode(
64+
array $data,
65+
XmlDocumentInterface $doc,
66+
DOMNode $parent,
67+
): void {
6668
foreach ($data as $key => $value) {
6769

6870
// If the index is '@attributes' then the value of this index is an
@@ -97,33 +99,18 @@ public function encode(
9799
// Only the node is created if it has child nodes. The node will
98100
// not be created if an empty array (without children) is passed.
99101
if (!empty($value)) {
100-
$this->nodeAddChilds(
101-
$doc,
102-
$parent,
103-
$key,
104-
$value,
105-
$namespace
106-
);
102+
$this->nodeAddChilds($doc, $parent, $key, $value);
107103
}
108104
}
109105

110106
// The node is a scalar (not an array, not child nodes). So the
111107
// node is created and the value is assigned directly.
112108
else {
113109
if (!$this->skipValue($value)) {
114-
$this->nodeAddValue(
115-
$doc,
116-
$parent,
117-
$key,
118-
(string) $value,
119-
$namespace
120-
);
110+
$this->nodeAddValue($doc, $parent, $key, (string) $value);
121111
}
122112
}
123113
}
124-
125-
// Return the generated XML document.
126-
return $doc;
127114
}
128115

129116
/**
@@ -162,7 +149,6 @@ private function nodeAddAttributes(DOMElement $node, array $attributes): void
162149
* @param DOMNode $parent Node parent to which the child nodes will be added.
163150
* @param string $tagName Name of the child node tag.
164151
* @param array $childs Array of data of the child nodes.
165-
* @param array|null $namespace XML namespace (URI and prefix).
166152
* @return void
167153
* @throws XmlEncoderException If a child node is not an array.
168154
*/
@@ -171,7 +157,6 @@ private function nodeAddChilds(
171157
DOMNode $parent,
172158
string $tagName,
173159
array $childs,
174-
?array $namespace = null,
175160
): void {
176161
$keys = array_keys($childs);
177162
if (!is_int($keys[0])) {
@@ -196,30 +181,15 @@ private function nodeAddChilds(
196181
));
197182
}
198183

199-
// Add child nodes of the child node (add associative to the
200-
// node $tagName).
201-
$Node = $namespace
202-
? $doc->createElementNS(
203-
$namespace[0],
204-
$namespace[1] . ':' . $tagName
205-
)
206-
: $doc->createElement($tagName)
207-
;
184+
$Node = $doc->createElement($tagName);
208185
$parent->appendChild($Node);
209-
$this->encode($child, $namespace, $Node, $doc);
186+
$this->encodeNode($child, $doc, $Node);
210187
}
211188
// If the child is not an array, it is simply a duplicate node that
212189
// must be added at the same level as the parent node.
213190
else {
214191
$value = XmlHelper::sanitize((string) $child);
215-
$Node = $namespace
216-
? $doc->createElementNS(
217-
$namespace[0],
218-
$namespace[1] . ':' . $tagName,
219-
$value
220-
)
221-
: $doc->createElement($tagName, $value)
222-
;
192+
$Node = $doc->createElement($tagName, $value);
223193
$parent->appendChild($Node);
224194
}
225195
}
@@ -232,25 +202,16 @@ private function nodeAddChilds(
232202
* @param DOMNode $parent Node parent to which the node will be added.
233203
* @param string $tagName Name of the child node tag.
234204
* @param string $value Value of the child node.
235-
* @param array|null $namespace XML namespace (URI and prefix).
236205
* @return void
237206
*/
238207
private function nodeAddValue(
239208
XmlDocumentInterface $doc,
240209
DOMNode $parent,
241210
string $tagName,
242211
string $value,
243-
?array $namespace = null,
244212
): void {
245213
$value = XmlHelper::sanitize($value);
246-
$Node = $namespace
247-
? $doc->createElementNS(
248-
$namespace[0],
249-
$namespace[1] . ':' . $tagName,
250-
$value
251-
)
252-
: $doc->createElement($tagName, $value)
253-
;
214+
$Node = $doc->createElement($tagName, $value);
254215
$parent->appendChild($Node);
255216
}
256217

@@ -268,19 +229,4 @@ private function skipValue(mixed $value): bool
268229
true
269230
);
270231
}
271-
272-
/**
273-
* Checks if a value must generate an empty XML node.
274-
*
275-
* @param mixed $value Value to check.
276-
* @return bool `true` if the value must generate an empty node, `false` otherwise.
277-
*/
278-
// private function createWithEmptyValue(mixed $value): bool
279-
// {
280-
// return in_array(
281-
// $value,
282-
// $this->rules['node_values']['generate_empty'],
283-
// true
284-
// );
285-
// }
286232
}

0 commit comments

Comments
 (0)