diff --git a/src/Encoder/XsiTypeEncoder.php b/src/Encoder/XsiTypeEncoder.php
index e063e09..ae77281 100644
--- a/src/Encoder/XsiTypeEncoder.php
+++ b/src/Encoder/XsiTypeEncoder.php
@@ -78,7 +78,9 @@ private function to(IsoInterface $innerIso, mixed $value): string
*/
private function from(Context $context, IsoInterface $innerIso, ?Closure $detectEncoder, Element $value): mixed
{
- $iso = ($detectEncoder ? $detectEncoder($value->element()) : null)?->iso($context) ?? $innerIso;
+ // xsi:type is an attribute on the element itself, so an element without attributes cannot carry one.
+ $element = $value->element();
+ $iso = ($detectEncoder && $element->hasAttributes() ? $detectEncoder($element) : null)?->iso($context) ?? $innerIso;
/** @psalm-suppress ImplicitToStringCast - Encoders accept string|Element in from() */
return $iso->from($value);
diff --git a/tests/Unit/Encoder/XsiTypeEncoderTest.php b/tests/Unit/Encoder/XsiTypeEncoderTest.php
index 0483dc9..918dc15 100644
--- a/tests/Unit/Encoder/XsiTypeEncoderTest.php
+++ b/tests/Unit/Encoder/XsiTypeEncoderTest.php
@@ -6,7 +6,9 @@
use PHPUnit\Framework\Attributes\CoversClass;
use PHPUnit\Framework\TestCase;
use Soap\Encoding\Encoder\Context;
+use Soap\Encoding\Encoder\ElementEncoder;
use Soap\Encoding\Encoder\Feature\DisregardXsiInformation;
+use Soap\Encoding\Encoder\SimpleType\StringTypeEncoder;
use Soap\Encoding\Encoder\XmlEncoder;
use Soap\Encoding\Encoder\XsiTypeEncoder;
use Soap\Encoding\Test\Unit\ContextCreatorTrait;
@@ -64,6 +66,46 @@ public function test_it_ignores_xsi_type_for_encoders_that_disregard_it(): void
static::assertSame('inner', $iso->from($this->element('- 1
')));
}
+ public function test_it_decodes_through_the_detected_xsi_type(): void
+ {
+ $actual = $this->decode(
+ '32'
+ );
+
+ static::assertSame(32, $actual);
+ }
+
+ public function test_it_decodes_an_element_without_attributes_through_the_inner_encoder(): void
+ {
+ $actual = $this->decode('32');
+
+ static::assertSame('32', $actual);
+ }
+
+ public function test_it_decodes_an_element_with_attributes_but_no_xsi_type_through_the_inner_encoder(): void
+ {
+ $actual = $this->decode('32');
+
+ static::assertSame('32', $actual);
+ }
+
+ private function decode(string $xml): mixed
+ {
+ $encoder = new XsiTypeEncoder(new ElementEncoder(new StringTypeEncoder()));
+
+ return $encoder->iso($this->createStringContext())->from(Element::fromString($xml));
+ }
+
+ private function createStringContext(): Context
+ {
+ return self::createContext(
+ XsdType::guess('string')
+ ->withXmlNamespace('http://www.w3.org/2001/XMLSchema')
+ ->withXmlTargetNodeName('hello')
+ ->withMeta(static fn (TypeMeta $meta): TypeMeta => $meta->withIsQualified(true)->withIsSimple(true)->withIsElement(true))
+ );
+ }
+
private function element(string $xml): Element
{
return Element::fromString($xml);