﻿<?xml version="1.0" encoding="UTF-8"?>
<!--Transform Open Contacts XML into MS Outlook CSV.

This file can be used for exporting contact info in Open Contacts.
You are welcome to modify this file for your own needs if you have skills of writing XSLT, 
or you may ask local IT professionals to modify the file. Please be aware of the following factors:

1. This file assumes the default mapping of exporting CSV in MS Outlook. If you change the default mapping,
you might need to modify this file as well.
2. Some legacy fields such as Telex has only null data.
3. The date format of Open Contacts is yyyy-mm-dd, and MS Outlook should be able to import date fields of such format
regardless of the default format of Windows (e.g. dd/mm/yyyy).  However, some services like Yahoo Mail Contacts might not
be so smart when importing date fields in ISO format. You might need to call FormatDate template to transform the date field for
ISO date format to desired format. Please check the XSLT codes commented below for Birthday.
4. The exported CSV file is encoded in UTF8. However, the import function of MS Outlook and other services may not be
able to take the advantage of UTF8 in order to support non-English characters in multiple languages. For example,
German names may not be properly imported in English Windows. So far I found Yahoo can handle CSV in UTF8 format.
5. The mapping is based on the default configuration of Open Contacts. If you changed the Section/Field combinations,
you might need to modify this file.

Author: Andy Wong
Date: 2007-09-18
-->
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="text" encoding="UTF-8" />

  <xsl:template match="/">


    <!--CSV Header-->
    <xsl:text>"Title","First Name","Middle Name","Last Name","Suffix","Company","Department","Job Title","Business Street","Business Street 2","Business Street 3","Business City","Business State","Business Postal Code","Business Country/Region","Home Street","Home Street 2","Home Street 3","Home City","Home State","Home Postal Code","Home Country/Region","Other Street","Other Street 2","Other Street 3","Other City","Other State","Other Postal Code","Other Country/Region","Assistant's Phone","Business Fax","Business Phone","Business Phone 2","Callback","Car Phone","Company Main Phone","Home Fax","Home Phone","Home Phone 2","ISDN","Mobile Phone","Other Fax","Other Phone","Pager","Primary Phone","Radio Phone","TTY/TDD Phone","Telex","Account","Anniversary","Assistant's Name","Billing Information","Birthday","Business Address PO Box","Categories","Children","Directory Server","E-mail Address","E-mail Type","E-mail Display Name","E-mail 2 Address","E-mail 2 Type","E-mail 2 Display Name","E-mail 3 Address","E-mail 3 Type","E-mail 3 Display Name","Gender","Government ID Number","Hobby","Home Address PO Box","Initials","Internet Free Busy","Keywords","Language","Location","Manager's Name","Mileage","Notes","Office Location","Organizational ID Number","Other Address PO Box","Priority","Private","Profession","Referred By","Sensitivity","Spouse","User 1","User 2","User 3","User 4","Web Page"</xsl:text>
    <xsl:text>&#13;&#10;</xsl:text>


    <xsl:for-each select="OpenContacts/Contacts/Contact">

      <xsl:text>&quot;</xsl:text>
      <xsl:value-of select="@Title"/>
      <xsl:text>&quot;,</xsl:text>

      <xsl:text>&quot;</xsl:text>
      <xsl:value-of select="@GivenName"/>
      <xsl:text>&quot;,</xsl:text>

      <xsl:text>&quot;</xsl:text>
      <xsl:value-of select="@MidName"/>
      <xsl:text>&quot;,</xsl:text>

      <xsl:text>&quot;</xsl:text>
      <xsl:value-of select="@Surname"/>
      <xsl:text>&quot;,</xsl:text>

      <!--Suffix-->
      <xsl:text>&quot;</xsl:text>
      <xsl:value-of select="Sections/Section[@Name='Personal']/Fields/Field[@Name='Suffix']/@Value"/>
      <xsl:text>&quot;,</xsl:text>

      <!--Company-->
      <xsl:text>&quot;</xsl:text>
      <xsl:value-of select="Sections/Section[@Name='Work']/Fields/Field[@Name='Company']/@Value"/>
      <xsl:text>&quot;,</xsl:text>

      <!--Department-->
      <xsl:text>&quot;</xsl:text>
      <xsl:value-of select="Sections/Section[@Name='Work']/Fields/Field[@Name='Department']/@Value"/>
      <xsl:text>&quot;,</xsl:text>

      <!--Job Title-->
      <xsl:text>&quot;</xsl:text>
      <xsl:value-of select="Sections/Section[@Name='Work']/Fields/Field[@Name='Title']/@Value"/>
      <xsl:text>&quot;,</xsl:text>

      <!--Work Street address. Map to either OC Street or Address-->
      <xsl:choose>

        <xsl:when test="Sections/Section[@Name='Work']/Fields/Field[@Name='Address']/@Value">
          <xsl:call-template name="display_csv_field">
            <xsl:with-param name="field"  select="Sections/Section[@Name='Work']/Fields/Field[@Name='Address']/@Value"/>
          </xsl:call-template>
        </xsl:when>
        <xsl:otherwise>
          <xsl:call-template name="display_csv_field">
            <xsl:with-param name="field"  select="Sections/Section[@Name='Work']/Fields/Field[@Name='Street']/@Value"/>
          </xsl:call-template>
        </xsl:otherwise>
      </xsl:choose>
      <xsl:text>,</xsl:text>

      <!--Street2,3. Generally not used in OC-->
      <xsl:text>,,</xsl:text>

      <!--W City-->
      <xsl:text>&quot;</xsl:text>
      <xsl:value-of select="Sections/Section[@Name='Work']/Fields/Field[@Name='City']/@Value"/>
      <xsl:text>&quot;,</xsl:text>
      <!--W State-->
      <xsl:text>&quot;</xsl:text>
      <xsl:value-of select="Sections/Section[@Name='Work']/Fields/Field[@Name='State']/@Value"/>
      <xsl:text>&quot;,</xsl:text>
      <!--W Zip-->
      <xsl:text>&quot;</xsl:text>
      <xsl:value-of select="Sections/Section[@Name='Work']/Fields/Field[@Name='Postcode']/@Value"/>
      <xsl:text>&quot;,</xsl:text>
      <!--W Country, but both Outlook 2003 and Yahoo Mail Contacts do not import country? -->
      <xsl:text>&quot;</xsl:text>
      <xsl:value-of select="Sections/Section[@Name='Work']/Fields/Field[@Name='Country']/@Value"/>
      <xsl:text>&quot;,</xsl:text>


      <!--Home street address-->
      <xsl:choose>

        <xsl:when test="Sections/Section[@Name='Personal']/Fields/Field[@Name='Address']/@Value">
          <xsl:call-template name="display_csv_field">
            <xsl:with-param name="field"  select="Sections/Section[@Name='Personal']/Fields/Field[@Name='Address']/@Value"/>
          </xsl:call-template>
        </xsl:when>
        <xsl:otherwise>
          <xsl:call-template name="display_csv_field">
            <xsl:with-param name="field"  select="Sections/Section[@Name='Personal']/Fields/Field[@Name='Street']/@Value"/>
          </xsl:call-template>
        </xsl:otherwise>
      </xsl:choose>
      <xsl:text>,</xsl:text>

      <!--Street2,3-->
      <xsl:text>,,</xsl:text>

      <!--H City-->
      <xsl:text>&quot;</xsl:text>
      <xsl:value-of select="Sections/Section[@Name='Personal']/Fields/Field[@Name='City']/@Value"/>
      <xsl:text>&quot;,</xsl:text>
      <!--H State-->
      <xsl:text>&quot;</xsl:text>
      <xsl:value-of select="Sections/Section[@Name='Personal']/Fields/Field[@Name='State']/@Value"/>
      <xsl:text>&quot;,</xsl:text>
      <!--H Zip-->
      <xsl:text>&quot;</xsl:text>
      <xsl:value-of select="Sections/Section[@Name='Personal']/Fields/Field[@Name='Postcode']/@Value"/>
      <xsl:text>&quot;,</xsl:text>
      <!--H Country-->
      <xsl:text>&quot;</xsl:text>
      <xsl:value-of select="Sections/Section[@Name='Personal']/Fields/Field[@Name='Country']/@Value"/>
      <xsl:text>&quot;,</xsl:text>

      <!--Other street address-->
      <xsl:choose>

        <xsl:when test="Sections/Section[@Name='Other']/Fields/Field[@Name='Address']/@Value">
          <xsl:call-template name="display_csv_field">
            <xsl:with-param name="field"  select="Sections/Section[@Name='Other']/Fields/Field[@Name='Address']/@Value"/>
          </xsl:call-template>

        </xsl:when>
        <xsl:otherwise>
          <xsl:call-template name="display_csv_field">
            <xsl:with-param name="field"  select="Sections/Section[@Name='Other']/Fields/Field[@Name='Street']/@Value"/>
          </xsl:call-template>
        </xsl:otherwise>
      </xsl:choose>
      <xsl:text>,</xsl:text>

      <!--Street2,3-->
      <xsl:text>,,</xsl:text>

      <xsl:text>&quot;</xsl:text>
      <xsl:value-of select="Sections/Section[@Name='Other']/Fields/Field[@Name='City']/@Value"/>
      <xsl:text>&quot;,</xsl:text>
      <xsl:text>&quot;</xsl:text>
      <xsl:value-of select="Sections/Section[@Name='Other']/Fields/Field[@Name='State']/@Value"/>
      <xsl:text>&quot;,</xsl:text>
      <xsl:text>&quot;</xsl:text>
      <xsl:value-of select="Sections/Section[@Name='Other']/Fields/Field[@Name='Postcode']/@Value"/>
      <xsl:text>&quot;,</xsl:text>
      <xsl:text>&quot;</xsl:text>
      <xsl:value-of select="Sections/Section[@Name='Other']/Fields/Field[@Name='Country']/@Value"/>
      <xsl:text>&quot;,</xsl:text>

      <!--Assistant phone-->
      <xsl:text>&quot;</xsl:text>
      <xsl:value-of select="Sections/Section[@Name='Work']/Fields/Field[@Name='Assistant Phone']/@Value"/>
      <xsl:text>&quot;,</xsl:text>

      <!--Work fax-->
      <xsl:text>&quot;</xsl:text>
      <xsl:value-of select="Sections/Section[@Name='Work']/Fields/Field[@Name='Fax']/@Value"/>
      <xsl:text>&quot;,</xsl:text>

      <!--Work phone-->
      <xsl:text>&quot;</xsl:text>
      <xsl:value-of select="Sections/Section[@Name='Work']/Fields/Field[@Name='Phone']/@Value"/>
      <xsl:text>&quot;,</xsl:text>

      <!--Work phone2-->
      <xsl:text>&quot;</xsl:text>
      <xsl:value-of select="Sections/Section[@Name='Work']/Fields/Field[@Name='Phone2']/@Value"/>
      <xsl:text>&quot;,</xsl:text>

      <!--Callback-->
      <xsl:text>&quot;</xsl:text>
      <xsl:value-of select="Sections/Section[@Name='Work']/Fields/Field[@Name='Callback']/@Value"/>
      <xsl:text>&quot;,</xsl:text>

      <!--Car phone. Who's still using car phone?-->
      <xsl:text>&quot;</xsl:text>
      <xsl:value-of select="Sections/Section[@Name='Work']/Fields/Field[@Name='Car Phone']/@Value"/>
      <xsl:text>&quot;,</xsl:text>

      <!--Company Main Phone-->
      <xsl:text>&quot;</xsl:text>
      <xsl:value-of select="Sections/Section[@Name='Work']/Fields/Field[@Name='Primary Phone']/@Value"/>
      <xsl:text>&quot;,</xsl:text>

      <!--Home Fax-->
      <xsl:text>&quot;</xsl:text>
      <xsl:value-of select="Sections/Section[@Name='Personal']/Fields/Field[@Name='Fax']/@Value"/>
      <xsl:text>&quot;,</xsl:text>

      <!--Home phone-->
      <xsl:text>&quot;</xsl:text>
      <xsl:value-of select="Sections/Section[@Name='Personal']/Fields/Field[@Name='Phone']/@Value"/>
      <xsl:text>&quot;,</xsl:text>

      <!--Home phone2-->
      <xsl:text>&quot;</xsl:text>
      <xsl:value-of select="Sections/Section[@Name='Personal']/Fields/Field[@Name='Phone2']/@Value"/>
      <xsl:text>&quot;,</xsl:text>

      <!--ISDN, Is anyone using it?-->
      <xsl:text>&quot;</xsl:text>
      <xsl:value-of select="Sections/Section[@Name='Personal']/Fields/Field[@Name='ISDN']/@Value"/>
      <xsl:text>&quot;,</xsl:text>

      <!--Mobile-->
      <xsl:text>&quot;</xsl:text>
      <xsl:value-of select="Sections/Section[@Name='Personal']/Fields/Field[@Name='Mobile']/@Value"/>
      <xsl:text>&quot;,</xsl:text>

      <!--Other fax-->
      <xsl:text>&quot;</xsl:text>
      <xsl:value-of select="Sections/Section[@Name='Other']/Fields/Field[@Name='fax']/@Value"/>
      <xsl:text>&quot;,</xsl:text>

      <!--Other phone-->
      <xsl:text>&quot;</xsl:text>
      <xsl:value-of select="Sections/Section[@Name='Other']/Fields/Field[@Name='Phone']/@Value"/>
      <xsl:text>&quot;,</xsl:text>

      <!--Pager-->
      <xsl:text>&quot;</xsl:text>
      <xsl:value-of select="Sections/Section[@Name='Personal']/Fields/Field[@Name='Pager']/@Value"/>
      <xsl:text>&quot;,</xsl:text>

      <!--Primary phone-->
      <xsl:text>&quot;</xsl:text>
      <xsl:value-of select="Sections/Section[@Name='Personal']/Fields/Field[@Name='Primary Phone']/@Value"/>
      <xsl:text>&quot;,</xsl:text>

      <!--Radio phone-->
      <xsl:text>&quot;</xsl:text>
      <xsl:value-of select="Sections/Section[@Name='Personal']/Fields/Field[@Name='Radio Phone']/@Value"/>
      <xsl:text>&quot;,</xsl:text>

      <!--TTY-->
      <xsl:text>&quot;</xsl:text>
      <xsl:value-of select="Sections/Section[@Name='Personal']/Fields/Field[@Name='TTY']/@Value"/>
      <xsl:text>&quot;,</xsl:text>

      <!--Telex. Legacy. US had stopped the service-->
      <xsl:text>,</xsl:text>

      <!--Account-->
      <xsl:text>&quot;</xsl:text>
      <xsl:value-of select="Sections/Section[@Name='Work']/Fields/Field[@Name='Account']/@Value"/>
      <xsl:text>&quot;,</xsl:text>

      <!--Anniversary. Outlook can handle ISO date format, and others might not-->
      <xsl:text>&quot;</xsl:text>
      <xsl:value-of select="Sections/Section[@Name='Personal']/Fields/Field[@Name='Anniversary']/@Value"/>
      <xsl:text>&quot;,</xsl:text>

      <!--Assistant-->
      <xsl:text>&quot;</xsl:text>
      <xsl:value-of select="Sections/Section[@Name='Work']/Fields/Field[@Name='Assistant']/@Value"/>
      <xsl:text>&quot;,</xsl:text>

      <!--Billing-->
      <xsl:text>&quot;</xsl:text>
      <xsl:value-of select="Sections/Section[@Name='Work']/Fields/Field[@Name='Billing']/@Value"/>
      <xsl:text>&quot;,</xsl:text>

      <!--Birthday. MS Outlook can handle ISO date format. For other services like Yahoo Mail, 
      you may need to call the following, and do it for anniversary as well:
      <xsl:call-template name="FormatDate">
        <xsl:with-param name="Date"  select="Sections/Section[@Name='Personal']/Fields/Field[@Name='Birthday']/@Value"/>
      </xsl:call-template>     
      -->
      <xsl:text>&quot;</xsl:text>
      <xsl:value-of select="Sections/Section[@Name='Personal']/Fields/Field[@Name='Birthday']/@Value"/>
      <xsl:text>&quot;,</xsl:text>

      <!--Business PO Box-->
      <xsl:text>&quot;</xsl:text>
      <xsl:value-of select="Sections/Section[@Name='Work']/Fields/Field[@Name='PO Box']/@Value"/>
      <xsl:text>&quot;,</xsl:text>

      <!--Categories. Shall I map OC categories into outlook categories?-->
      <xsl:text>,</xsl:text>

      <!--Children-->
      <xsl:text>&quot;</xsl:text>
      <xsl:value-of select="Sections/Section[@Name='Personal']/Fields/Field[@Name='Children']/@Value"/>
      <xsl:text>&quot;,</xsl:text>

      <!--Directory Svr-->
      <xsl:text>&quot;</xsl:text>
      <xsl:value-of select="Sections/Section[@Name='Work']/Fields/Field[@Name='Directory Server']/@Value"/>
      <xsl:text>&quot;,</xsl:text>

      <!--Email-->
      <xsl:text>&quot;</xsl:text>
      <xsl:value-of select="Sections/Section[@Name='Personal']/Fields/Field[@Name='Email']/@Value"/>
      <xsl:text>&quot;,</xsl:text>
      <xsl:text>,</xsl:text>
      <xsl:text>,</xsl:text>

      <!--Email2-->
      <xsl:text>&quot;</xsl:text>
      <xsl:value-of select="Sections/Section[@Name='Personal']/Fields/Field[@Name='Email2']/@Value"/>
      <xsl:text>&quot;,</xsl:text>
      <xsl:text>,</xsl:text>
      <xsl:text>,</xsl:text>

      <!--Email3-->
      <xsl:text>&quot;</xsl:text>
      <xsl:value-of select="Sections/Section[@Name='Personal']/Fields/Field[@Name='Email3']/@Value"/>
      <xsl:text>&quot;,</xsl:text>
      <xsl:text>,</xsl:text>
      <xsl:text>,</xsl:text>

      <!--Gender, Gender is not in Outlook UI?-->
      <xsl:text>,</xsl:text>

      <!--Government ID-->
      <xsl:text>&quot;</xsl:text>
      <xsl:value-of select="Sections/Section[@Name='Personal']/Fields/Field[@Name='Government ID']/@Value"/>
      <xsl:text>&quot;,</xsl:text>

      <!--Hobby-->
      <xsl:text>&quot;</xsl:text>
      <xsl:value-of select="Sections/Section[@Name='Personal']/Fields/Field[@Name='Hobby']/@Value"/>
      <xsl:text>&quot;,</xsl:text>

      <!--Home PO Box-->
      <xsl:text>&quot;</xsl:text>
      <xsl:value-of select="Sections/Section[@Name='Personal']/Fields/Field[@Name='PO Box']/@Value"/>
      <xsl:text>&quot;,</xsl:text>

      <!--Initials,	Internet Free Busy,	Keywords,	Language-->
      <xsl:text>,,,,</xsl:text>

      <!--Location-->
      <xsl:text>&quot;</xsl:text>
      <xsl:value-of select="Sections/Section[@Name='Work']/Fields/Field[@Name='Location']/@Value"/>
      <xsl:text>&quot;,</xsl:text>

      <!--Manager-->
      <xsl:text>&quot;</xsl:text>
      <xsl:value-of select="Sections/Section[@Name='Work']/Fields/Field[@Name='Manager']/@Value"/>
      <xsl:text>&quot;,</xsl:text>

      <!--Mileage-->
      <xsl:text>,</xsl:text>

      <!--Notes-->
      <xsl:call-template name="display_csv_field">
        <xsl:with-param name="field" select="Notes"/>
      </xsl:call-template>
      <xsl:text>,</xsl:text>

      <!--Location-->
      <xsl:text>&quot;</xsl:text>
      <xsl:value-of select="Sections/Section[@Name='Work']/Fields/Field[@Name='Location']/@Value"/>
      <xsl:text>&quot;,</xsl:text>

      <!--Org ID-->
      <xsl:text>&quot;</xsl:text>
      <xsl:value-of select="Sections/Section[@Name='Work']/Fields/Field[@Name='Org ID']/@Value"/>
      <xsl:text>&quot;,</xsl:text>

      <!--Other PO Box-->
      <xsl:text>&quot;</xsl:text>
      <xsl:value-of select="Sections/Section[@Name='Other']/Fields/Field[@Name='PO Box']/@Value"/>
      <xsl:text>&quot;,</xsl:text>

      <!--Priority, Private-->
      <xsl:text>,,</xsl:text>

      <!--Profession-->
      <xsl:text>&quot;</xsl:text>
      <xsl:value-of select="Sections/Section[@Name='Work']/Fields/Field[@Name='Profession']/@Value"/>
      <xsl:text>&quot;,</xsl:text>


      <!--Referred By-->
      <xsl:text>&quot;</xsl:text>
      <xsl:value-of select="Sections/Section[@Name='Work']/Fields/Field[@Name='Referred By']/@Value"/>
      <xsl:text>&quot;,</xsl:text>

      <!--Sensitivity-->
      <xsl:text>,</xsl:text>

      <!--Spouse-->
      <xsl:text>&quot;</xsl:text>
      <xsl:value-of select="Sections/Section[@Name='Personal']/Fields/Field[@Name='Spouse']/@Value"/>
      <xsl:text>&quot;,</xsl:text>

      <!--User1,2,3,4-->
      <xsl:text>,,,,</xsl:text>

      <!--Web. Outlook allow only one web page link, and it is Business Home Page-->
      <xsl:text>&quot;</xsl:text>
      <xsl:value-of select="Sections/Section[@Name='Work']/Fields/Field[@Name='Web']/@Value"/>
      <xsl:text>&quot;</xsl:text>

      <xsl:text>&#13;&#10;</xsl:text>

    </xsl:for-each>
  </xsl:template>
  
  
  <!--This template will quote field value, and escape quotes in the field value-->
  <xsl:template name="display_csv_field">
    <xsl:param name="field"/>

    <xsl:variable name="linefeed">
      <xsl:text>&#10;</xsl:text>
    </xsl:variable>

    <xsl:choose>

      <xsl:when test="contains( $field, '&quot;' )">
        <!-- Field contains a quote. We must enclose this field in quotes,
           and we must escape each of the quotes in the field value.
      -->
        <xsl:text>&quot;</xsl:text>

        <xsl:call-template name="escape_quotes">
          <xsl:with-param name="string" select="$field" />
        </xsl:call-template>

        <xsl:text>&quot;</xsl:text>
      </xsl:when>


      <xsl:when test="contains( $field, ',' ) or
                    contains( $field, $linefeed )" >
        <!-- Field contains a comma and/or a linefeed.
           We must enclose this field in quotes.
      -->
        <xsl:text>&quot;</xsl:text>
        <xsl:value-of select="$field" />
        <xsl:text>&quot;</xsl:text>
      </xsl:when>


      <xsl:otherwise>
        <!-- No need to enclose this field in quotes.
      -->
        <xsl:value-of select="$field" />
      </xsl:otherwise>

    </xsl:choose>
  </xsl:template>

  <xsl:template name="escape_quotes">
    <xsl:param name="string" />

    <xsl:value-of select="substring-before( $string, '&quot;' )" />
    <xsl:text>""</xsl:text>

    <xsl:variable name="substring_after_first_quote"
                  select="substring-after( $string, '&quot;' )" />

    <xsl:choose>

      <xsl:when test="not( contains( $substring_after_first_quote,'&quot;' ) )">
        <xsl:value-of select="$substring_after_first_quote" />
      </xsl:when>

      <xsl:otherwise>
        <!-- The substring after the first quote contains a quote.
           So, call recursively to escape the quotes in the substring after the first quote.
      -->

        <xsl:call-template name="escape_quotes">
          <xsl:with-param name="string" select="$substring_after_first_quote"/>
        </xsl:call-template>
      </xsl:otherwise>

    </xsl:choose>

  </xsl:template>
  
  
  <!--Convert ISO date format to other format-->
  <xsl:template name="FormatDate">
    <!-- Expect date format 1998-11-23-->
    <xsl:param name="Date" />
    <!-- new date format 23/11/1998 -->
    <xsl:variable name="year">
      <xsl:value-of select="substring-before($Date,'-')" />
    </xsl:variable>
    <xsl:variable name="monthday">
      <xsl:value-of select="substring-after($Date,'-')" />
    </xsl:variable>
    <xsl:variable name="month">
      <xsl:value-of select="substring-before($monthday,'-')" />
    </xsl:variable>
    <xsl:variable name="day">
      <xsl:value-of select="substring-after($monthday,'-')" />
    </xsl:variable>

    <xsl:value-of select="$month"/>
    <xsl:text>/</xsl:text>
    <xsl:value-of select="$day"/>
    <xsl:text>/</xsl:text>
    <xsl:value-of select="$year"/>
  </xsl:template>

</xsl:stylesheet>
