MENU

  /   XML Bestanden

MetaFactory produceert op dit moment 3 verschillende soorten bestanden: bron code (java), xml bestanden en platten bestanden.

Om xml te produceren moet het element xml worden gebruikt in het pattern.

Dit is de syntax:

<?xml version="1.0" encoding="UTF-8"?>
<pattern xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xmlns="http://www.firstbase.nl/xsd/personaliom/pattern"
         xsi:schemaLocation="http://www.firstbase.nl/xsd/personaliom/pattern
                             http://www.firstbase.nl/xsd/personaliom/pattern.xsd">

  ...
  <xml __filename=""
       __path=""
       __root=""
       __publicid=""
       __systemid=""
       __baseuri=""
       __foreach="package|object|attribute|reference|
                  object.attribute|object.reference"
       __package=""
       __condition=""
       __skip="">
    <your-root-element  __foreach="package|object|attribute|reference|
                                   object.attribute|object.reference"
                        __package=""
                        __condition="">

      <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="">
      </some-recurring-element>
    </your-root-element>
  </xml>
  ...
</pattern>

Alles wat onder het xml element staat wordt in het gegenereerde document gezet op een de onderstaande gereserverde attributen na. Het __filename attribuut is verplicht en geeft de naam van het xml bestand aan.
Namespaces in de elementen worden overgenomen.

attributen van <xml/>:

Naam Betekenis
__filename De bestandsnaam van het xml document dat gemaakt wordt.
__path Het pad waarin het xml document moet worden opgeslagen.
__root Indien het te maken xml document een verwijzing naar een DTD moet krijgen, dan wordt met dit attribuut het root element gespecificeerd.
Stel dat de volgende DTD moet worden toegevoegd aan het te maken xml document:

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

Dit kan worden bereikt met de volgende attributen:

    <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 Indien het te maken xml document een verwijzing naar een DTD moet krijgen, dan wordt met dit attribuut de public id van de DTD gespecificeerd.
__systemid Indien het te maken xml document een verwijzing naar een DTD moet krijgen, dan wordt met dit attribuut de system id van de DTD gespecificeerd.
__baseuri Met dit attribuut wordt het xml:base attribuut van een xml document opgegeven.
__foreach Geeft aan of er geïtereerd moet worden over het model. Mogelijke waarden: package, object, attribute, reference, object.attribute, object.reference
__condition Een expression die uitkomt op true of false. Indien er true uitkomt wordt het xml document ook daadwerkelijk gemaakt, maar als er false uit komt niet.
vb:

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

Het xml document wordt in dit geval alleen gemaakt indien het huidige model object de naam Person heeft. Dit werkt alleen indien er geïtereerd wordt over alle model objecten (foreach=”object”).

__package Naam van het package in het model (model.xml) wat gebruikt moet worden voor het uitvoeren van het foreach attribuut
__var0 Waarde die je wil opslaan in de voorgedefinieerde variabele met naam var0. Naar deze waarde kan later worden gerefereerd d.m.v. ${var0}. Dit kan zowel in het pattern als in een snippet worden gebruikt.
__var1 Waarde die je wil opslaan in de voorgedefinieerde variabele met naam var1. Naar deze waarde kan later worden gerefereerd d.m.v. ${var1}. Dit kan zowel in het pattern als in een snippet worden gebruikt.
__var2 Waarde die je wil opslaan in de voorgedefinieerde variabele met naam var2. Naar deze waarde kan later worden gerefereerd d.m.v. ${var2}. Dit kan zowel in het pattern als in een snippet worden gebruikt.
__var3 Waarde die je wil opslaan in de voorgedefinieerde variabele met naam var3. Naar deze waarde kan later worden gerefereerd d.m.v. ${var3}. Dit kan zowel in het pattern als in een snippet worden gebruikt.
__var4 Waarde die je wil opslaan in de voorgedefinieerde variabele met naam var4. Naar deze waarde kan later worden gerefereerd d.m.v. ${var4}. Dit kan zowel in het pattern als in een snippet worden gebruikt.
__var5 Waarde die je wil opslaan in de voorgedefinieerde variabele met naam var5. Naar deze waarde kan later worden gerefereerd d.m.v. ${var5}. Dit kan zowel in het pattern als in een snippet worden gebruikt.
__skip true of false. Als true en de het menu item “Use @skip of xml files” (menu Transform) is aangevinkt, dan wordt het package niet gemaakt. Deze functie is bedoeld om te voorkomen dat altijd alles opnieuw wordt gegenereerd en scheelt daarom tijd. Met deze functie kan je aan een specifiek package werken door alle skip attributen op true te zetten, behalve degene waaraan je nu werkt.

subelementen van <xml/>:
Het eerst child element van xml wordt het root element van het te maken document. Er mag daarom maar 1 child element aanwezig zijn. Onder het child element is alles toegestaan, zolang het maar geldige xml is. Bij alle child elementen kan ook weer gebruik worden gemaakt van

 __foreach, __condition en __package

zodra er geïtereerd moet worden over het model.

Namespace:
Het gehele pattern moet in de pattern namespace staan. Het te maken xml document niet, dus de pattern namespace wordt verwijderd uit het resultaat.
Het komt soms voor dat er geen namespace wordt opgegeven voor het te produceren document, maar dat er wel elementen in zitten die ook in de pattern namespace voorkomen. De xml parser geeft hier een foutmelding over, indien het element volgens het pattern niet geldig. Om te voorkomen dat de parser denkt dat het element bij de pattern namespace hoort kan gebruik worden gemaakt van de gereserveerde namespace met als prefix xml:. Elementen met deze prefix, worden zonder deze prefix in het geproduceerde xml document gezet. Door deze xml prefix wordt aangegeven dat hij niet bij de pattern namespace hoort.
Voorbeeld van een situatie waar dit nodig is bij het produceren van hibernate xml mapping files om classes aan database tables te koppelen. In dit mapping document wordt gebruikt gemaakt van een class element:

    <xml xmlns="http://www.firstbase.nl/xsd/personaliom/pattern"
        __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="${firstLower(${object.name})}Id" column="${allUpper(${object.name}_id)}">
            <generator class="native"></generator>
          </id>
      ....
        </xml:class>
      </hibernate-mapping>
    </xml>

Om bovenstaand probleem te omzeilen is het beter om het pattern niet in de default namespace te schrijven, maar om een prefix te gebruiken.

Snippets die xml produceren:
Soms is het handig om het gehele document of een gedeelte er van te produceren door middel van een “snippet”, zodat gebruik kan worden gemaakt van velocity of freemarker. Om bij het produceren gebruik te maken van een snippet en toch well-formed xml te houden kan gebruik worden gemaakt van het gereserveerde element

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

.
Het voordeel is dat de snippet zelf geen xml met 1 root element hoeft te produceren. Alle xml die geproduceerd wordt komen als child element onder de parent van het speciale snippet_to_xml element.
vb.:
In onderstaand voorbeeld wordt het .page.xml document van een JBoss Seam webapplicatie geproduceerd. In dit document komen verschillende param elementen voor die allemaal child zijn van het root element page. Voor sommige param elementen bleken de constructies iets complexer te zijn, waardoor het niet mogelijk (of lastig) was om dit met __foreach te beschrijven. Er moest daarom gebruik worden gemaakt van een velocity snippet. De benodigde xml code in het pattern zag er als volgt uit:

    <xml xmlns="http://www.firstbase.nl/xsd/personaliom/pattern"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://www.firstbase.nl/xsd/personaliom/pattern http://www.firstbase.nl/xsd/personaliom/pattern.xsd"
        __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" />

        <span class="red"><snippet_to_xml>${snippet.seam.page.edit.referencennParams}</snippet_to_xml></span>

        <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>

De inhoud van de velocity snippet was dit:

    ##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