When I run the following XSLT with xsltproc, I get your desired output (with one exception, there's an extra blank column at the end).
Much thanks to @Daniel_Haley for their solution to the general problem of printing the node path (please go vote that answer up if you like this).
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" />
<xsl:strip-space elements="*" />
<xsl:variable name="delim">;</xsl:variable>
<xsl:template match="/">
<!-- Recurse document for header -->
<xsl:copy>
<xsl:apply-templates select="node()" mode="header"/>
</xsl:copy>
<!-- Linebreak after last column in header -->
<xsl:text>
</xsl:text>
<!-- Recurse document for values -->
<xsl:copy>
<xsl:apply-templates select="node()" />
</xsl:copy>
<!-- Linebreak after last column in row -->
<xsl:text>
</xsl:text>
</xsl:template>
<xsl:template match="text()">
<xsl:copy-of select="." />
<xsl:value-of select="$delim"/>
</xsl:template>
<!-- https://stackoverflow.com/a/10112579/246801 -->
<xsl:template match="text()" mode="header">
<xsl:for-each select="ancestor::*">
<xsl:choose>
<!-- avoid beginning slash (at root) -->
<xsl:when test="position() = 1">
<xsl:value-of select="local-name()" />
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="concat('/',local-name())" />
</xsl:otherwise>
</xsl:choose>
<xsl:if test="(preceding-sibling::*|following-sibling::*)[local-name()=local-name(current())]">
<xsl:value-of select="concat('[',count(preceding-sibling::*[local-name()=local-name(current())])+1,']')" />
</xsl:if>
</xsl:for-each>
<xsl:value-of select="$delim"/>
<!-- <xsl:apply-templates select="node()" /> -->
</xsl:template>
</xsl:stylesheet>
tXML/Header/Source |
tXML/Header/User_ID |
tXML/Header/Message_Type |
tXML/Header/Company_ID |
tXML/Header/Msg_Locale |
tXML/Header/Version |
tXML/Message/Ship/ShipSummary/ComName |
tXML/Message/Ship/ShipSummary/FacName |
|
XPTO |
127 |
Ship |
105 |
English (United States) |
2017 |
XPTO 123 |
6 |
|