-
-
Notifications
You must be signed in to change notification settings - Fork 2
Description
Support Question
I tried to follow the examples and set up custom anyType encoder that could inject 'non-string' XML.
$registry->addSimpleTypeConverter(
namespace: Xmlns::xsd()->value(),
name: 'anyType',
encoder: new AnyTypeEncoder(new MyObjectTypeEncoder()),
);AnyTypeEncoder is pretty much a proxy into MyObjectTypeEncoder:
/**
* @template T of GetMyObjectRequestType|GetMyObjectResponseType
* @implements XmlEncoder<T, string>
*/
final class MyObjectTypeEncoder implements XmlEncoder, XsiTypeCalculator
{
private SerializerInterface $serializer;
public function __construct()
{
$this->serializer = MyObjectSerializerFactory::createSerializer();
}
/**
* @return Iso<T, string>
*/
public function iso(Context $context): Iso
{
return new Iso(
fn(mixed $data): string => $this->to($context, $data),
fn(string $data): mixed => match ($context->type->getName()) {
GetMyObjectRequestType::class => $this->serializer->deserialize($data, GetMyObjectRequestType::class, 'xml'),
GetMyObjectResponseType::class => $this->serializer->deserialize($data, GetMyObjectResponseType::class, 'xml'),
default => throw RestrictionException::unsupportedValueType($context->type, $data),
},
);
}
/**
* @param T $data
* @return non-empty-string
*/
private function to(Context $context, mixed $data): string
{
$wrapped = $this->serializer->serialize(
data: $data,
format: 'xml',
);
return str_replace(['<result>', '</result>'], '', trim_xml_header($wrapped));
}
public function resolveXsiTypeForValue(Context $context, mixed $value): string
{
return match (true) {
$value instanceof GetMyObjectRequestType => 'getMyObjectRequestType',
$value instanceof GetMyObjectResponseType => 'getMyObjectResponseType',
default => ElementValueBuilder::resolveXsiTypeForValue($context, $value),
};
}
public function shouldIncludeXsiTargetNamespace(Context $context): bool
{
return true;
}
}My first problem is that the resulting output is escaped and looks like this:
<data xsi:type="getMyObjectRequestType" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<ns-001db19f:field1 xmlns:ns-001db19f="http://example.com/ns/my/object">value1</ns-001db19f:field1>
<ns-001db19f:field2 xmlns:ns-001db19f="http://example.com/ns/my/object">value2</ns-001db19f:field2>
<ns-001db19f:field3 xmlns:ns-001db19f="http://example.com/ns/my/object">value3</ns-001db19f:field3>
</data>
whereas I want it to be a proper XML:
<data xsi:type="getUserDataRequestType" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<ns-001db19f:field1 xmlns:ns-001db19f="http://example.com/ns/my/object">value1</ns-001db19f:field1>
<ns-001db19f:field2 xmlns:ns-001db19f="http://example.com/ns/my/object">value2</ns-001db19f:field2>
<ns-001db19f:field3 xmlns:ns-001db19f="http://example.com/ns/my/object">value3</ns-001db19f:field3>
</data>
My second problem is that I'm using a JMS Serializer for an XSD schema that only defines types, i.e the there are no elements, so my serializer have not types with xml_root_name. Because of that serialized output will wrap the XML with <result> root.
What would be my best course of action to fake a root object that could be recognized as anyType mixed element?
On ext-soap-engine, I used to hack the input by wrapping it like $data = new \SoapVar(trim_xml_header($xml), XSD_ANYXML);.
While writing this, I realized that the xsd type was supposed to be anyxml. But from what I've seen in the wild, anyType should also support non-escaped output when xsi:type is explicitly not a string.