highsource/jsonix-schema-compiler

Generate oneOf for xsd:choice

pdesmarets opened this issue · 6 comments

I'm trying to convert an XSD with lots of tags xsd:choice into a JSON Schema, using your compiler (through Clemens' http://www.xml-buddy.com/ValidatorBuddy.htm)

The good thing is that I got a JSON schema out, which is great already! However, I was expecting to get oneOf keywords. Example:

<xsd:complexType name="PostalCodeMunicipalityComplexType">
    <xsd:choice>
        <xsd:element ref="msg:StructuredPostalCodeMunicipality"/>
        <xsd:element name="UnstructuredPostalCodeMunicipality"
            type="xsd:string">
        </xsd:element>
    </xsd:choice>
</xsd:complexType>

gets returned as:

            "type":"object",
            "title":"PostalCodeMunicipalityComplexType",
            "properties":{
                "structuredPostalCodeMunicipality":{
                    "title":"structuredPostalCodeMunicipality",
                    "allOf":[
                        {
                            "$ref":"#/definitions/StructuredPostalCodeMunicipalityComplexType"
                        }
                    ],
                    "propertyType":"element",
                    "elementName":{
                        "localPart":"StructuredPostalCodeMunicipality",
                        "namespaceURI":"http://schema...."
                    }
                },
                "unstructuredPostalCodeMunicipality":{
                    "title":"unstructuredPostalCodeMunicipality",
                    "allOf":[
                        {
                            "$ref":"http://www.jsonix.org/jsonschemas/w3c/2001/XMLSchema.jsonschema#/definitions/string"
                        }
                    ],
                    "propertyType":"element",
                    "elementName":{
                        "localPart":"UnstructuredPostalCodeMunicipality",
                        "namespaceURI":"http://schema..."
                    }
                }
            },
            "typeType":"classInfo",
            "typeName":{
                "localPart":"PostalCodeMunicipalityComplexType",
                "namespaceURI":"http://schema..."
            },
            "propertiesOrder":[
                "structuredPostalCodeMunicipality",
                "unstructuredPostalCodeMunicipality"
            ]
        }

What am I doing wrong, or misunderstanding?

No, you're not doing anything wrong. It's just a missing feature. The whole JSON Schema generation thing is still in early stage, there are a number of things missing. Like min/maxoccurs #40, default values #39 or enums #38.

However the problem with xsd:choice is that it will be quite hard to implement due to some limitations of the underlying technologies. Other things are much easier. This means that this feature will probably be missing for quite long if implemented at all. I don't want to discourage you, but it's better be honest than sorry.

Thanks for the prompt reply! I appreciate the warning. And in the meantime, I can add the oneOf's manually.

Maybe someone more technically-inclined than me will be tempted to contribute an enhancement...

I'd love to do this, but it's quite hard.

Jsonix Schema Compiler uses the XJC, "XML Schema to Java Compiler" under the hood. And that one is interested in producing classes with properties, there's no notion of "choice" there, you get a class with properties for complex types even if it is not xs:sequence but xs:choice - modelled.

So this would be quite hard to implement.

hi Alexey, I work with pdesmarets and he asked me to have a look at this.

I see the problem with xjc you were talking about: xjc only needs to generate a binding and some of the metadata in the schema is lost.
I suspect this won't be the only case of this but there is a jaxb global binding that could help here: choiceContentProperty.
xjc then seems to generate some more metadata to be able to recognize the choice element properly.

<?xml version="1.0" encoding="UTF-8"?>
<bindings xmlns="http://java.sun.com/xml/ns/jaxb"
          version="2.1">
    <globalBindings choiceContentProperty="true" />
</bindings>

Doing this now generates the following.
Still not exactly oneOf but a bit closer.

        "PostalCodeMunicipalityComplexType":{
            "type":"object",
            "title":"PostalCodeMunicipalityComplexType",
            "properties":{
                "structuredPostalCodeMunicipalityOrUnstructuredPostalCodeMunicipality":{
                    "title":"structuredPostalCodeMunicipalityOrUnstructuredPostalCodeMunicipality",
                    "allOf":[
                        {
                            "anyOf":[
                                {
                                    "anyOf":[
                                        {
                                            "$ref":"#/definitions/StructuredPostalCodeMunicipalityComplexType"
                                        }
                                    ],
                                    "elementName":{
                                        "localPart":"StructuredPostalCodeMunicipality",
                                        "namespaceURI":"http://schema.bpost.be/services/common/address/ExternalMailingAddressProofingCSMessages/v001"
                                    }
                                },
                                {
                                    "anyOf":[
                                        {
                                            "$ref":"http://www.jsonix.org/jsonschemas/w3c/2001/XMLSchema.jsonschema#/definitions/string"
                                        }
                                    ],
                                    "elementName":{
                                        "localPart":"UnstructuredPostalCodeMunicipality",
                                        "namespaceURI":"http://schema.bpost.be/services/common/address/ExternalMailingAddressProofingCSMessages/v001"
                                    }
                                }
                            ]
                        }
                    ],
                    "propertyType":"elements"
                }
            },
            "typeType":"classInfo",
            "typeName":{
                "localPart":"PostalCodeMunicipalityComplexType",
                "namespaceURI":"http://schema.bpost.be/services/common/address/ExternalMailingAddressProofingCSMessages/v001"
            },
            "propertiesOrder":[
                "structuredPostalCodeMunicipalityOrUnstructuredPostalCodeMunicipality"
            ]
        },

I made a little test case and followed the execution (but didn't understand it all). Could something could be done in JsonSchemaPropertyInfoProducerVisitor?
If it proves to be feasible, I suppose this binding could be added automatically (although given the way the xjc ModelLoader works it would be a bit hacky).

Maybe xerces could help as well. It is possible to get at the underlying schema model: (https://xerces.apache.org/xerces2-j/javadocs/xs/org/apache/xerces/xs/XSModel.html)
Not sure it would be easy to cross reference in the visitors, but maybe it could be a longer term solution.

cheers,
Mark

Hi Mark,

thanks for the pointers.
choiceContentProperty is really an option. By the way, XJC uses XSOM, not Xerces XSModel for XML Schema model, but it's similar. It is accessible from the XJC Model, but it's a bit hard to restore the "real" model and correspondence between properties and elements or particles of the XML Schema model. It's like gluing a broken cup together - you may have all the parts but it's still quite challenging. The problem would be to handle all the corner cases.

I think it would be good to start from some clear case - like xs:choice on top of complex type. This is what you have with structuredPostalCodeMunicipalityOrUnstructuredPostalCodeMunicipality.

So I believe this is solvable to some extent, but there will also be limits. I also think it's better to start with #40 and #50.

Best wishes,
Alexey

sp3rk commented

6 years ago...
...Is there a solution in the meantime?

I want to create a mapping of ptb.de/dcc and there are several xs:choice