Kevin Dullemond on March 2, 2015
XSD choice elements exist to specify a number of alternatives of which only one can be present in an XML file. Formerly importing data from XML files which contained choice elements was not fully supported in the Mendix platform but with the release of version 5.14 this has been resolved. In this article we explain why this is important and how to make use of the new functionality.
To integrate Mendix applications with the outside world, it is possible to import XML documents and create Mendix objects based on the information contained in the document. To do this two things are needed. Firstly, an XML schema document (XSD file) which describes how the XML data is allowed to look like, to be able to recognize the objects described within. Secondly a translation of these XML object to Mendix objects is needed. A user of the Mendix platform describes this translation in an XML-to Domain mapping document and that document is the main topic of this article. In this document the user needs to configure:
Finally, to help the user in constructing this document there is a feature to create the Mendix entities automatically based on the defined elements in the XML schema.
The main limitations in the implementation of the situation described above have been resolved in version 5.14 and are discussed in this article. These limitations were:
In the remainder of this article we explain how the above issues have been resolved. Therefore it is targeted at Mendix developers that make use of XML-to-Domain mappings in general and to people making use of XML schema documents with choice elements in particular. First we introduce an explicit example of an XML schema with a choice element to illustrate the new functionality in section 2. Subsequently, in section 3 we illustrate the limitations by showing the example in action in the Mendix platform before version 5.14. Then in section 4 we use the same example to illustrate how this has been remedied in version 5.14. Finally, in section 5, we further illustrate the value of the changes by making use of the richer type information in the new XML-to-Domain mapping in a microflow.
We consider the following XML schema:
<?xml version="1.0" encoding="UTF-8"?> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" > <xs:complexType name="employee"> <xs:sequence> <xs:element name="firstname" type="xs:string"/> <xs:element name="lastname" type="xs:string"/> <xs:element name="salary" type="xs:int"/> </xs:sequence> </xs:complexType> <xs:complexType name="customer"> <xs:sequence> <xs:element name="firstname" type="xs:string"/> <xs:element name="lastname" type="xs:string"/> <xs:element name="company" type="xs:string"/> </xs:sequence> </xs:complexType> <xs:element name="persons"> <xs:complexType> <xs:choice minOccurs="0" maxOccurs="unbounded"> <xs:element name="employee" type="employee"/> <xs:element name="customer" type="customer"/> </xs:choice> </xs:complexType> </xs:element> </xs:schema>
This schema defines an element “persons”. It contains is a list of choice elements reflecting each “person” (minOccurs=”0” maxOccurs=”unbounded”). Each entry in this list is either an “employee” or a “customer” (but not both).
This is an example of a valid XML message:
<?xml version="1.0" encoding="UTF-8"?> <persons> <employee> <firstname>Piet </firstname> <lastname>Pieters</lastname> <salary>5</salary> </employee> <customer> <firstname>Customer</firstname> <lastname>Klant</lastname> <company>Company</company> </customer> <employee> <firstname>Other</firstname> <lastname>Guy</lastname> <salary>50</salary> </employee> </persons>
Here the persons list contains 3 entries: an employee, a customer and another employee.
In this section we show how creating a XML-to-Domain mapping based on this XML schema works in the current situation. First, you create a new XML schema document and choose the XML schema we defined in section 2. Subsequently, you create a new XML-to-Domain mapping, click “select elements” and in the resulting popup select the XML schema we just created as the schema source1. The resulting screen is displayed in Figure 1. In this figure we see that the choice element is not shown in the schema element tree and also that its 0-* multiplicity is therefore missing.
Figure 1. Selecting the XSD elements to include in a XML-to-Domain Mapping prior to version 5.14
When we select all elements and click Ok the left-hand side of the mapping has been filled. If subsequently we click “generate mappings” associated entities, attributes and associations are created (in the domain model, see Figure 2) and filled in on the right-hand side of the XML-to-Domain Mapping. The result is shown in Figure 3. In this figure we can see that on the left-hand side the choice option is indeed missing. The main consequence of this is that persons does not have one association with a list filled with both employees and customers (mixed together) as one would expect from the definition in the XML schema document but rather two 1:1 associations, one to employee and one to customer. This is something inherently different and can therefore lead to data loss if lists of customer/employees are imported as only the first is actually mapped to a Mendix Object. This has been resolved in version 5.14 of the Mendix platform as we illustrate in the next section.
Figure 2. The automatically generated domain model for the persons example prior to version 5.14
Figure 3. Configuring the mapping in a XML-to-Domain Mapping in the persons example prior to version 5.14
In this section we show how the situation described in the previous section in resolved. We do this by starting with the previous situation, describing the steps that need to be taken to convert the project and reflecting on the resulting changes. We do this to make it easier for people to upgrade. Of course, it is perfectly feasible to start a new project from scratch in the new situation. To do this, simply follow the same steps as described in section 3 and expand these with the additional steps described in this section.
When you open the project we created in section 3 in version 5.14 of the Mendix platform manual steps are need to convert your project. In the Errors window the following error message appears: “The mapping element is an option of a choice. Please reselect schema elements and include the choice element”. If you double-click on the message, the XML-to-Domain document will open and the relevant element is selected (see Figure 4).
Figure 4. After converting manual steps are needed to convert the project
As the message describes, we need to reselect schema elements to resolve the consistency error. To do this click “Select elements…” and the dialog depicted in Figure 5 will appear.
Figure 5. Reselecting the schema elements after conversion
In the schema elements tree we see there is now an explicit element for the XML choice element “(choice)”. Take note that the multiplicity of this element is correctly set to 0..*. The choice element has been automatically selected when opening this window so click Ok to save the setting and continue with the configuration of the mapping.
As can be seen in Figure 6, the “(choice)” mapping element has been inserted into the import mapping document. The meaning of this extra mapping element is the following: all alternatives for the choice (in this case employee and customer) should have something in common as they are alternatives for something. In this case the commonality between them is that they are both a person. Therefore in the new situation all the alternatives of a choice should inherit from a more general entity (Person) and that entity should be dragged onto the mapping. It is important to really get the meaning of this. For the example it means that the persons entity has a list of type Person and employees and customers are specific types of Persons that can therefore appear in the list.
In Figure 6 there are four consistency errors. The first two are resolved by selecting a correct generalization entity for employee and customer. The bottom two have to do with the fact that in the original situation (without the explicit choice element) the choice alternatives themselves (employee and customer) had associations with persons in the mapping. This is no longer allowed as this should be configured in the choice element. To resolve this double click the employee and customer, a message will appear explaining the association will be removed. Click Ok to confirm this.
Figure 6. The XML-to-Domain mapping document after selecting the new (choice) element
Resolving the first two consistency errors can be done by manually creating a generalization class for employee and customer and selecting this in the mapping document. An alternative is to use the “Map automatically” button to do this for you. If you click this button the message shown in Figure 7 is shown explaining what has been done.
Figure 7. An overview of the changes when automatically generating the mappings, entities, associations and attributes
Here you see that most of the entities and association in the mapping have been retained from the previous situation. For the choice element a class called ChoiceBase has been created, employee and customer have become specializations of this class and ChoiceBase is associated with the persons entity. This is a large improvement over how the “Map Automatically ..” function created entities, attributes and associations in previous versions as it used to recreate all entities, attributes and associations every time is was ran, resulting in an ever growing domain model filled with entities which are no longer needed.
The resulting domain model is shown in Figure 8.
Figure 8. The automatically generated domain model for the persons example
Note that we can make some improvements to this automatically generated model. Firstly, ChoiceBase is a very general term and because we actually understand our own domain model we can make it more specific. We can for instance rename the entity to “Person”. If we do so it is also a good idea to rename the “ChoiceBase_persons” association. Following this we can move the “firstname” and “lastname” attributes from the employee and customer entities to this Person entity because both specializations contain these attributes. Finally, we can remove the associations between employee and persons, and customer and persons because they are not needed anymore with the introduction of the Person entity. This because they they inherit the association with persons from the Person entity. After making all these changes the domain model will look like the one shown in Figure 9.
Figure 9. Manual improvement of the automatically generated domain model for the persons example
Having made these changes we notice four new consistency errors for the XML-to-Domain mapping. These consistency errors exist because we moved the “firstname” and “lastname” attributes from the specialization entities (employee and customer) to the generalization (Person) and we need to remap these manually. To do so go to the XML-to-Domain mapping and double click both customer and employee and map the attributes either manually or by clicking the “Map attributes by name” button. Having done so all the consistency errors are resolved and the XML-to-Domain mapping document looks like the one shown in Figure 10.
Figure 10. Final version of the XML-to-Domain mapping document for the persons example
Having explained how to create and configure a XML-to-Domain mapping for XML schemas with choice elements in the previous sections, we conclude this article by giving an example of how to use this mapping in a microflow. In this example we calculate the total of the salaries of all employees in the imported XML file while ignoring the customers (who have no salary defined).
To do this we create the microflow depicted in Figure 11. We do this as follows: First we select a Filedocument as the input parameter. Subsequently we drag in an “Import XML document” action, select the Filedocument as the input, our defined XML-to-Domain mapping as the mapping and select to store the output in a persons variable. Following this, we drag in a retrieve action in which we retrieve the personList over the “Person_persons” association of the persons variable. After this we create a variable to store the total of all the salaries and initialize it to zero. Then we iterate over all the items in the personList and take a different action based on what specific subtype of Person the item is (using an inheritance split). When the Person is an employee we cast it to an employee and add its salary to the total. If the Person is a customer we instead ignore it. Having iterated over all the items we write the sum of all the salaries to the log.
Figure 11. Microflow to sum the salaries of all the customers in an XML file using the XML-to-Domain mapping for the persons example
This article is co-authored by Pieter van Balen and Kevin Dullemond.