4.4.4. XML files

MetaFactory produces 3 different kinds of files:

  • java source code,

  • xml files and

  • plain text files.

The <xml files> element is the way to create XML files such as Maven’s pom.xml.

Usage

Listing 4.37 <XML files element> Syntax
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
<pattern>
...

<xml __filename=""
     __path=""
     __root=""
     __publicid=""
     __systemid=""
     __baseuri=""
     __foreach="package|object|attribute|reference|object.attribute|object.reference"
     __package=""
     __condition=""
     __var0=""
     __var1=""
     __var2=""
     __var3=""
     __var4=""
     __var5=""
     __skip="">

    <your-root-element
            __foreach="package|object|attribute|reference|object.attribute|object.reference"
        __package=""
        __condition=""
        __var0=""
        __var1=""
        __var2=""
        __var3=""
        __var4=""
        __var5="">

        <some-element someAttribute="any attribute"
            someOtherAttribute="another attribute">
        </some-element>
        <some-other-element ></some-other-element>

        ...any valid xml allowed here

        <some-recurring-element someattribute=""
            __foreach=""
            __package=""
            __condition=""
            __var0=""
            __var1=""
            __var2=""
            __var3=""
            __var4=""
            __var5="">
        </some-recurring-element>
    </your-root-element>
</xml>

...
</pattern>

The <xml> element is the root element of the created xml document. Everything is copied into this root element except some predefined attributes. The __filename attribute of xml is mandatory and used to set the name of the created xml file. Namespaces that you define in children of the <xml> element (e.g. the Maven namespace for pom.xml) are copied to its generated XML output. However, the MetaFactory namespaces that belong to the pattern are removed from the result.

Attributes

Table 4.39 attributes of <xml/>

Name

Details

__filename

Name of the xml file being made.

__path

Path where the xml file is saved.

__root

Used to set root of a DOCTYPE. Suppose this DOCTYPE must be declared for a xml file:

<!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD//EN"
                        "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">

These attributes of the xml pattern element need to be set:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
<xml __filename="hibernate.cfg.xml"
     ...
     __root="hibernate-configuration"
     __publicid="-//Hibernate/Hibernate Configuration DTD//EN"
     __systemid="http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd"
     ...>

    <hibernate-configuration>
    ...
    </hibernate-configuration>
</xml>

__publicid

Used to set the publicid part of a DTD reference. Used to set a DOCTYPE

__systemid

Used to set the systemid part of a DTD reference. Used to set a DOCTYPE

__baseuri

Set the xml:base attribute of the xml document.

__foreach

Indicates if XML File must be created foreach element in model (value of foreach determines what model element). Possible values: package, object, attribute, reference, object.attribute, object.reference

__condition

An expression that evaluates to true or false. Generation of the current file wil precede if true and otherwise not.

Example:

condition="${object.name}=Person"

In this case, the package is generated only if the current model object has the name: Person. This works only if all model objects are iterated (foreach=”object”).

__package

The name of the package in the model (model.xml) that must be used to apply the foreach attribute.

__var0

Value that you wish to store in the pre-defined variable with the name var0. Reference to this value can be made later by means of: ${var0}. This can be used in both the pattern and in a snippet (freemarker or velocity template).

__var1

Value that you wish to store in the pre-defined variable with the name var1. Reference to this value can be made later by means of: ${var1}. This can be used in both the pattern and in a snippet (freemarker or velocity template).

__var2

Value that you wish to store in the pre-defined variable with the name var2. Reference to this value can be made later by means of: ${var2}. This can be used in both the pattern and in a snippet (freemarker or velocity template).

__var3

Value that you wish to store in the pre-defined variable with the name var3. Reference to this value can be made later by means of: ${var3}. This can be used in both the pattern and in a snippet (freemarker or velocity template).

__var4

Value that you wish to store in the pre-defined variable with the name var4. Reference to this value can be made later by means of: ${var4}. This can be used in both the pattern and in a snippet (freemarker or velocity template).

__var5

Value that you wish to store in the pre-defined variable with the name var5. Reference to this value can be made later by means of: ${var5}. This can be used in both the pattern and in a snippet (freemarker or velocity template).

skip

true or false. If true and the menu check box “Use @skip of packages” (menu Transform) is checked, then the package is not made. This function is intended to prevent everything having to be re-generated each time, thereby saving time. This function enables you to work on a specific xml file by setting all skip attributes to true, except for those you are currently working on.

Sub elements

The first child element of xml is used as root element of the XML file to create, so only 1 child is allowed. Below this child element everything well formed xml is allowed. If iteration is required all child elements can also use these reserved attributes:

__foreach, __condition, __package  and  __var0 till __var5

Namespace

The entire pattern has to be in the pattern namespace, whereas the xml file to be created does not. The pattern namespace is therefore removed from the result. Occasionally no namespace is given for the document to be created, however it does contain elements which also occur in the pattern namespace. If, according to the pattern, an element is not valid, the xml parser gives an error message. To prevent the parser treating the element as part of the pattern namespace, we can use the namespace reserved with xml: as the prefix. Elements with this prefix are created, without this prefix, in the resulting xml document. This xml prefix indicates that the element doesn’t belong to the pattern namespace.

A better way to deal with this problem is defining the pattern namespace with a prefix (instead of default namespace).

An example of a situation where this is necessary occurs when creating hibernate xml mapping files for linking classes to database tables. In this mapping document use is made of a class element:

Listing 4.38 <XML element> Syntax
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
<xml
    __filename="${object.name}.hbm.xml"
    __foreach="object"
    __package="domain_model"
    __path="${pattern.property.directory.dao}/${pattern.property.conf.main.directory}"
    __root="hibernate-mapping"
    __systemid="http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"
    __skip="false">

    <hibernate-mapping package="${pattern.property.hibernate.pojo.package}">
        <xml:class name="${pattern.property.hibernate.pojo.class}" table="${object.name}" lazy="true">
            <id name="${firstgit rm Lower(${object.name})}Id" column="${allUpper(${object.name}_id)}">
                <generator class="native"></generator>
            </id>
            ....
        </xml:class>
    </hibernate-mapping>
</xml>

Snippets producing xml

Sometimes it is useful for the whole document (or a part) to be created by means of a “snippet”, in order to benefit from the power of velocity or freemarker. To utilise a snippet when creating the document and still maintain well-formed xml, you can use the the reserved element ‘<snippet_to_xml>’:

<snippet_to_xml>${snippet.xml.path.to.file.templatename}</snippet_to_xml>

The advantage is that the snippet itself does not have to make a 1-root element xml. All xml elements created are added as children of the parent of the special <snippet_to_xml> element.

Example

In the following example, the .page.xml document is created of a JBoss Seam web application. In this document, several param elements occur each of which is a child of the root element page. Some param elements appear to have a rather more complex structure, making it impossible (or difficult) to describe these with _foreach. Use should therefore be made of a velocity snippet (or freemarker).

The required xml in the pattern appears as follows:

Listing 4.39 <XML element> Example
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
<xml
   __filename="${firstLower(${object.name})}${var3}.page.xml"
   __path="${pattern.property.webapp.directory}"
   __foreach="object.property.edit.page"
   __package="domain_model"
   __var3="${forEachPropertyValue}"
   __var4="${firstLower(${object.name})}Dao"
   __skip="true">
        <page login-required="true"
              __ns="http://jboss.com/products/seam/pages"
              xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
              xsi:schemaLocation="http://jboss.com/products/seam/pages
                                  http://jboss.com/products/seam/pages-2.2.xsd">
            <restrict>${snippet.seam.page.edit.hasPermission}</restrict>

            <begin-conversation join="true" flush-mode="MANUAL"/>
            <action execute="#{${firstLower(${object.name})}Home.wire}"/>

            <description>#{messages['edit.text']}
                #{messages['${firstLower(${object.name})}.text']}
                (#{${firstLower(${object.name})}Home.${firstLower(${object.name})}Id})
            </description>

            <param name="${firstLower(${object.name})}From"/>
            <param name="${firstLower(${object.name})}Id"
                   value="#{${firstLower(${object.name})}Home.${firstLower(${object.name})}Id}"/>
            <param name="fromIdName" />
            <param name="fromIdValue" />

            <param name="${reference.name}From" __foreach="reference"
                   __condition="${reference.multiplicity}=0..1 OR ${reference.multiplicity}=1..1"/>
            <param name="${firstLower(${reference.type})}Id"
                   value="#{${firstLower(${reference.type})}Home.${firstLower(${reference.type})}Id}"
                   __foreach="reference"
                   __condition="${reference.multiplicity}=0..1 OR ${reference.multiplicity}=1..1" />

            <snippet_to_xml>${snippet.seam.page.edit.referencennParams}</snippet_to_xml>

            <param name="firstResult" value="#{${var4}.firstResult}"/>
            <param name="maxResults" value="#{${var4}.maxResults}" />
            <param name="sort" value="#{${var4}.orderColumn}"/>
            <param name="dir" value="#{${var4}.orderDirection}"/>

            <navigation from-action="#{${firstLower(${object.name})}Home.persist}">
                <rule if-outcome="persisted">
                    <end-conversation/>
                    <redirect view-id="/#{empty ${firstLower(${object.name})}From ?
                    '${firstLower(${object.name})}Search' : ${firstLower(${object.name})}From}.xhtml"/>
                </rule>
            </navigation>

            <navigation from-action="#{${firstLower(${object.name})}Home.update}">
                <rule if-outcome="updated">
                    <end-conversation/>
                    <redirect view-id="/#{empty ${firstLower(${object.name})}From ?
                    '${firstLower(${object.name})}Search' : ${firstLower(${object.name})}From}.xhtml"/>
                </rule>
            </navigation>

            <navigation from-action="#{${firstLower(${object.name})}Home.remove}">
                <rule if-outcome="removed">
                    <end-conversation/>
                    <redirect view-id="/${firstLower(${object.name})}Search.xhtml"/>
                </rule>
            </navigation>

        </page>
</xml>

Contents of the velocity template:

##stop if $currentModelObject is null
#if(!$currentModelObject)
  $generator.error("currentModelObject not found in context")
#end
#set($modelobject=$currentModelObject)  ## element of model
#set($modelObjectName=$currentModelObject.getAttributeValue("name"))
#set($modelObjectNameFL=${generator.firstLower($modelObjectName)})
#set($nnReferenceProperties=$generator.getPropertyElements($modelobject,"reference.nn"))
#foreach($nnReferenceProperty in $nnReferenceProperties)
  #set($nnReferencePath=$nnReferenceProperty.getTextNormalize())
  ##// handle nn reference: $nnReferencePath
  #set($tokens=$nnReferencePath.split('\.'))
  #set($tokenList=$generator.asList($tokens))
  #set($startObject=$tokenList.get(0))
  ##find the modelObject with name $startObject => this is just a check, because we only need the name of the object which we already know
  #set($modelPackage=$context.getModelPackage("domain_model"))
  #set($nnReferenceObjectElement=$generator.findChildByAttribute($modelPackage, "object", "name", "$startObject"))
  #set($nnReferenceObjectName=$nnReferenceObjectElement.getAttributeValue("name"))
  #set($nnReferenceObjectNameFL=${generator.firstLower($nnReferenceObjectName)})
        <!-- The ${modelObjectNameFL}Edit page can be called by ${nnReferenceObjectNameFL}View,
                 so we need to remember ${nnReferenceObjectNameFL}From and ${nnReferenceObjectNameFL}Id -->
   <param name="${nnReferenceObjectNameFL}From"/>
   <param name="${nnReferenceObjectNameFL}Id" value="#{${nnReferenceObjectNameFL}Home.${nnReferenceObjectNameFL}Id}"/>
#end