Adding Custom Aspect Support in Alfresco Share

Since Alfresco 3.2 introduced the ability to configure the metadata forms used in the Document Library, there have been several good articles published on how to add support for custom document types.
One of the first questions people often ask when they see Share is how they can easily extend the metadata fields that are stored against a document. Whilst this can be done using custom document types, aspects often provide a more agile solution.
So this article should explain how Share can be easily extended to support custom aspects using good practice techniques, specifically

  • Ensuring all extended configuration is placed outside of the share webapp, so protecting it from upgrades and redeployments, and
  • Using i18n labels for all text strings that appear in the UI, thus allowing translation of the labels.

The example provides a number of files, all of which should be placed below the tomcat/shared/classes directory of your Alfresco installation. If you are not using the Alfresco-bundled version of Tomcat then you may need to create this directory yourself and configure Tomcat’s shared classloader to use it.
First you will need to configure the repository with your custom model definition. In my case I am using a simple knowledge base model that defines a single aspect kb:referencable. The aspect adds a new text property that allows a unique KB reference number to be added to documents.
First, the Spring configuration defined in alfresco/extension/kb-model-context.xml

<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE beans PUBLIC '-//SPRING//DTD BEAN//EN' 'http://www.springframework.org/dtd/spring-beans.dtd'>
<beans>
    <!-- Registration of new models -->
    <bean id="extension.kb.dictionaryBootstrap" parent="dictionaryModelBootstrap" depends-on="dictionaryBootstrap">
        <property name="models">
            <list>
                <value>alfresco/extension/kb-model.xml</value>
            </list>
        </property>
    </bean>
     <bean id="extension.kb.resourceBundle" class="org.alfresco.i18n.ResourceBundleBootstrapComponent">
       <property name="resourceBundles">
          <list>
             <value>alfresco.messages.knowledgebase</value>
          </list>
       </property>
    </bean>
</beans>

Then, define the model itself in alfresco/extension/kb-model.xml

<?xml version="1.0" encoding="UTF-8"?>
<!-- Definition of Knowledge Base Model -->
<model name="kb:knowledgebase" xmlns="http://www.alfresco.org/model/dictionary/1.0">
   <!-- Optional meta-data about the model -->
   <description>Knowledge Base Model</description>
   <author>Will Abson</author>
   <version>1.0</version>
   <!-- Imports are required to allow references to definitions in other models -->
   <imports>
      <!-- Import Alfresco Dictionary Definitions -->
      <import uri="http://www.alfresco.org/model/dictionary/1.0" prefix="d"/>
      <!-- Import Alfresco Content Domain Model Definitions -->
      <import uri="http://www.alfresco.org/model/content/1.0" prefix="cm"/>
   </imports>
   <!-- Introduction of new namespaces defined by this model -->
   <namespaces>
      <namespace uri="http://www.alfresco.com/model/knowledgebase/1.0" prefix="kb"/>
   </namespaces>
    <aspects>
      <!-- Definition of new Content Aspect: Knowledge Base Document -->
      <aspect name="kb:referencable">
         <title>Knowledge Base Referencable</title>
         <properties>
            <property name="kb:documentRef">
               <type>d:text</type>
            </property>
         </properties>
      </aspect>
   </aspects>
</model>

The last file in our model definition adds some i18n labels for the aspect and property names. Add the following content to the file alfresco/messages/knowledgebase.properties.

# Custom knowledge base messages
kb_knowledgebase.property.kb_documentRef.title=KB Reference
kb_knowledgebase.aspect.kb_referencable.title=Knowledge Base Referencable
aspect.kb_referencable=Knowledge Base Referencable

With the model added the repository should start up without errors and will know about the new aspect. In order to use it, we need to configure Share to show this aspect in the Manage Aspects dialogue and to display the KB Reference field in forms, when a node has the aspect applied.
The file alfresco/web-extension/share-config-custom.xml can be used to do both these things.

<alfresco-config>
   <!-- Document Library config section -->
   <config evaluator="string-compare" condition="DocumentLibrary">
      <!--
         Used by the "Manage Aspects" action
         For custom aspects, remember to also add the relevant i18n string(s)
            cm_myaspect=My Aspect
      -->
      <aspects>
         <!-- Aspects that a user can see -->
         <visible>
            <aspect name="cm:generalclassifiable" />
            <aspect name="cm:complianceable" />
            <aspect name="cm:dublincore" />
            <aspect name="cm:effectivity" />
            <aspect name="cm:summarizable" />
            <aspect name="cm:versionable" />
            <aspect name="cm:templatable" />
            <aspect name="cm:emailed" />
            <aspect name="emailserver:aliasable" />
            <aspect name="cm:taggable" />
            <aspect name="app:inlineeditable" />
            <aspect name="kb:referencable" />
         </visible>
         <!-- Aspects that a user can add. Same as "visible" if left empty -->
         <addable>
         </addable>
         <!-- Aspects that a user can remove. Same as "visible" if left empty -->
         <removeable>
         </removeable>
      </aspects>
   </config>
   <!-- cm:content type (existing nodes) -->
   <config  evaluator="node-type" condition="cm:content">
      <forms>
         <!-- Default form configuration used on the document details and edit metadata pages -->
         <form>
            <field-visibility>
               <show id="kb:documentRef" />
            </field-visibility>
         </form>
         <!-- Document Library pop-up Edit Metadata form -->
         <form id="doclib-simple-metadata">
            <field-visibility>
               <show id="kb:documentRef" />
            </field-visibility>
            <edit-form template="../documentlibrary/forms/doclib-simple-metadata.ftl" />
         </form>
         <!-- Document Library Inline Edit form -->
         <form id="doclib-inline-edit">
            <field-visibility>
               <show id="kb:documentRef" />
            </field-visibility>
         </form>
      </forms>
   </config>
</alfresco-config>

This configuration will add the KB reference field at the bottom of the main Edit Metadata form, the pop-up edit form used in the document list view and lastly the in-line edit form used for HTML, text and XML content (introduced in Alfresco 3.3).
Note: More advanced control is possible over the placement of the field within the form, but this requires copying over the full form definitions for the cm:content type from the file alfresco/web-framework-config-commons.xml (or alfresco/share-form-config.xml in 3.3 onwards) inside the Share webapp and adding the attribute replace="true" on the <config> element.
Now that you’ve configured Share, you must restart Tomcat so that the changes are picked up. The application should start up and you should be able to add the aspect to some content and see the document reference field appear in forms.
The last thing to do is to add an i18n label for the Knowledge Base aspect in the Manage Aspects dialogue. To do this we need to define a small bit of Spring configuration in the file alfresco/web-extension/custom-slingshot-application-context.xml, which will wire the knowledgebase.properties file we created earlier into Share.

<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE beans PUBLIC '-//SPRING//DTD BEAN//EN' 'http://www.springframework.org/dtd/spring-beans.dtd'>
<beans>
   <!-- Add Knowledge Base messages -->
   <bean id="webscripts.kb.resources" class="org.springframework.extensions.surf.util.ResourceBundleBootstrapComponent">
      <property name="resourceBundles">
         <list>
            <value>alfresco.messages.knowledgebase</value>
         </list>
      </property>
   </bean>
</beans>

In versions prior to Alfresco 3.3 (when some changes were made to the Share resource bundle classes) the following configuration must be used instead (note the different class name)

<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE beans PUBLIC '-//SPRING//DTD BEAN//EN' 'http://www.springframework.org/dtd/spring-beans.dtd'>
<beans>
   <!-- Add Knowledge Base messages -->
   <bean id="webscripts.kb.resources" class="org.alfresco.i18n.ResourceBundleBootstrapComponent">
      <property name="resourceBundles">
         <list>
            <value>alfresco.messages.knowledgebase</value>
         </list>
      </property>
   </bean>
</beans>

This configuration tells Share to look in the file knowledgebase.properties for aspect labels, in addition to the core message bundles.
With that file added you should be able to restart Tomcat again and see the correct label in the Manage Aspects dialogue. You’ve now fully-customised Alfresco Share to support additional custom aspects.
Update: Thanks to Brian Ochs, who pointed out that the additional message aspect.kb_referencable is also required in knowledgebase.properties.
Update: The configuration files in this tutorial can now be downloaded in ZIP format. To use them directly extract the archive into tomcat/shared/classes and restart the server. Please do not use these files, which are now outdated.

Share Extensions Build Script

Update, 4th May 2011: The latest version of the build script and sample Eclipse project is now hosted on Share Extras. For more information please see the Sample Project page.
With Kev’s recent SpringSurf changes in the 3.3 code line, Share extensions are now much easier to deploy as shared libraries. However, it’s still up to individual developers to set up their own project structure and to package this up as a JAR.
So, to build the latest Site Tags dashlet using this method I put together an Ant build script, which hopefully will be useful to others.
As well as building a JAR it also supports the unofficial ZIP structure that we’d used previously to package up sample dashlets, in addition to the AMP format that we use for the more complex DoD extensions for Share.
The build script assumes a standard Alfresco project layout as follows

 /config - all web-tier configuration files, with a top-level 'alfresco' package
 /web - all static resources, e.g. CSS and JS files

You can use the build script with your existing projects if they fit this structure, or you can use my own zipped-up site tags dashlet project as a template for your own. This should import into a fresh Eclipse project but you could extract it elsewhere.
Once your project is set up and you’re ready to package up your extension, you can run the following command to build the JAR.

 ant -Djar.name=my-sample-project.jar package-jar

To package up a ZIP or AMP, substitute ‘jar’ in the parameters to ‘zip’ or ‘acp’. Easy, eh?

Opportunistic Alfresco

Great post from Jono at Ubuntu on making the Ubuntu platform better suited to opportunistic development, basically helping people who want to ‘scratch an itch’ but don’t have the time or commitment to write an application in the traditional sense.
This is the first time I’ve come across a term for this sort of activity, but it describes very well what Apple have done so well with their app store, and what many of us hope Google may be about to do better.
The faster development cycle afforded with open source means that such an environment is much better suited in theory to rapid application development than proprietary platforms, but it does require the necessary infrastructure to be in place.
I’ve been having thoughts recently on how we could better support this type of development within Alfresco. Like the iPhone and like Ubuntu, Alfresco is much more than just a product, it’s a solid platform for others to develop on.
In our case the building blocks are the web scripts and Surf frameworks that we recently fed back up into Spring, and the delivery mechanism could easily be provided by the Share UI.
Share already allows developers to define self-contained bits of functionality as dashlets, and also provides mechanisms to manage the configuration and display of these dashlets within the application. That’s 90% of our intrastructure already there.
The missing 10% is a mechanism by which developers can publish these extensions to make them available for others, basically a distibution channel, or if you must, an app store.
This is why I’ve started spec’ing out what I’m tentatively calling Share Components, to provide a directory of Share extensions and an easy mechanism for users to query such directories (note, plural) and install components from them onto their own Alfresco systems.
I’m making it very clear that this is a proposed feature for Share but nonetheless it’s one that I firmly believe is critical to ensuring that others – including our partners and others in the wider community – are able to join up their opportunistic dots using the Alfresco platfom.

Site tags dashlet improvements

If you attended one of the recent Meetups in Europe of the US you may have caught us using the site tags dashlet as an example of how to develop a custom dashlet for Alfresco Share.
Mike Hatfield did a great job of taking my original code and re-working it to shift most of the logic to client-side JS where it should be, as well as adding some funky scoping stuff using a couple of YUI controls.
The resulting code that we demonstrated ourselves in Madrid, and which others showed in other locations has been posted under the Meetups Worldwide space on share.alfresco.com (free login required) as a ZIP file. Also in the bundle is an example of how to extend the Document Library actions in Share with your own custom action.
For the latest version of the dashlet, however, you’ll need to head over to the site tags dashlet page. Version 0.1.1 contains a couple of extra lines to sort the tags into alphabetical order before they’re displayed – more consistent with other tag clouds I’m told – and the code has also been back-ported to Alfresco 3.1 because a few people asked for this.
The subject of porting dashlets between v3.1 and v3.2 is another topic in itself, as the pattern used to define JS modules in the latest version has improved substantially. I’ll try post more on this soon.

Tag cloud dashlet for Alfresco Share

This small extension to Share provides a new site dashlet to display the most popular tags within the site as a tag cloud.

The dashlet uses the existing tagging REST API, so no additional repository tier scripts are required. The zipped files can be extracted into your tomcat/shared/classes directory to add the Share support. You should find that the directory structure will be automatically created, although you will need to move the site-tags.css file to the components/dashlets directory in the webapp.
It should be trivial to write a second dashlet to surface a global tag cloud, suitable for display in a user dashboard, using the list all tags method, rather than the tagscope-based approach used by this script.
UPDATE: The latest version of the code can now be found on the site tags dashlet page.

ISO 3166 county codes and xs:enumeration

I’ve recently been working with the web team here to improve the partners section of the Alfresco site, the last part of which requires me to write a web form to allow content authors to easily add new partners, and modify existing ones.
Until now our partner listings have been manually edited using our generic page form, which has over time become difficult to edit and inflexible in the user searches it allows on the published site.
This situation has only got worse as we’ve added new partners. To illustrate this we now have over 150 partners around the globe, rather than the handful the current pages were designed to display.
One of the important capabilities of the new pages is the ability to query by country, therefore I needed a way for page authors to easily select countries from a drop-down list in the web form.
The current list of ISO country codes is pretty well maintained and is available to download in CSV or XML formats, however I couldn’t find any mark-up for expressing this list within an XSD form definition using xs:enumeration elements.
If you are using Alfresco WCM or writing an XSD for any other purpose, and you want to include a drop-down allowing the user to select a country from the list, you can use something like the following.
<xs:simpleType name="country">
<xs:restriction base="xs:normalizedString">
<xs:enumeration value="AF"><xs:annotation><xs:appinfo><alf:label>AFGHANISTAN</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="AX"><xs:annotation><xs:appinfo><alf:label>ÅLAND ISLANDS</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="AL"><xs:annotation><xs:appinfo><alf:label>ALBANIA</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="DZ"><xs:annotation><xs:appinfo><alf:label>ALGERIA</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="AS"><xs:annotation><xs:appinfo><alf:label>AMERICAN SAMOA</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="AD"><xs:annotation><xs:appinfo><alf:label>ANDORRA</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="AO"><xs:annotation><xs:appinfo><alf:label>ANGOLA</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="AI"><xs:annotation><xs:appinfo><alf:label>ANGUILLA</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="AQ"><xs:annotation><xs:appinfo><alf:label>ANTARCTICA</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="AG"><xs:annotation><xs:appinfo><alf:label>ANTIGUA AND BARBUDA</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="AR"><xs:annotation><xs:appinfo><alf:label>ARGENTINA</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="AM"><xs:annotation><xs:appinfo><alf:label>ARMENIA</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="AW"><xs:annotation><xs:appinfo><alf:label>ARUBA</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="AU"><xs:annotation><xs:appinfo><alf:label>AUSTRALIA</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="AT"><xs:annotation><xs:appinfo><alf:label>AUSTRIA</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="AZ"><xs:annotation><xs:appinfo><alf:label>AZERBAIJAN</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="BS"><xs:annotation><xs:appinfo><alf:label>BAHAMAS</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="BH"><xs:annotation><xs:appinfo><alf:label>BAHRAIN</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="BD"><xs:annotation><xs:appinfo><alf:label>BANGLADESH</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="BB"><xs:annotation><xs:appinfo><alf:label>BARBADOS</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="BY"><xs:annotation><xs:appinfo><alf:label>BELARUS</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="BE"><xs:annotation><xs:appinfo><alf:label>BELGIUM</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="BZ"><xs:annotation><xs:appinfo><alf:label>BELIZE</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="BJ"><xs:annotation><xs:appinfo><alf:label>BENIN</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="BM"><xs:annotation><xs:appinfo><alf:label>BERMUDA</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="BT"><xs:annotation><xs:appinfo><alf:label>BHUTAN</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="BO"><xs:annotation><xs:appinfo><alf:label>BOLIVIA, PLURINATIONAL STATE OF</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="BA"><xs:annotation><xs:appinfo><alf:label>BOSNIA AND HERZEGOVINA</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="BW"><xs:annotation><xs:appinfo><alf:label>BOTSWANA</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="BV"><xs:annotation><xs:appinfo><alf:label>BOUVET ISLAND</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="BR"><xs:annotation><xs:appinfo><alf:label>BRAZIL</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="IO"><xs:annotation><xs:appinfo><alf:label>BRITISH INDIAN OCEAN TERRITORY</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="BN"><xs:annotation><xs:appinfo><alf:label>BRUNEI DARUSSALAM</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="BG"><xs:annotation><xs:appinfo><alf:label>BULGARIA</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="BF"><xs:annotation><xs:appinfo><alf:label>BURKINA FASO</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="BI"><xs:annotation><xs:appinfo><alf:label>BURUNDI</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="KH"><xs:annotation><xs:appinfo><alf:label>CAMBODIA</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="CM"><xs:annotation><xs:appinfo><alf:label>CAMEROON</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="CA"><xs:annotation><xs:appinfo><alf:label>CANADA</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="CV"><xs:annotation><xs:appinfo><alf:label>CAPE VERDE</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="KY"><xs:annotation><xs:appinfo><alf:label>CAYMAN ISLANDS</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="CF"><xs:annotation><xs:appinfo><alf:label>CENTRAL AFRICAN REPUBLIC</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="TD"><xs:annotation><xs:appinfo><alf:label>CHAD</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="CL"><xs:annotation><xs:appinfo><alf:label>CHILE</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="CN"><xs:annotation><xs:appinfo><alf:label>CHINA</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="CX"><xs:annotation><xs:appinfo><alf:label>CHRISTMAS ISLAND</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="CC"><xs:annotation><xs:appinfo><alf:label>COCOS (KEELING) ISLANDS</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="CO"><xs:annotation><xs:appinfo><alf:label>COLOMBIA</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="KM"><xs:annotation><xs:appinfo><alf:label>COMOROS</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="CG"><xs:annotation><xs:appinfo><alf:label>CONGO</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="CD"><xs:annotation><xs:appinfo><alf:label>CONGO, THE DEMOCRATIC REPUBLIC OF THE</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="CK"><xs:annotation><xs:appinfo><alf:label>COOK ISLANDS</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="CR"><xs:annotation><xs:appinfo><alf:label>COSTA RICA</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="CI"><xs:annotation><xs:appinfo><alf:label>CÔTE D'IVOIRE</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="HR"><xs:annotation><xs:appinfo><alf:label>CROATIA</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="CU"><xs:annotation><xs:appinfo><alf:label>CUBA</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="CY"><xs:annotation><xs:appinfo><alf:label>CYPRUS</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="CZ"><xs:annotation><xs:appinfo><alf:label>CZECH REPUBLIC</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="DK"><xs:annotation><xs:appinfo><alf:label>DENMARK</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="DJ"><xs:annotation><xs:appinfo><alf:label>DJIBOUTI</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="DM"><xs:annotation><xs:appinfo><alf:label>DOMINICA</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="DO"><xs:annotation><xs:appinfo><alf:label>DOMINICAN REPUBLIC</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="EC"><xs:annotation><xs:appinfo><alf:label>ECUADOR</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="EG"><xs:annotation><xs:appinfo><alf:label>EGYPT</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="SV"><xs:annotation><xs:appinfo><alf:label>EL SALVADOR</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="GQ"><xs:annotation><xs:appinfo><alf:label>EQUATORIAL GUINEA</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="ER"><xs:annotation><xs:appinfo><alf:label>ERITREA</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="EE"><xs:annotation><xs:appinfo><alf:label>ESTONIA</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="ET"><xs:annotation><xs:appinfo><alf:label>ETHIOPIA</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="FK"><xs:annotation><xs:appinfo><alf:label>FALKLAND ISLANDS (MALVINAS)</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="FO"><xs:annotation><xs:appinfo><alf:label>FAROE ISLANDS</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="FJ"><xs:annotation><xs:appinfo><alf:label>FIJI</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="FI"><xs:annotation><xs:appinfo><alf:label>FINLAND</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="FR"><xs:annotation><xs:appinfo><alf:label>FRANCE</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="GF"><xs:annotation><xs:appinfo><alf:label>FRENCH GUIANA</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="PF"><xs:annotation><xs:appinfo><alf:label>FRENCH POLYNESIA</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="TF"><xs:annotation><xs:appinfo><alf:label>FRENCH SOUTHERN TERRITORIES</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="GA"><xs:annotation><xs:appinfo><alf:label>GABON</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="GM"><xs:annotation><xs:appinfo><alf:label>GAMBIA</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="GE"><xs:annotation><xs:appinfo><alf:label>GEORGIA</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="DE"><xs:annotation><xs:appinfo><alf:label>GERMANY</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="GH"><xs:annotation><xs:appinfo><alf:label>GHANA</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="GI"><xs:annotation><xs:appinfo><alf:label>GIBRALTAR</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="GR"><xs:annotation><xs:appinfo><alf:label>GREECE</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="GL"><xs:annotation><xs:appinfo><alf:label>GREENLAND</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="GD"><xs:annotation><xs:appinfo><alf:label>GRENADA</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="GP"><xs:annotation><xs:appinfo><alf:label>GUADELOUPE</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="GU"><xs:annotation><xs:appinfo><alf:label>GUAM</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="GT"><xs:annotation><xs:appinfo><alf:label>GUATEMALA</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="GG"><xs:annotation><xs:appinfo><alf:label>GUERNSEY</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="GN"><xs:annotation><xs:appinfo><alf:label>GUINEA</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="GW"><xs:annotation><xs:appinfo><alf:label>GUINEA-BISSAU</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="GY"><xs:annotation><xs:appinfo><alf:label>GUYANA</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="HT"><xs:annotation><xs:appinfo><alf:label>HAITI</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="HM"><xs:annotation><xs:appinfo><alf:label>HEARD ISLAND AND MCDONALD ISLANDS</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="VA"><xs:annotation><xs:appinfo><alf:label>HOLY SEE (VATICAN CITY STATE)</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="HN"><xs:annotation><xs:appinfo><alf:label>HONDURAS</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="HK"><xs:annotation><xs:appinfo><alf:label>HONG KONG</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="HU"><xs:annotation><xs:appinfo><alf:label>HUNGARY</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="IS"><xs:annotation><xs:appinfo><alf:label>ICELAND</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="IN"><xs:annotation><xs:appinfo><alf:label>INDIA</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="ID"><xs:annotation><xs:appinfo><alf:label>INDONESIA</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="IR"><xs:annotation><xs:appinfo><alf:label>IRAN, ISLAMIC REPUBLIC OF</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="IQ"><xs:annotation><xs:appinfo><alf:label>IRAQ</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="IE"><xs:annotation><xs:appinfo><alf:label>IRELAND</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="IM"><xs:annotation><xs:appinfo><alf:label>ISLE OF MAN</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="IL"><xs:annotation><xs:appinfo><alf:label>ISRAEL</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="IT"><xs:annotation><xs:appinfo><alf:label>ITALY</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="JM"><xs:annotation><xs:appinfo><alf:label>JAMAICA</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="JP"><xs:annotation><xs:appinfo><alf:label>JAPAN</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="JE"><xs:annotation><xs:appinfo><alf:label>JERSEY</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="JO"><xs:annotation><xs:appinfo><alf:label>JORDAN</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="KZ"><xs:annotation><xs:appinfo><alf:label>KAZAKHSTAN</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="KE"><xs:annotation><xs:appinfo><alf:label>KENYA</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="KI"><xs:annotation><xs:appinfo><alf:label>KIRIBATI</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="KP"><xs:annotation><xs:appinfo><alf:label>KOREA, DEMOCRATIC PEOPLE'S REPUBLIC OF</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="KR"><xs:annotation><xs:appinfo><alf:label>KOREA, REPUBLIC OF</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="KW"><xs:annotation><xs:appinfo><alf:label>KUWAIT</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="KG"><xs:annotation><xs:appinfo><alf:label>KYRGYZSTAN</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="LA"><xs:annotation><xs:appinfo><alf:label>LAO PEOPLE'S DEMOCRATIC REPUBLIC</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="LV"><xs:annotation><xs:appinfo><alf:label>LATVIA</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="LB"><xs:annotation><xs:appinfo><alf:label>LEBANON</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="LS"><xs:annotation><xs:appinfo><alf:label>LESOTHO</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="LR"><xs:annotation><xs:appinfo><alf:label>LIBERIA</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="LY"><xs:annotation><xs:appinfo><alf:label>LIBYAN ARAB JAMAHIRIYA</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="LI"><xs:annotation><xs:appinfo><alf:label>LIECHTENSTEIN</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="LT"><xs:annotation><xs:appinfo><alf:label>LITHUANIA</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="LU"><xs:annotation><xs:appinfo><alf:label>LUXEMBOURG</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="MO"><xs:annotation><xs:appinfo><alf:label>MACAO</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="MK"><xs:annotation><xs:appinfo><alf:label>MACEDONIA, THE FORMER YUGOSLAV REPUBLIC OF</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="MG"><xs:annotation><xs:appinfo><alf:label>MADAGASCAR</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="MW"><xs:annotation><xs:appinfo><alf:label>MALAWI</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="MY"><xs:annotation><xs:appinfo><alf:label>MALAYSIA</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="MV"><xs:annotation><xs:appinfo><alf:label>MALDIVES</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="ML"><xs:annotation><xs:appinfo><alf:label>MALI</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="MT"><xs:annotation><xs:appinfo><alf:label>MALTA</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="MH"><xs:annotation><xs:appinfo><alf:label>MARSHALL ISLANDS</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="MQ"><xs:annotation><xs:appinfo><alf:label>MARTINIQUE</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="MR"><xs:annotation><xs:appinfo><alf:label>MAURITANIA</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="MU"><xs:annotation><xs:appinfo><alf:label>MAURITIUS</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="YT"><xs:annotation><xs:appinfo><alf:label>MAYOTTE</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="MX"><xs:annotation><xs:appinfo><alf:label>MEXICO</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="FM"><xs:annotation><xs:appinfo><alf:label>MICRONESIA, FEDERATED STATES OF</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="MD"><xs:annotation><xs:appinfo><alf:label>MOLDOVA, REPUBLIC OF</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="MC"><xs:annotation><xs:appinfo><alf:label>MONACO</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="MN"><xs:annotation><xs:appinfo><alf:label>MONGOLIA</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="ME"><xs:annotation><xs:appinfo><alf:label>MONTENEGRO</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="MS"><xs:annotation><xs:appinfo><alf:label>MONTSERRAT</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="MA"><xs:annotation><xs:appinfo><alf:label>MOROCCO</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="MZ"><xs:annotation><xs:appinfo><alf:label>MOZAMBIQUE</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="MM"><xs:annotation><xs:appinfo><alf:label>MYANMAR</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="NA"><xs:annotation><xs:appinfo><alf:label>NAMIBIA</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="NR"><xs:annotation><xs:appinfo><alf:label>NAURU</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="NP"><xs:annotation><xs:appinfo><alf:label>NEPAL</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="NL"><xs:annotation><xs:appinfo><alf:label>NETHERLANDS</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="AN"><xs:annotation><xs:appinfo><alf:label>NETHERLANDS ANTILLES</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="NC"><xs:annotation><xs:appinfo><alf:label>NEW CALEDONIA</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="NZ"><xs:annotation><xs:appinfo><alf:label>NEW ZEALAND</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="NI"><xs:annotation><xs:appinfo><alf:label>NICARAGUA</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="NE"><xs:annotation><xs:appinfo><alf:label>NIGER</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="NG"><xs:annotation><xs:appinfo><alf:label>NIGERIA</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="NU"><xs:annotation><xs:appinfo><alf:label>NIUE</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="NF"><xs:annotation><xs:appinfo><alf:label>NORFOLK ISLAND</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="MP"><xs:annotation><xs:appinfo><alf:label>NORTHERN MARIANA ISLANDS</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="NO"><xs:annotation><xs:appinfo><alf:label>NORWAY</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="OM"><xs:annotation><xs:appinfo><alf:label>OMAN</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="PK"><xs:annotation><xs:appinfo><alf:label>PAKISTAN</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="PW"><xs:annotation><xs:appinfo><alf:label>PALAU</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="PS"><xs:annotation><xs:appinfo><alf:label>PALESTINIAN TERRITORY, OCCUPIED</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="PA"><xs:annotation><xs:appinfo><alf:label>PANAMA</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="PG"><xs:annotation><xs:appinfo><alf:label>PAPUA NEW GUINEA</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="PY"><xs:annotation><xs:appinfo><alf:label>PARAGUAY</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="PE"><xs:annotation><xs:appinfo><alf:label>PERU</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="PH"><xs:annotation><xs:appinfo><alf:label>PHILIPPINES</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="PN"><xs:annotation><xs:appinfo><alf:label>PITCAIRN</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="PL"><xs:annotation><xs:appinfo><alf:label>POLAND</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="PT"><xs:annotation><xs:appinfo><alf:label>PORTUGAL</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="PR"><xs:annotation><xs:appinfo><alf:label>PUERTO RICO</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="QA"><xs:annotation><xs:appinfo><alf:label>QATAR</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="RE"><xs:annotation><xs:appinfo><alf:label>RÉUNION</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="RO"><xs:annotation><xs:appinfo><alf:label>ROMANIA</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="RU"><xs:annotation><xs:appinfo><alf:label>RUSSIAN FEDERATION</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="RW"><xs:annotation><xs:appinfo><alf:label>RWANDA</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="BL"><xs:annotation><xs:appinfo><alf:label>SAINT BARTHÉLEMY</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="SH"><xs:annotation><xs:appinfo><alf:label>SAINT HELENA</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="KN"><xs:annotation><xs:appinfo><alf:label>SAINT KITTS AND NEVIS</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="LC"><xs:annotation><xs:appinfo><alf:label>SAINT LUCIA</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="MF"><xs:annotation><xs:appinfo><alf:label>SAINT MARTIN</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="PM"><xs:annotation><xs:appinfo><alf:label>SAINT PIERRE AND MIQUELON</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="VC"><xs:annotation><xs:appinfo><alf:label>SAINT VINCENT AND THE GRENADINES</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="WS"><xs:annotation><xs:appinfo><alf:label>SAMOA</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="SM"><xs:annotation><xs:appinfo><alf:label>SAN MARINO</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="ST"><xs:annotation><xs:appinfo><alf:label>SAO TOME AND PRINCIPE</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="SA"><xs:annotation><xs:appinfo><alf:label>SAUDI ARABIA</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="SN"><xs:annotation><xs:appinfo><alf:label>SENEGAL</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="RS"><xs:annotation><xs:appinfo><alf:label>SERBIA</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="SC"><xs:annotation><xs:appinfo><alf:label>SEYCHELLES</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="SL"><xs:annotation><xs:appinfo><alf:label>SIERRA LEONE</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="SG"><xs:annotation><xs:appinfo><alf:label>SINGAPORE</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="SK"><xs:annotation><xs:appinfo><alf:label>SLOVAKIA</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="SI"><xs:annotation><xs:appinfo><alf:label>SLOVENIA</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="SB"><xs:annotation><xs:appinfo><alf:label>SOLOMON ISLANDS</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="SO"><xs:annotation><xs:appinfo><alf:label>SOMALIA</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="ZA"><xs:annotation><xs:appinfo><alf:label>SOUTH AFRICA</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="GS"><xs:annotation><xs:appinfo><alf:label>SOUTH GEORGIA AND THE SOUTH SANDWICH ISLANDS</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="ES"><xs:annotation><xs:appinfo><alf:label>SPAIN</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="LK"><xs:annotation><xs:appinfo><alf:label>SRI LANKA</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="SD"><xs:annotation><xs:appinfo><alf:label>SUDAN</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="SR"><xs:annotation><xs:appinfo><alf:label>SURINAME</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="SJ"><xs:annotation><xs:appinfo><alf:label>SVALBARD AND JAN MAYEN</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="SZ"><xs:annotation><xs:appinfo><alf:label>SWAZILAND</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="SE"><xs:annotation><xs:appinfo><alf:label>SWEDEN</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="CH"><xs:annotation><xs:appinfo><alf:label>SWITZERLAND</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="SY"><xs:annotation><xs:appinfo><alf:label>SYRIAN ARAB REPUBLIC</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="TW"><xs:annotation><xs:appinfo><alf:label>TAIWAN, PROVINCE OF CHINA</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="TJ"><xs:annotation><xs:appinfo><alf:label>TAJIKISTAN</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="TZ"><xs:annotation><xs:appinfo><alf:label>TANZANIA, UNITED REPUBLIC OF</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="TH"><xs:annotation><xs:appinfo><alf:label>THAILAND</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="TL"><xs:annotation><xs:appinfo><alf:label>TIMOR-LESTE</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="TG"><xs:annotation><xs:appinfo><alf:label>TOGO</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="TK"><xs:annotation><xs:appinfo><alf:label>TOKELAU</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="TO"><xs:annotation><xs:appinfo><alf:label>TONGA</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="TT"><xs:annotation><xs:appinfo><alf:label>TRINIDAD AND TOBAGO</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="TN"><xs:annotation><xs:appinfo><alf:label>TUNISIA</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="TR"><xs:annotation><xs:appinfo><alf:label>TURKEY</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="TM"><xs:annotation><xs:appinfo><alf:label>TURKMENISTAN</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="TC"><xs:annotation><xs:appinfo><alf:label>TURKS AND CAICOS ISLANDS</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="TV"><xs:annotation><xs:appinfo><alf:label>TUVALU</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="UG"><xs:annotation><xs:appinfo><alf:label>UGANDA</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="UA"><xs:annotation><xs:appinfo><alf:label>UKRAINE</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="AE"><xs:annotation><xs:appinfo><alf:label>UNITED ARAB EMIRATES</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="GB"><xs:annotation><xs:appinfo><alf:label>UNITED KINGDOM</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="US"><xs:annotation><xs:appinfo><alf:label>UNITED STATES</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="UM"><xs:annotation><xs:appinfo><alf:label>UNITED STATES MINOR OUTLYING ISLANDS</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="UY"><xs:annotation><xs:appinfo><alf:label>URUGUAY</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="UZ"><xs:annotation><xs:appinfo><alf:label>UZBEKISTAN</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="VU"><xs:annotation><xs:appinfo><alf:label>VANUATU</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="VE"><xs:annotation><xs:appinfo><alf:label>VENEZUELA, BOLIVARIAN REPUBLIC OF</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="VN"><xs:annotation><xs:appinfo><alf:label>VIET NAM</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="VG"><xs:annotation><xs:appinfo><alf:label>VIRGIN ISLANDS, BRITISH</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="VI"><xs:annotation><xs:appinfo><alf:label>VIRGIN ISLANDS, U.S.</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="WF"><xs:annotation><xs:appinfo><alf:label>WALLIS AND FUTUNA</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="EH"><xs:annotation><xs:appinfo><alf:label>WESTERN SAHARA</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="YE"><xs:annotation><xs:appinfo><alf:label>YEMEN</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="ZM"><xs:annotation><xs:appinfo><alf:label>ZAMBIA</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
<xs:enumeration value="ZW"><xs:annotation><xs:appinfo><alf:label>ZIMBABWE</alf:label></xs:appinfo></xs:annotation></xs:enumeration>
</xs:restriction>
</xs:simpleType>

Alfresco Share yn Gymraeg

Tracking string updates in HEAD is probably not the most productive way to manage a translation project, but I’m impatient.

Despite that, at this moment in time all the translatable text of Alfresco Share is now available in Welsh. Some things such as page titles don’t seem to be internationalisable yet, but I estimate some 90% of the content is fully translated.

A small patch to the Web Script Framework is needed to force the web app to use the locale-specific message bundles rather than the default ones but once that was done and I’d thrown the translated .properties files onto the classpath (they must be added into the web app itself, not anywhere else) it all started magically working.

Screenshots ahoy!

EA cause chaos in North London!

We all know the guys at Electronic Arts know a good WCM platform when they see one, but their latest trick over here has landed them some mixed PR – taking over a petrol station in Finsbury Park and giving away £20,000 of fuel to anyone who wants it!

According to the article on BBC News, the stunt is in order to promote their latest game Mercenaries 2, but the disruption has upset a few local residents.

Louise Marchant, from Electronic Arts, said the scenes of queuing mimicked aspects of the game.

Wicked.

WCM and XML Processing

One thing that we’ve been pretty good at since the launch of Alfresco WCM 18 months ago is our eating of the proverbial dog-food, in that we use the product itself to author, review and push out updates to our web site.

The majority of the site is relatively static in nature and is therefore pre-baked by our templates. Where JSP is used it is mostly for simple tasks such as including common header and footer components and looking up message strings, but there are some areas of the site which do have more dynamic data.

Up until now these areas – including our events, press releases and training pages – have leveraged some relatively simple but custom-built Java libraries that allow data from the underlying XML files to be queried and presented as appropriate, similar to the press release example bundled with the Alfresco example site in WCM.

This approach has worked well, but is a barrier to adding new functionality to the site since extra code must be developed to handle new data types. Whereas data can be queried easily at rendering time using the getXMLDocuments() function exposed to Freemarker and Xalan, this is more difficult to do at request time, requiring either an Alfresco runtime environment on the delivery side or extra code, as above.

I wanted to find a way to allow web developers to easily implement this functionality using JSP and JSTL only and the result has been an XML data processing library that can be leveraged by a JSP page to dynamically pull in and process XML data to assemble the page.

As of yet there is no snazzy name, but suggestions are welcome! The library is a single JAR file, plus a tag descriptor to provide the necessary functions to the JSP.

Under the covers, the library uses functionality from J2SE 5.0’s XPath classes to parse XML content and is capable of loading data from within a standalone servlet container or in the context of the Alfresco virtualisation server, via AVMRemote.

Binary downloads are available as a ZIP containing all the files needed, with the Java source also available.

To install this in an existing webapp, you will need to do the following:

Step 1 – Set up the webapp

Drop alfrescowww-xml.jar into your WEB-INF/lib folder and alf-xml.tld into WEB-INF. You will also need to reference the TLD from within the <web-app> element of web.xml as follows to ensure this gets picked up as appropriate.

<taglib>
<taglib-uri>http://www.alfresco.org/jsp/alf-xml</taglib-uri>
<taglib-location>/WEB-INF/alf-xml.tld</taglib-location>
</taglib>

If you are using JSTL you should also have a section like this, with c.tld and jstl.jar installed as above.

<taglib>
<taglib-uri>http://jakarta.apache.org/taglibs/core</taglib-uri>
<taglib-location>/WEB-INF/c.tld</taglib-location>
</taglib>

Step 2 – Set up the JSP

Add the namespace to your JSP page to allow it to reference the data functions, as follows.

<jsp:root version="1.2"
xmlns:jsp="http://java.sun.com/JSP/Page"
xmlns:c="http://java.sun.com/jsp/jstl/core"
xmlns:alfxml="http://www.alfresco.org/jsp/alf-xml">

This assumes you are using XML syntax within your JSPs and also that you are also using JSTL‘s core components on your page with these fully installed. If not, you will need to modify this code appropriately.

Step 3 -Get XML data

Assuming your webapp starts OK at this stage, you should now be able to use the alfxml:getXMLDocuments() function to pull in XML data from the JSP, using something like the following.

<c:forEach
   items="${alfxml:getXMLDocuments(pageContext, '/media/releases', false, '/alfdotcom:pressrelease', '/alfdotcom:pressrelease/alfdotcom:launch_date', 2)}"
var="pr">
<div class="list-item">
<h3>
<a href="/media/releases/${pr['$xml_file_name']}.jsp">
<c:out value="${pr['/alfdotcom:pressrelease/alfdotcom:title']}" />
</a></h3>
<p class="summary"><c:out value="${pr['/alfdotcom:pressrelease/alfdotcom:abstract']}" /></p>
</div>
</c:forEach>

In order, the arguments to the function are as follows: the implicit JSP pageContext object; the virtual directory path to search for XML assets under; a boolean value indicating whether or not the search should be deep (i.e. descend into subdirectories); an XPath condition which must match true (e.g. to only match documents with a alfdotcom:pressrelease root element); an XPath expression, the value of which is used to sort documents (use null or an empty string if no sorting is needed); and lastly an integer indicating the desired sort order (1=increasing, 2=decreasing).

Here I’ve used JSTL’s c:forEach element to iterate over the collection of items returned, but other mechanisms are obviously possible. The code above is a pretty simple example of what can be output using EL to fetch field values from the XML based on simple XPath expressions, but more complex expressions can obviously be built up. I’ll post more examples another time.

Repair web project web script

This is actually two small web scripts, which between them allow you to select an Alfresco web project and fix up the metadata on all form generated assets, including renditions. I wrote it to allow me to reassociate assets with their forms after using CIFS to do an export and import of some sites I’ve been working on.

The functionality is similar to that provided by Uzi’s Web Project Tools AMP which isn’t yet building against 2.2, but rather than being Java-based uses the JavaScript API against the AVM – which should remain stable over time.

At the moment the script iterates through the site directory structure looking for any XML item not associated with a web form. Then, if a form with a matching root tag is found associated with the web project then the appropriate aspects and properties are added to the node and any existing renditions.

Unlike with the Web Project Tools AMP existing form metadata cannot be removed or repaired, but I quite like the simpleness of this approach. Adding the ability to do this would perhaps be useful, but would complicate the UI and wasn’t required for my purposes. I might add this later, in addition to the ability to preview the changes.

Right now it’s recommended to ensure the current user’s sandbox is empty before executing the script, so that you can easily undo all changes should your data get munged. The script has been tested against a couple of web projects that I have access to but as it has not yet had widespread testing it should be used with caution!

Note, you need to have a sandbox for the web project you want to repair. If you do not then the site will not show up in the initial list.

To install the web script extract the contents of the ZIP file somewhere in your web script package hierarchy, either on the classpath or inside the Data Dictionary – org/alfresco/wcm works for me. Remember you’ll need to reload Alfresco or at least refresh the list of web scripts to get Alfresco to pick it up.

repair-web-project.zip

Comments welcome!

Update: Thanks to Nancy for pointing me at the Developer Tools area of the Content Community – the code is also now available there.