-
-
Notifications
You must be signed in to change notification settings - Fork 176
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support for complexType with sequnce of any #533
Comments
Hello @MudrakIvan, Not sure what to do with this at the moment:
This is perfectly valid XSD and XML wise, but it just does not correspond to PHP: <xs:element name="person">
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="person">
<xs:complexType>
<xs:sequence>
<xs:element name="firstname" type="xs:string"/>
<xs:element name="lastname" type="xs:string"/>
<xs:any minOccurs="0" maxOccurs="100" processContents="lax" />
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema> <person>
<firstname>Jos</firstname>
<lastname>Bos</lastname>
<hello />
<world />
</person> One could create a class Person with dynamic props for this, but there is not really a way to trustworthy fill up this object given the data is not known by the schema. So it feels a bit beyond the scope of this package : generating code based on the known parts of the schema. In this specific situation, I'dd create a complexTypeEncoder for the Parsing it could be as easy as using something like https://github.com/veewee/xml/blob/3.x/docs/encoding.md |
Hello @veewee, I completely understand your points however when the |
Don't get me wrong : I like the idea of having it in here. It's just a lot of work and hard to implement:
<person>
<firstname>Jos</firstname>
<lastname>Bos</lastname>
<!-- Start of any -->
<hello />
<world />
<firstname>Jos</firstname>
<lastname>Bos</lastname>
<firstname>Jos</firstname>
<lastname>Bos</lastname>
</person>
class Person {
private string $firstname;
private string $lastName;
use DynamicDataStorageTrait;
}
trait DynamicDataStorageTrait {
private array $__dynamic_any_storage__veryuniquehashtomakesureitdoesnotexistinwsdl;
// Some easier to use accessors:
public function storeDynamicData(array $data): self {/*...*/}
public function fetchDynamicData(): array {/*...*/}
} As you can tell, it won't be easy to do so. Now given your initial problem : It's pretty easy to parse this data by using a custom complexType encoder: use Soap\Encoding\Xml\Node\Element;
use function VeeWee\Xml\Encoding\xml_decode;
use function VeeWee\Xml\Encoding\document_encode;
$registry->addComplexTypeConverter(
'http://example.com/customerdetails',
'customerData',
new class implements XmlEncoder {
public function iso(Context $context): VeeWee\Reflecta\Iso\Iso
{
$typeName = $context->type->getName();
return new Iso(
to: static fn(array $data): string => document_encode([$typeName => $data])->stringifyDocumentElement(),
from: static fn(Element|string $xml) => xml_decode(
($xml instanceof Element ? $xml : Element::fromString($xml))->value()
)[$typeName],
);
}
}
); <x:GetCustomerDetailsResponse xmlns:x="http://example.com/customerdetails">
<customerName>John Doe</customerName>
<customerEmail>john@doe.com</customerEmail>
<customerData>
<foo />
<bar />
<hello>world</hello>
</customerData>
</x:GetCustomerDetailsResponse> Result in:
For your specific case, it's rather easy to get the data parsed manually than going through all the steps above. |
Thanks for you effort @veewee. I understand your points and I have to admit it's quite an unusual case. Before I close this issue, I wanted to ask, if you now some way to to decode xml with xsd definition to a php class. To be exact this entire problem is that I'm dealing with service that returns multiple different schemas (which are send as element with complexType |
No need to close this issue. Lets keep it open so that we can resolve the core of the issue some day eventually :) There are 2 approaches: 1. Manual You can add a XSD schema through the encoding component through a loader to validate the content of the XML. https://github.com/veewee/xml/blob/3.x/docs/encoding.md#typed Example: use function Psl\Type\int;
use function Psl\Type\shape;
use function Psl\Type\string;
use function Psl\Type\vector;
use function VeeWee\Xml\Dom\Configurator\validator;
use function VeeWee\Xml\Dom\Validator\xsd_validator;
use function VeeWee\Xml\Encoding\typed;
$data = typed(
<<<EOXML
<root>
<item>
<id>1</id>
<name>X</name>
<category>A</category>
<category>B</category>
<category>C</category>
</item>
</root>
EOXML,
shape([
'root' => shape([
'item' => shape([
'id' => int(),
'name' => string(),
'category' => vector(string()),
])
])
]),
validator(xsd_validator('some-schema.xsd'))
); Besides regular shapes, you can map it to classes directly by using the converted type: 2. Automatic mapping by using the encoding package Since the https://github.com/php-soap/encoding is already using the XSD(s) as the source of truth for encoding and decoding, you could do something like this: (❗ untested) use GoetasWebservices\XML\XSDReader\SchemaReader;
use Soap\Encoding\Encoder\Context;
use Soap\Encoding\EncoderRegistry;
use Soap\Engine\Metadata\Collection\MethodCollection;
use Soap\Engine\Metadata\InMemoryMetadata;
use Soap\WsdlReader\Metadata\Converter\SchemaToTypesConverter;
use Soap\WsdlReader\Metadata\Converter\Types\TypesConverterContext;
use Soap\WsdlReader\Parser\Definitions\NamespacesParser;
use VeeWee\Xml\Dom\Document;
$yourXsd = Document::fromXmlFile('your.xsd');
$namespaces = NamespacesParser::tryParse($yourXsd);
$metadata = new InMemoryMetadata(
$types = (new SchemaToTypesConverter())(
(new SchemaReader())->readNode($yourXsd->locateDocumentElement()),
TypesConverterContext::default($namespaces)
),
new MethodCollection()
);
$registry = EncoderRegistry::default()
->addClassMap('http://somenamespace', 'someObject', YourClass::class);
$context = new Context($types->fetchFirstByName('someObject')->getXsdType(), $metadata, $registry, $namespaces);
$encoder = $registry->detectEncoderForContext($context);
$data = $encoder->iso($context)->from($theRawXmlString); You could theoretically even use this similar approach to let this package generate the PHP type code for you. |
The automatic mapping with the new encoding package works like a charm. Even the PHP class generator works after only some minor modifications. Thanks again @veewee. |
FYI: Provided a PR for the first part of the process: Grabbing the information from the XSD: goetas-webservices/xsd-reader#86. Next up is using this information to enhance the metadata and find a way to generate code from it. |
Feature Request
Currently, if type have an complexType with sequence of any, empty class is generated. This leads data loss, as the content of this element is not converted. Unfortunately I was unable to make the conversion automatically via TypeConverters.
Summary
To replicate this behaviour, following wsdl can be used:
In this example, customerData will be generated as a class with no properties. Would it be possible to store those data like \DOMDocument or like a string, so the content is not lost?
The text was updated successfully, but these errors were encountered: