diff --git a/src/Encoder/OptionalElementEncoder.php b/src/Encoder/OptionalElementEncoder.php
index edeaef9..3f08d82 100644
--- a/src/Encoder/OptionalElementEncoder.php
+++ b/src/Encoder/OptionalElementEncoder.php
@@ -4,10 +4,13 @@
namespace Soap\Encoding\Encoder;
use Soap\Encoding\Xml\Node\Element;
+use Soap\Encoding\Xml\Node\ElementList;
use Soap\Encoding\Xml\Writer\NilAttributeBuilder;
use Soap\Encoding\Xml\Writer\XsdTypeXmlElementWriter;
use VeeWee\Reflecta\Iso\Iso;
use VeeWee\Xml\Xmlns\Xmlns;
+use function count;
+use function is_string;
/**
* @template T of mixed
@@ -31,6 +34,7 @@ public function iso(Context $context): Iso
$type = $context->type;
$meta = $type->getMeta();
$elementIso = $this->elementEncoder->iso($context);
+ $isList = $meta->isList()->unwrapOr(false);
if (!$meta->isNullable()->unwrapOr(false)) {
return $elementIso;
@@ -48,17 +52,27 @@ public function iso(Context $context): Iso
/**
* @return T|null
*/
- static function (Element|string $xml) use ($elementIso) : mixed {
+ static function (ElementList|Element|string $xml) use ($elementIso, $isList) : mixed {
if ($xml === '') {
return null;
}
- $documentElement = ($xml instanceof Element ? $xml : Element::fromString($xml))->element();
- if ($documentElement->getAttributeNS(Xmlns::xsi()->value(), 'nil') === 'true') {
+ $parsedXml = match(true) {
+ $isList && is_string($xml) => ElementList::fromString(''.$xml.'
'),
+ is_string($xml) => Element::fromString($xml),
+ default => $xml,
+ };
+
+ $documentElement = match (true) {
+ $parsedXml instanceof ElementList && count($parsedXml) === 1 => $parsedXml->elements()[0]->element(),
+ $parsedXml instanceof Element => $parsedXml->element(),
+ default => null
+ };
+ if ($documentElement && $documentElement->getAttributeNS(Xmlns::xsi()->value(), 'nil') === 'true') {
return null;
}
- /** @var Iso $elementIso */
+ /** @var Iso $elementIso */
return $elementIso->from($xml);
}
);
diff --git a/src/Xml/Node/ElementList.php b/src/Xml/Node/ElementList.php
index 806afba..0740e28 100644
--- a/src/Xml/Node/ElementList.php
+++ b/src/Xml/Node/ElementList.php
@@ -4,10 +4,12 @@
namespace Soap\Encoding\Xml\Node;
use Closure;
+use Countable;
use DOMElement;
use Soap\Encoding\Xml\Reader\DocumentToLookupArrayReader;
use Stringable;
use VeeWee\Xml\Dom\Document;
+use function count;
use function Psl\Iter\reduce;
use function Psl\Vec\map;
use function VeeWee\Xml\Dom\Locator\Element\children as readChildren;
@@ -15,7 +17,7 @@
/**
* @psalm-import-type LookupArray from DocumentToLookupArrayReader
*/
-final class ElementList implements Stringable
+final class ElementList implements Countable, Stringable
{
/** @var list */
private array $elements;
@@ -111,4 +113,9 @@ public function __toString()
{
return $this->value();
}
+
+ public function count(): int
+ {
+ return count($this->elements);
+ }
}
diff --git a/tests/PhpCompatibility/Implied/ImpliedSchema009Test.php b/tests/PhpCompatibility/Implied/ImpliedSchema009Test.php
new file mode 100644
index 0000000..85a5c33
--- /dev/null
+++ b/tests/PhpCompatibility/Implied/ImpliedSchema009Test.php
@@ -0,0 +1,66 @@
+
+
+
+
+
+
+
+
+
+
+
+ EOXML;
+ protected string $type = 'type="tns:testType"';
+
+ protected function calculateParam(): mixed
+ {
+ return (object)[
+ 'Company' => [
+ (object)['ID' => 0],
+ (object)['ID' => 1],
+ ],
+ ];
+ }
+
+ protected function expectXml(): string
+ {
+ return <<
+
+
+
+
+ 0
+
+
+ 1
+
+
+
+
+
+ XML;
+ }
+}
diff --git a/tests/PhpCompatibility/Implied/ImpliedSchema010Test.php b/tests/PhpCompatibility/Implied/ImpliedSchema010Test.php
new file mode 100644
index 0000000..87b5e9c
--- /dev/null
+++ b/tests/PhpCompatibility/Implied/ImpliedSchema010Test.php
@@ -0,0 +1,57 @@
+
+
+
+
+
+
+
+
+
+
+
+ EOXML;
+ protected string $type = 'type="tns:testType"';
+
+ protected function calculateParam(): mixed
+ {
+ return (object) [
+ 'Company' => null,
+ ];
+ }
+
+ protected function expectXml(): string
+ {
+ return <<
+
+
+
+
+
+
+
+
+ XML;
+ }
+}
diff --git a/tests/PhpCompatibility/Implied/ImpliedSchema011Test.php b/tests/PhpCompatibility/Implied/ImpliedSchema011Test.php
new file mode 100644
index 0000000..0d13376
--- /dev/null
+++ b/tests/PhpCompatibility/Implied/ImpliedSchema011Test.php
@@ -0,0 +1,55 @@
+
+
+
+
+
+
+
+
+
+
+
+ EOXML;
+ protected string $type = 'type="tns:testType"';
+
+ protected function calculateParam(): mixed
+ {
+ return (object) [
+ 'Company' => [],
+ ];
+ }
+
+ protected function expectXml(): string
+ {
+ return <<
+
+
+
+
+
+
+ XML;
+ }
+}
diff --git a/tests/PhpCompatibility/Implied/ImpliedSchema012Test.php b/tests/PhpCompatibility/Implied/ImpliedSchema012Test.php
new file mode 100644
index 0000000..1813457
--- /dev/null
+++ b/tests/PhpCompatibility/Implied/ImpliedSchema012Test.php
@@ -0,0 +1,62 @@
+
+
+
+
+
+
+
+
+
+
+
+ EOXML;
+ protected string $type = 'type="tns:testType"';
+
+ protected function calculateParam(): mixed
+ {
+ return (object) [
+ 'Company' => [
+ (object)['ID' => 0],
+ ],
+ ];
+ }
+
+ protected function expectXml(): string
+ {
+ return <<
+
+
+
+
+ 0
+
+
+
+
+
+ XML;
+ }
+}
diff --git a/tests/Unit/Xml/Node/ElementListTest.php b/tests/Unit/Xml/Node/ElementListTest.php
index 277984b..ca3a914 100644
--- a/tests/Unit/Xml/Node/ElementListTest.php
+++ b/tests/Unit/Xml/Node/ElementListTest.php
@@ -55,4 +55,12 @@ public function test_it_can_load_nested_list(): void
static::assertSame([$hello, $list1, $list2], $list->elements());
}
+
+ public function test_it_can_be_countded(): void
+ {
+ $list = new ElementList(Element::fromString('world'));
+
+ static::assertCount(1, $list->elements());
+ static::assertCount(1, $list);
+ }
}