﻿<?xml version="1.0" encoding="UTF-8"?>
<!--Transform Open Contacts XML into Yahoo Mail Contacts CSV.

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 note the first column is Dummy. Yahoo's import function can not properly handle CSV in UTF8 format with BOM. 
The import function considers the first header is corrupted, ignores the first column, and will read the rest of the headers to match.

A CSV file exported by Yahoo is in UTF8 format without BOM, likely because of Unix's tradition of handling Unicode. However, in Windows world, 
UTF8 files traditionally have BOM, and MSXML does generate UTF8 output with BOM. MS Outlook can only handle CSV in ANSI, 
and treat UTF8 as ANSI.

I have reported this shortfall (I won't call it bug) to Yahoo, and I hope Yahoo will imporve the import functions 
properly for UTF8 with or without BOM. If in the future Yahoo does improve the handling of CSV in UTF8 format, you may then
need to remove the Dummy column.

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="/">


    <xsl:text>"Dummy","First","Middle","Last","Nickname","Email","Category","Distribution Lists","Messenger ID","Home","Work","Pager","Fax","Mobile","Other","Yahoo! Phone","Primary","Alternate Email 1","Alternate Email 2","Personal Website","Business Website","Title","Company","Work Address","Work City","Work State","Work ZIP","Work Country","Home Address","Home City","Home State","Home ZIP","Home Country","Birthday","Anniversary","Custom 1","Custom 2","Custom 3","Custom 4","Comments","Messenger ID1","Messenger ID2","Messenger ID3","Messenger ID4","Messenger ID5","Messenger ID6","Messenger ID7","Messenger ID8","Messenger ID9","Skype ID","IRC ID","ICQ ID","Google ID","MSN ID","AIM ID","QQ ID"</xsl:text>
    <xsl:text>&#13;&#10;</xsl:text>
    
    
    <xsl:for-each select="OpenContacts/Contacts/Contact">

      <xsl:text>&quot;</xsl:text>
      <xsl:text>D</xsl:text>
      <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>
      
      <xsl:text>&quot;</xsl:text>
      <xsl:value-of select="Sections/Section/Fields/Field[@Name='Nickname']/@Value"/>
      <xsl:text>&quot;,</xsl:text>

      <!--Email better later-->
      <xsl:text>&quot;</xsl:text>
      <xsl:value-of select="Sections/Section[@Name='Personal']/Fields/Field[@Name='Email']/@Value"/>
      <xsl:text>&quot;,</xsl:text>

      <!--Category, not used-->
      <xsl:text>,</xsl:text>

      <!--Not used, Distribution List-->
      <xsl:text>,</xsl:text>

      <!--Messenger ID-->
      <xsl:text>&quot;</xsl:text>
      <xsl:value-of select="Sections/Section[@Name='Personal']/Fields/Field[@Name='Yahoo']/@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>

      <!--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>

      <!--Pager-->
      <xsl:text>&quot;</xsl:text>
      <xsl:value-of select="Sections/Section[@Name='Personal']/Fields/Field[@Name='Pager']/@Value"/>
      <xsl:text>&quot;,</xsl:text>

      <!--FAX-->
      <xsl:text>&quot;</xsl:text>
      <xsl:value-of select="Sections/Section[@Name='Personal']/Fields/Field[@Name='Fax']/@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>

      <!--Ohter phone-->
      <xsl:text>&quot;</xsl:text>
      <xsl:value-of select="Sections/Section[@Name='Other']/Fields/Field[@Name='Pager']/@Phone"/>
      <xsl:text>&quot;,</xsl:text>

      <!--Yahoo Phone-->
      <xsl:text>&quot;</xsl:text>
      <xsl:value-of select="Sections/Section[@Name='Personal']/Fields/Field[@Name='Yahoo Phone']/@Value"/>
      <xsl:text>&quot;,</xsl:text>

      <!--Not used,Primary number. Or if aphone is in a section, then tell-->
      <xsl:text>,</xsl:text>

      <!--Alt. Email1-->
      <xsl:text>&quot;</xsl:text>
      <xsl:value-of select="Sections/Section[@Name='Personal']/Fields/Field[@Name='Email2']/@Value"/>
      <xsl:text>&quot;,</xsl:text>

      <!--Alt. Email2-->
      <xsl:text>&quot;</xsl:text>
      <xsl:value-of select="Sections/Section[@Name='Personal']/Fields/Field[@Name='Email3']/@Value"/>
      <xsl:text>&quot;,</xsl:text>

      <!--Personal Web-->
      <xsl:text>&quot;</xsl:text>
      <xsl:value-of select="Sections/Section[@Name='Personal']/Fields/Field[@Name='Web']/@Value"/>
      <xsl:text>&quot;,</xsl:text>

      <!--Business Web-->
      <xsl:text>&quot;</xsl:text>
      <xsl:value-of select="Sections/Section[@Name='Work']/Fields/Field[@Name='Web']/@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>

      <!--Company-->
      <xsl:text>&quot;</xsl:text>
      <xsl:value-of select="Sections/Section[@Name='Work']/Fields/Field[@Name='Company']/@Value"/>
      <xsl:text>&quot;,</xsl:text>

      <!--Work 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>
      
      <!--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-->
      <xsl:text>&quot;</xsl:text>
      <xsl:value-of select="Sections/Section[@Name='Work']/Fields/Field[@Name='Country']/@Value"/>
      <xsl:text>&quot;,</xsl:text>

      <!--Home 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>

      <!--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>

      <!--Birthday-->
      <xsl:text>&quot;</xsl:text>
      <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>

      <!--Anniversary-->
      <xsl:text>&quot;</xsl:text>
      <xsl:call-template name="FormatDate">
        <xsl:with-param name="Date"  select="Sections/Section[@Name='Personal']/Fields/Field[@Name='Anniversary']/@Value"/>
      </xsl:call-template>
      <xsl:text>&quot;,</xsl:text>

      <!--Custom 1,2,3,4-->
      <xsl:text>,</xsl:text>
      <xsl:text>,</xsl:text>
      <xsl:text>,</xsl:text>
      <xsl:text>,</xsl:text>

      <!--Comments-->
      <xsl:call-template name="display_csv_field">
        <xsl:with-param name="field" select="Notes"/>
      </xsl:call-template>
      <xsl:text>,</xsl:text>

      <!--Messenger ID 1..9-->
      <xsl:text>,</xsl:text>
      <xsl:text>,</xsl:text>
      <xsl:text>,</xsl:text>
      <xsl:text>,</xsl:text>
      <xsl:text>,</xsl:text>
      <xsl:text>,</xsl:text>
      <xsl:text>,</xsl:text>
      <xsl:text>,</xsl:text>
      <xsl:text>,</xsl:text>

      <!--Skype-->
      <xsl:text>&quot;</xsl:text>
      <xsl:value-of select="Sections/Section[@Name='Personal']/Fields/Field[@Name='Skype']/@Value"/>
      <xsl:text>&quot;,</xsl:text>

      <!--IRC-->
      <xsl:text>&quot;</xsl:text>
      <xsl:value-of select="Sections/Section[@Name='Personal']/Fields/Field[@Name='IRC']/@Value"/>
      <xsl:text>&quot;,</xsl:text>

      <!--ICQ-->
      <xsl:text>&quot;</xsl:text>
      <xsl:value-of select="Sections/Section[@Name='Personal']/Fields/Field[@Name='ICQ']/@Value"/>
      <xsl:text>&quot;,</xsl:text>

      <!--Google-->
      <xsl:text>&quot;</xsl:text>
      <xsl:value-of select="Sections/Section[@Name='Personal']/Fields/Field[@Name='Google']/@Value"/>
      <xsl:text>&quot;,</xsl:text>

      <!--MSN-->
      <xsl:text>&quot;</xsl:text>
      <xsl:value-of select="Sections/Section[@Name='Personal']/Fields/Field[@Name='MSN']/@Value"/>
      <xsl:text>&quot;,</xsl:text>

      <!--AIM-->
      <xsl:text>&quot;</xsl:text>
      <xsl:value-of select="Sections/Section[@Name='Personal']/Fields/Field[@Name='AIM']/@Value"/>
      <xsl:text>&quot;,</xsl:text>

      <!--QQ-->
      <xsl:text>&quot;</xsl:text>
      <xsl:value-of select="Sections/Section[@Name='Personal']/Fields/Field[@Name='QQ']/@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>


  <xsl:template name="FormatDate">
    <!-- expected 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>
