Search code examples
xsltxpathxsdmetadatadatamodel

Meta data driven generation with XSLT


I'm regularly creating an XSD schema by transforming a proprietary data model of a legacy system. This works out pretty good. However, the legacy system only allows me to specify very basic attributes of a parameter, such as the data type (int, string etc.).

I would like to enhance the XSL transformation with a mechanism that allows me to add meta data in order to provide more details for the transformation. I thought of something like the Java properties notation to assign attributes to an XPath.

Imagine the following example:

legacy system data model (actually that neat, but best suited for demonstration purposes)

<datamodel>
  <customer>
    <firstName type="string"/>
    <lastName type="string"/>
    <age type="int">
  <customer>
</datamodel>

meta data

customer/firstName/@nillable=false
customer/lastName/@nillable=false
customer/age/@nillable=true
customer/firstName/@minOccurs=1
customer/firstName/@maxOccurs=1
customer/lastName/@minOccurs=1
customer/lastName/@maxOccurs=1

resulting XSD schema

...
<xs:complexType name="customerType">
  <xs:sequence>
    <xs:element name="firstName" type="xs:string" nillable="false" minOccurs="1" maxOccurs="1"/>
    <xs:element name="lastName" type="xs:string" nillable="false" minOccurs="1" maxOccurs="1"/>
    <xs:element name="age" type="xs:int" nillable="true"/>
  </xs:sequence>
</xs:complexType>
...

What do you think of that? Is there a way to include meta data into an XSL stylesheet?


Solution

  • The best solution would be to modify the legacy data by adding the missing metadata.

    An instance of the modified "datamodel" vocabulary may be something like this:

    <datamodel xmlns:nm="my:new.meta">
        <customer>
            <firstName type="string"
                       nm:nillable="false"
                       nm:minOccurs="1"
                       nm:maxOccurs="1"
                       />
            <lastName type="string"
                      nm:nillable="false"
                      nm:minOccurs="1"
                      nm:maxOccurs="1"
                      />
            <age type="int" nm:nillable="true"/>
        </customer>
    </datamodel>
    

    Putting the new properties in a separate namespace is a good way to easily distinguish them from the already supported properties. Usually using attributes in a namespace is not recommended, so if this is to be avoided, one could use sub-elements (belonging to the new namespace) instead of attributes. Making the new attributes belong to a different namespace may result in the legacy schema validation not to reject them.

    If due to some reasons it is not possible to modify the legacy data, I would recommend not to include the new properties in the XSLT stylesheet itself (this is perfectly possible, for example as defining this as the contents of a global <xsl:variable>), but to provide these new properties as a separate XML file or as a set of one ore more XML files.

    Any XML file may be accessed dynamically during an XSLT transformation using the XSLT document() function. An instance of the XML file with the new properties may look like this:

    <newProperties xmlns:nm="my:new.meta">
        <customer>
            <firstName nm:nillable="false"
                       nm:minOccurs="1"
                       nm:maxOccurs="1"
                       />
            <lastName nm:nillable="false"
                      nm:minOccurs="1"
                      nm:maxOccurs="1"
                      />
            <age nm:nillable="true"/>
        </customer>
    </newProperties>
    

    Hope this helped.

    Cheers,

    Dimitre Novatchev