Source XML (since I haven't bothered with a schema):<?xml version=1.0?><ContactDetails>  <Names>    <FullName>   Nicholas Example  </FullName>  <AltName context=Nickname>    Nick  </AltName>  <AltName context=Online>   oxinabox  </AltName>  </Names>  <Phones>    <Phone context=Mobile>04 1234 1234</Phone>  </Phones>  <Addresses>    <Address context=Semester>      Contrived Apartments      <number> 5 </number> <street>Some Rd</street>      <town>Newtown</town> <state>ST</state>    </Address>  </Addresses>  <Emails>    <Email context=Work>examplen@work.com</Email>    <Email context=Personal>nick99@ManMail.com</Email>  </Emails>  <Websites>    <Website>http://www.a2b3c4.com</Website>  </Websites>  <Banking>   <BankAccount context=Everyday       Name=Nicholas Example       BSB=123 123       AccountNumber=111 222 333 />  </Banking></ContactDetails>and here is the actual XSLT I would like a review of. It is supposed to turn the XML in to a human readable flat file (and does except for addresses which I am still working on):<?xml version=1.0 ?><xsl:stylesheet version=1.0     xmlns:xsl=http://www.w3.org/1999/XSL/Transform    xmlns:fn=http://www.w3.org/2005/xpath-functions    >    <xsl:output        method=text        omit-xml-declaration=yes        indent=no        media-type=text/plain/>   <xsl:strip-space elements=*/>    <xsl:template match=ContactDetails>        <xsl:apply-templates/>    </xsl:template>    <xsl:template match=Names>    <xsl:value-of select=FullName/>    <xsl:for-each select=AltName>             <xsl:text> AKA </xsl:text><xsl:value-of select=normalize-space(.)/>        </xsl:for-each>        <xsl:text>        </xsl:text>    </xsl:template>    <xsl:template match=//Phone>      <xsl:text>Ph (</xsl:text><xsl:value-of select=@context/> <xsl:text>): </xsl:text>        <xsl:value-of select = ./>    </xsl:template>     <xsl:template match=//Email>      <xsl:text>Email (</xsl:text><xsl:value-of select=@context/> <xsl:text>): </xsl:text>        <xsl:value-of select = ./>    </xsl:template>     <xsl:template match=//Website>      <xsl:text>Website: </xsl:text>        <xsl:value-of select = ./>    </xsl:template>     <xsl:template match=//Address><!--        <xsl:value-of select =./>        <xsl:for-each select=*>        <xsl:value-of select = ./>                <xsl:if test=fn:name(.)=town>                    <xsl:text>, </xsl:text>                </xsl:if>        </xsl:for-each>        -->    </xsl:template>     <xsl:template match=Banking><xsl:text>Bank Details:------------</xsl:text>         <xsl:for-each select=BankAccount>            <xsl:value-of select=@context/> <xsl:text> Account: </xsl:text>            <xsl:value-of select=@BSB/>-<xsl:value-of select=@AccountNumber/>        </xsl:for-each>    </xsl:template></xsl:stylesheet>
Making a flat file
xml;xslt
<xsl:output    method=text    omit-xml-declaration=yes    indent=no    media-type=text/plain/> Consider using XSLT 2.0, which can't hurt but could help if you need a XSLT 2.0 function in the future. Also note that you don't need omit-output-declaration since you're outputing text. Ditto for indent.<xsl:template match=ContactDetails>    <xsl:apply-templates/></xsl:template>This is the default template for every element, which means it's not needed.<xsl:template match=//Email>Why the //? It makes more sense without it, eg. match=Email. This applies to all your templates.    <xsl:text>Ph (</xsl:text><xsl:value-of select=@context/> <xsl:text>): </xsl:text>    <xsl:value-of select = ./>You're using xsl:text too much. This could become:Ph (<xsl:value-of select=@context/>): <xsl:value-of select = ./>Besides, I'm not sure context is a good choice for an attribute name. Context node already has a specific meaning in XSLT.