Skip to content
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

Omitted elements when unmarshalling types with same name in different namespaces #83

Closed
hokkos opened this issue May 7, 2015 · 6 comments
Assignees
Labels
Milestone

Comments

@hokkos
Copy link

hokkos commented May 7, 2015

Hi,
I use Jsonix with a big collection of schemas. I create a mapping module for each xsd where an xml will be instantiated from. Those xsd import "common" xsd files, and sometime they use a type with the same name in different common xsd (so in different namespaces) and in those case the unmarshalled json will have omitted elements in the elements of the name that are common.

For example a schema A imports schemas B and C (of namespaces b and c) and both contains a type of name "CommonType", schema A uses both b:CommonType and c:CommonType. b:CommonType have the elements "Common" and "B" and c:CommonType have the elements "Common" and "C" . So it seems the unmarshalled json will contain the Common node in b:CommonType and c:CommonType, elements but not their exclusive elements "B" and "C".

So if type have the same name in different namespace, it seems jsonix can't disambiguate them.

I am trying to create a simple reproducible example I can share; but maybe I just did something wrong with the mapping or config.

Thanks.

@highsource
Copy link
Owner

May be related to #50.

Normally the mapping should refer to B.CommonType or C.CommonType, so it should not be ambiguous. But mayber something's wrong. Please try to create a reproducible test case, this would be helpful.

@highsource highsource added the bug label May 7, 2015
@highsource highsource added this to the 2.3.0 milestone May 7, 2015
@highsource highsource self-assigned this May 7, 2015
@hokkos
Copy link
Author

hokkos commented May 11, 2015

Hi, here is an example, ground.xsd imports house.xsd and garden.xsd schemas, where in each there is a LocaType type in their own namespace. Then there is the ground.xml instance of ground.xsd, ground.json the unmarshalled json and groudroundtrip.xml as the output of unmarshalling and marshalling. ground.js is the mapping of ground.xsd.

ground.xsd :

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified"
    xmlns:ns1="hieu_a" xmlns:h1="urban" xmlns:h2="rural">

    <xs:import namespace="urban" schemaLocation="./house.xsd"/>
    <xs:import namespace="rural" schemaLocation="./garden.xsd"/>

    <xs:element name="Root">
        <xs:complexType>
            <xs:sequence>
                <xs:element name="House">
                    <xs:complexType>
                        <xs:sequence>
                            <xs:element name="id" type="xs:int"/>
                            <xs:element name="localisation" type="h1:LocaType"/>
                        </xs:sequence>
                    </xs:complexType>
                </xs:element>
                <xs:element name="Garden">
                    <xs:complexType>
                        <xs:sequence>
                            <xs:element name="id" type="xs:int"/>
                            <xs:element name="localisation" type="h2:LocaType"/>
                        </xs:sequence>
                    </xs:complexType>
                </xs:element>
            </xs:sequence>
        </xs:complexType>
    </xs:element>
</xs:schema>

house.xsd :

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified"
    targetNamespace="urban" xmlns:ns1="urban">

    <xs:element name="localisation" type="ns1:LocaType"> </xs:element>
    <xs:complexType name="LocaType">
        <xs:sequence>
            <xs:element name="name" type="xs:string"/>
            <xs:element name="oldName" type="xs:string"/>
            <xs:element name="streetName" type="xs:string"/>
        </xs:sequence>
    </xs:complexType>
</xs:schema>

garden.xsd :

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified"
    targetNamespace="rural" xmlns:ns2="rural">

    <xs:element name="localisation" type="ns2:LocaType"> </xs:element>
    <xs:complexType name="LocaType">
        <xs:sequence>
            <xs:element name="name" type="xs:string"/>
            <xs:element name="swingCount" type="xs:int"/>
            <xs:element name="kennelCount" type="xs:int"/>
        </xs:sequence>
    </xs:complexType>
</xs:schema>

ground.xml :

<?xml version="1.0" encoding="utf-8"?>
<Root
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="./ground.xsd">
    <House>
        <id>
            1
        </id>
        <localisation>
            <name>
                Kleber
            </name>
            <oldName>
                Kleb
            </oldName>
            <street>
                MainStreet
            </street>
        </localisation>
    </House>
    <Garden>
        <id>
            2
        </id>
        <localisation>
            <name>
                Versailles
            </name>
            <swingCount>
                3
            </swingCount>
            <kennelCount>
                5
            </kennelCount>
        </localisation>
    </Garden>
</Root>

ground.json

{
  "name": {
    "namespaceURI": "",
    "localPart": "Root",
    "prefix": "",
    "key": "Root",
    "string": "Root"
  },
  "value": {
    "TYPE_NAME": "ground.Root",
    "house": {
      "TYPE_NAME": "ground.Root.House",
      "id": 1,
      "localisation": {
        "TYPE_NAME": "ground.LocaType"
      }
    },
    "garden": {
      "TYPE_NAME": "ground.Root.Garden",
      "id": 2,
      "localisation": {
        "TYPE_NAME": "ground.LocaType"
      }
    }
  }
}

groudroundtrip.xml :

<Root>
    <House>
        <id>1</id>
        <localisation/>
    </House>
    <Garden>
        <id>2</id>
        <localisation/>
    </Garden>
</Root>

ground.js:

var ground_Module_Factory = function () {
  var ground = {
    name: 'ground',
    typeInfos: [{
        localName: 'Root.House',
        propertyInfos: [{
            name: 'id',
            elementName: {
              localPart: 'id'
            },
            typeInfo: 'Int'
          }, {
            name: 'localisation',
            elementName: {
              localPart: 'localisation'
            },
            typeInfo: '.LocaType'
          }]
      }, {
        localName: 'LocaType',
        propertyInfos: [{
            name: 'name',
            elementName: {
              localPart: 'name',
              namespaceURI: 'urban'
            }
          }, {
            name: 'oldName',
            elementName: {
              localPart: 'oldName',
              namespaceURI: 'urban'
            }
          }, {
            name: 'streetName',
            elementName: {
              localPart: 'streetName',
              namespaceURI: 'urban'
            }
          }]
      }, {
        localName: 'Root',
        propertyInfos: [{
            name: 'house',
            elementName: {
              localPart: 'House'
            },
            typeInfo: '.Root.House'
          }, {
            name: 'garden',
            elementName: {
              localPart: 'Garden'
            },
            typeInfo: '.Root.Garden'
          }]
      }, {
        localName: 'LocaType',
        propertyInfos: [{
            name: 'name',
            elementName: {
              localPart: 'name',
              namespaceURI: 'rural'
            }
          }, {
            name: 'swingCount',
            elementName: {
              localPart: 'swingCount',
              namespaceURI: 'rural'
            },
            typeInfo: 'Int'
          }, {
            name: 'kennelCount',
            elementName: {
              localPart: 'kennelCount',
              namespaceURI: 'rural'
            },
            typeInfo: 'Int'
          }]
      }, {
        localName: 'Root.Garden',
        propertyInfos: [{
            name: 'id',
            elementName: {
              localPart: 'id'
            },
            typeInfo: 'Int'
          }, {
            name: 'localisation',
            elementName: {
              localPart: 'localisation'
            },
            typeInfo: '.LocaType'
          }]
      }],
    elementInfos: [{
        elementName: {
          localPart: 'localisation',
          namespaceURI: 'urban'
        },
        typeInfo: '.LocaType'
      }, {
        elementName: {
          localPart: 'Root'
        },
        typeInfo: '.Root'
      }, {
        elementName: {
          localPart: 'localisation',
          namespaceURI: 'rural'
        },
        typeInfo: '.LocaType'
      }]
  };
  return {
    ground: ground
  };
};
if (typeof define === 'function' && define.amd) {
  define([], ground_Module_Factory);
}
else {
  var ground_Module = ground_Module_Factory();
  if (typeof module !== 'undefined' && module.exports) {
    module.exports.ground = ground_Module.ground;
  }
  else {
    var ground = ground_Module.ground;
  }
}

highsource added a commit that referenced this issue Jun 13, 2015
@highsource
Copy link
Owner

Thank you for the very detailed report. I've reproduced it.

The problem is that your mapping has LocaType generated two times, but with the same name. How did you generate the ground.js mapping, exactly? You've actually got 3 namespaces so normally you should get 3 mappings. You're getting just one.

So from the two LocaTypes you're getting, just one is effective. I think it is the last one.

When your original XML is parsed, you don't get contents in House and Ground for two different reasons:

  • In House - wrong LocaType is applied (this is the core issue).
  • In Ground - your elements should be in the rural namespace, but they are in the default namespace. This is a mistake in your XML.

@highsource
Copy link
Owner

You must have compiled with -p ground.

highsource added a commit to highsource/jsonix-support that referenced this issue Jun 13, 2015
highsource added a commit that referenced this issue Jun 13, 2015
highsource added a commit to highsource/jsonix-support that referenced this issue Jun 13, 2015
@highsource
Copy link
Owner

To sum up, this does not seem to be a problem in Jsonix, but rather in Jsonix Schema Compiler.
With the -p option you've generated everything in just one mapping. The correct behaviour for the Jsonix Schema Compiler would have been to fail with an error message about duplicate types.
Here's an issue for that:

highsource/jsonix-schema-compiler#41

You have the following options:

  • don't use -p - you'll get three modules instead.
  • customize one of the LocaType to get a different name.
  • do not use -p, customize to generate one module with three mappings.

I've created a "support" project to demonstrate the third options:

https://github.com/highsource/jsonix-support/blob/master/issues/issue-83/bindings/bindings.xjb

With generated mappings, tests go through:

https://github.com/highsource/jsonix/tree/master/nodejs/scripts/tests/GH83

I'm closing this as this is not a Jsonix issue and there's a workaround.
See highsource/jsonix-schema-compiler#41 for the follow-up issue in Jsonix Schema Compiler.

@hokkos
Copy link
Author

hokkos commented Jun 14, 2015

Yesterday I had another look at the jsonix schema compiler documentation and indeed tried without the -p options and successfully tested a round trip marshalling with our 84 schemas catalog on all our samples. I was about to close the issue, thanks for the explanation I will also look at the bindings options.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants