17
17
use Symfony \Component \Serializer \SerializerAwareTrait ;
18
18
19
19
/**
20
- * Encodes XML data.
21
- *
22
20
* @author Jordi Boggiano <j.boggiano@seld.be>
23
21
* @author John Wards <jwards@whiteoctober.co.uk>
24
22
* @author Fabian Vogler <fabian@equivalence.ch>
@@ -68,13 +66,6 @@ class XmlEncoder implements EncoderInterface, DecoderInterface, NormalizationAwa
68
66
self ::TYPE_CAST_ATTRIBUTES => true ,
69
67
];
70
68
71
- /**
72
- * @var \DOMDocument
73
- */
74
- private $ dom ;
75
- private $ format ;
76
- private $ context ;
77
-
78
69
/**
79
70
* @param array $defaultContext
80
71
*/
@@ -107,19 +98,17 @@ public function encode($data, $format, array $context = [])
107
98
108
99
$ xmlRootNodeName = $ context [self ::ROOT_NODE_NAME ] ?? $ this ->defaultContext [self ::ROOT_NODE_NAME ];
109
100
110
- $ this ->dom = $ this ->createDomDocument ($ context );
111
- $ this ->format = $ format ;
112
- $ this ->context = $ context ;
101
+ $ dom = $ this ->createDomDocument ($ context );
113
102
114
103
if (null !== $ data && !is_scalar ($ data )) {
115
- $ root = $ this -> dom ->createElement ($ xmlRootNodeName );
116
- $ this -> dom ->appendChild ($ root );
117
- $ this ->buildXml ($ root , $ data , $ xmlRootNodeName );
104
+ $ root = $ dom ->createElement ($ xmlRootNodeName );
105
+ $ dom ->appendChild ($ root );
106
+ $ this ->buildXml ($ root , $ data , $ format , $ context , $ xmlRootNodeName );
118
107
} else {
119
- $ this ->appendNode ($ this -> dom , $ data , $ xmlRootNodeName );
108
+ $ this ->appendNode ($ dom , $ data, $ format , $ context , $ xmlRootNodeName );
120
109
}
121
110
122
- return $ this -> dom ->saveXML ($ ignorePiNode ? $ this -> dom ->documentElement : null );
111
+ return $ dom ->saveXML ($ ignorePiNode ? $ dom ->documentElement : null );
123
112
}
124
113
125
114
/**
@@ -242,7 +231,7 @@ public function getRootNodeName()
242
231
final protected function appendXMLString (\DOMNode $ node , string $ val ): bool
243
232
{
244
233
if ('' !== $ val ) {
245
- $ frag = $ this -> dom ->createDocumentFragment ();
234
+ $ frag = $ node -> ownerDocument ->createDocumentFragment ();
246
235
$ frag ->appendXML ($ val );
247
236
$ node ->appendChild ($ frag );
248
237
@@ -254,15 +243,15 @@ final protected function appendXMLString(\DOMNode $node, string $val): bool
254
243
255
244
final protected function appendText (\DOMNode $ node , string $ val ): bool
256
245
{
257
- $ nodeText = $ this -> dom ->createTextNode ($ val );
246
+ $ nodeText = $ node -> ownerDocument ->createTextNode ($ val );
258
247
$ node ->appendChild ($ nodeText );
259
248
260
249
return true ;
261
250
}
262
251
263
252
final protected function appendCData (\DOMNode $ node , string $ val ): bool
264
253
{
265
- $ nodeText = $ this -> dom ->createCDATASection ($ val );
254
+ $ nodeText = $ node -> ownerDocument ->createCDATASection ($ val );
266
255
$ node ->appendChild ($ nodeText );
267
256
268
257
return true ;
@@ -284,7 +273,7 @@ final protected function appendDocumentFragment(\DOMNode $node, $fragment): bool
284
273
285
274
final protected function appendComment (\DOMNode $ node , string $ data ): bool
286
275
{
287
- $ node ->appendChild ($ this -> dom ->createComment ($ data ));
276
+ $ node ->appendChild ($ node -> ownerDocument ->createComment ($ data ));
288
277
289
278
return true ;
290
279
}
@@ -412,22 +401,22 @@ private function parseXmlValue(\DOMNode $node, array $context = [])
412
401
*
413
402
* @throws NotEncodableValueException
414
403
*/
415
- private function buildXml (\DOMNode $ parentNode , $ data , string $ xmlRootNodeName = null ): bool
404
+ private function buildXml (\DOMNode $ parentNode , $ data , string $ format , array $ context , string $ xmlRootNodeName = null ): bool
416
405
{
417
406
$ append = true ;
418
- $ removeEmptyTags = $ this -> context [self ::REMOVE_EMPTY_TAGS ] ?? $ this ->defaultContext [self ::REMOVE_EMPTY_TAGS ] ?? false ;
419
- $ encoderIgnoredNodeTypes = $ this -> context [self ::ENCODER_IGNORED_NODE_TYPES ] ?? $ this ->defaultContext [self ::ENCODER_IGNORED_NODE_TYPES ];
407
+ $ removeEmptyTags = $ context [self ::REMOVE_EMPTY_TAGS ] ?? $ this ->defaultContext [self ::REMOVE_EMPTY_TAGS ] ?? false ;
408
+ $ encoderIgnoredNodeTypes = $ context [self ::ENCODER_IGNORED_NODE_TYPES ] ?? $ this ->defaultContext [self ::ENCODER_IGNORED_NODE_TYPES ];
420
409
421
- if (\is_array ($ data ) || ($ data instanceof \Traversable && (null === $ this ->serializer || !$ this ->serializer ->supportsNormalization ($ data , $ this -> format )))) {
410
+ if (\is_array ($ data ) || ($ data instanceof \Traversable && (null === $ this ->serializer || !$ this ->serializer ->supportsNormalization ($ data , $ format )))) {
422
411
foreach ($ data as $ key => $ data ) {
423
412
//Ah this is the magic @ attribute types.
424
413
if (str_starts_with ($ key , '@ ' ) && $ this ->isElementNameValid ($ attributeName = substr ($ key , 1 ))) {
425
414
if (!is_scalar ($ data )) {
426
- $ data = $ this ->serializer ->normalize ($ data , $ this -> format , $ this -> context );
415
+ $ data = $ this ->serializer ->normalize ($ data , $ format , $ context );
427
416
}
428
417
$ parentNode ->setAttribute ($ attributeName , $ data );
429
418
} elseif ('# ' === $ key ) {
430
- $ append = $ this ->selectNodeType ($ parentNode , $ data );
419
+ $ append = $ this ->selectNodeType ($ parentNode , $ data, $ format , $ context );
431
420
} elseif ('#comment ' === $ key ) {
432
421
if (!\in_array (\XML_COMMENT_NODE , $ encoderIgnoredNodeTypes , true )) {
433
422
$ append = $ this ->appendComment ($ parentNode , $ data );
@@ -441,15 +430,15 @@ private function buildXml(\DOMNode $parentNode, $data, string $xmlRootNodeName =
441
430
* From ["item" => [0,1]];.
442
431
*/
443
432
foreach ($ data as $ subData ) {
444
- $ append = $ this ->appendNode ($ parentNode , $ subData , $ key );
433
+ $ append = $ this ->appendNode ($ parentNode , $ subData , $ format , $ context , $ key );
445
434
}
446
435
} else {
447
- $ append = $ this ->appendNode ($ parentNode , $ data , $ key );
436
+ $ append = $ this ->appendNode ($ parentNode , $ data , $ format , $ context , $ key );
448
437
}
449
438
} elseif (is_numeric ($ key ) || !$ this ->isElementNameValid ($ key )) {
450
- $ append = $ this ->appendNode ($ parentNode , $ data , 'item ' , $ key );
439
+ $ append = $ this ->appendNode ($ parentNode , $ data , $ format , $ context , 'item ' , $ key );
451
440
} elseif (null !== $ data || !$ removeEmptyTags ) {
452
- $ append = $ this ->appendNode ($ parentNode , $ data , $ key );
441
+ $ append = $ this ->appendNode ($ parentNode , $ data , $ format , $ context , $ key );
453
442
}
454
443
}
455
444
@@ -461,20 +450,20 @@ private function buildXml(\DOMNode $parentNode, $data, string $xmlRootNodeName =
461
450
throw new BadMethodCallException (sprintf ('The serializer needs to be set to allow "%s()" to be used with object data. ' , __METHOD__ ));
462
451
}
463
452
464
- $ data = $ this ->serializer ->normalize ($ data , $ this -> format , $ this -> context );
453
+ $ data = $ this ->serializer ->normalize ($ data , $ format , $ context );
465
454
if (null !== $ data && !is_scalar ($ data )) {
466
- return $ this ->buildXml ($ parentNode , $ data , $ xmlRootNodeName );
455
+ return $ this ->buildXml ($ parentNode , $ data , $ format , $ context , $ xmlRootNodeName );
467
456
}
468
457
469
458
// top level data object was normalized into a scalar
470
459
if (!$ parentNode ->parentNode ->parentNode ) {
471
460
$ root = $ parentNode ->parentNode ;
472
461
$ root ->removeChild ($ parentNode );
473
462
474
- return $ this ->appendNode ($ root , $ data , $ xmlRootNodeName );
463
+ return $ this ->appendNode ($ root , $ data , $ format , $ context , $ xmlRootNodeName );
475
464
}
476
465
477
- return $ this ->appendNode ($ parentNode , $ data , 'data ' );
466
+ return $ this ->appendNode ($ parentNode , $ data , $ format , $ context , 'data ' );
478
467
}
479
468
480
469
throw new NotEncodableValueException ('An unexpected value could not be serialized: ' .(!\is_resource ($ data ) ? var_export ($ data , true ) : sprintf ('%s resource ' , get_resource_type ($ data ))));
@@ -485,13 +474,14 @@ private function buildXml(\DOMNode $parentNode, $data, string $xmlRootNodeName =
485
474
*
486
475
* @param array|object $data
487
476
*/
488
- private function appendNode (\DOMNode $ parentNode , $ data , string $ nodeName , string $ key = null ): bool
477
+ private function appendNode (\DOMNode $ parentNode , $ data , string $ format , array $ context , string $ nodeName , string $ key = null ): bool
489
478
{
490
- $ node = $ this ->dom ->createElement ($ nodeName );
479
+ $ dom = $ parentNode instanceof \DomDocument ? $ parentNode : $ parentNode ->ownerDocument ;
480
+ $ node = $ dom ->createElement ($ nodeName );
491
481
if (null !== $ key ) {
492
482
$ node ->setAttribute ('key ' , $ key );
493
483
}
494
- $ appendNode = $ this ->selectNodeType ($ node , $ data );
484
+ $ appendNode = $ this ->selectNodeType ($ node , $ data, $ format , $ context );
495
485
// we may have decided not to append this node, either in error or if its $nodeName is not valid
496
486
if ($ appendNode ) {
497
487
$ parentNode ->appendChild ($ node );
@@ -505,32 +495,32 @@ private function appendNode(\DOMNode $parentNode, $data, string $nodeName, strin
505
495
*/
506
496
private function needsCdataWrapping (string $ val ): bool
507
497
{
508
- return 0 < preg_match ('/[<>&]/ ' , $ val );
498
+ return preg_match ('/[<>&]/ ' , $ val );
509
499
}
510
500
511
501
/**
512
502
* Tests the value being passed and decide what sort of element to create.
513
503
*
514
504
* @throws NotEncodableValueException
515
505
*/
516
- private function selectNodeType (\DOMNode $ node , $ val ): bool
506
+ private function selectNodeType (\DOMNode $ node , $ val, string $ format , array $ context ): bool
517
507
{
518
508
if (\is_array ($ val )) {
519
- return $ this ->buildXml ($ node , $ val );
509
+ return $ this ->buildXml ($ node , $ val, $ format , $ context );
520
510
} elseif ($ val instanceof \SimpleXMLElement) {
521
- $ child = $ this -> dom ->importNode (dom_import_simplexml ($ val ), true );
511
+ $ child = $ node -> ownerDocument ->importNode (dom_import_simplexml ($ val ), true );
522
512
$ node ->appendChild ($ child );
523
513
} elseif ($ val instanceof \Traversable) {
524
- $ this ->buildXml ($ node , $ val );
514
+ $ this ->buildXml ($ node , $ val, $ format , $ context );
525
515
} elseif ($ val instanceof \DOMNode) {
526
- $ child = $ this -> dom ->importNode ($ val , true );
516
+ $ child = $ node -> ownerDocument ->importNode ($ val , true );
527
517
$ node ->appendChild ($ child );
528
518
} elseif (\is_object ($ val )) {
529
519
if (null === $ this ->serializer ) {
530
520
throw new BadMethodCallException (sprintf ('The serializer needs to be set to allow "%s()" to be used with object data. ' , __METHOD__ ));
531
521
}
532
522
533
- return $ this ->selectNodeType ($ node , $ this ->serializer ->normalize ($ val , $ this -> format , $ this -> context ));
523
+ return $ this ->selectNodeType ($ node , $ this ->serializer ->normalize ($ val , $ format , $ context ), $ format , $ context );
534
524
} elseif (is_numeric ($ val )) {
535
525
return $ this ->appendText ($ node , (string ) $ val );
536
526
} elseif (\is_string ($ val ) && $ this ->needsCdataWrapping ($ val )) {
0 commit comments