title: How can I merge two nodes in XML file using XSLT 1.0
body: <p>I have a text file being imported from an analytical instrument.  This text file is from an older machine and does not have options to do comma or tab delimited, it's basically fixed spacing.  When it's being processed for some rows it creates one node "a0" and for some rows it breaks it up into "a0", "a1", "a2", because there is a special character "~" and at the location of that character string is being broken up into multiple nodes.  I cannot get rid of this special character the machine uses it as an "approximation".  With help from this site I have been able to create a successful XSLT that works perfectly for when the entire row of raw data is just in "a0".  Now I have to account for examples when raw data row is split into "a0", "a1", "a2"..  Please see files/data below</p>
  
  <p><strong>Raw Data File (successful transformation, single node)</strong></p>
  
  <pre><code>07642110191055181NJL B2019     PURE_TIN  ALT201909130028               10-21-2019 0920 HRS                                         163120                        029Sn      00000099.5Pb      00000.0197Cu      00000.0104As      00000.0020Bi     &lt;00000.0000Zn      00000.0008Fe      00000.0057Ag      00000.4274Sb      00000.0114Ni      00000.0008Cd      00000.0001S       00000.0007Al      00000.0001Au     &lt;00000.0000P      &lt;00000.0001In      00000.0062Co     &lt;00000.0000Tl      00000.0002Be      0000000000Ce      0000000000Ga      0000000000Ge     &lt;00000.0001Hg      00000.0009Mg      0000000000Pd      0000000000Pt      0000000000Se      0000000000Te      0000000000Bg      00000099.502Customer                                SpecificatBDE                           
  </code></pre>
  
  <p><strong>XML Output (successful transformation, single node)</strong></p>
  
  <pre><code>&lt;dataRoot&gt;
  &lt;dataRow&gt;
      &lt;a0&gt;07642110191055181NJL B2019     PURE_TIN  ALT201909130028               10-21-2019 0920 HRS                                         163120                        029Sn      00000099.5Pb      00000.0197Cu      00000.0104As      00000.0020Bi     &amp;lt;00000.0000Zn      00000.0008Fe      00000.0057Ag      00000.4274Sb      00000.0114Ni      00000.0008Cd      00000.0001S       00000.0007Al      00000.0001Au     &amp;lt;00000.0000P      &amp;lt;00000.0001In      00000.0062Co     &amp;lt;00000.0000Tl      00000.0002Be      0000000000Ce      0000000000Ga      0000000000Ge     &amp;lt;00000.0001Hg      00000.0009Mg      0000000000Pd      0000000000Pt      0000000000Se      0000000000Te      0000000000Bg      00000099.502Customer                                SpecificatBDE                           &lt;/a0&gt;
    &lt;/dataRow&gt;
  &lt;/dataRoot&gt;
  </code></pre>
  
  <p><strong>Raw Data File (Multiple Nodes-unsuccessful transformation)</strong></p>
  
  <pre><code>06202110190918571NJL B2019     63SN      ALT201910210005                                                                                                         021Sn      00000055.4Pb      00000.0215Cu      00000.0320As      00000.0024Bi     ~0000043.68Zn      00000.0008Fe      00000.0016Ag      000000.841Sb      00000.0206Ni      00000.0012Cd     &lt;00000.0000S       00000.0005Al      00000.0001Au      00000.0001P       00000.0006In      00000.0032Co      00000.0035Tl      00000.0177Hg     &lt;00000.0000Pd     &lt;00000.0001Total   0000044.5802CUST ID                                 SPEC      BDE                           
  </code></pre>
  
  <p><strong>XML Output (Here you can see multiple nodes are created due to the "~" symbol)</strong></p>
  
  <pre><code>&lt;dataRoot&gt;
      &lt;dataRow&gt;
          &lt;a0&gt;06202110190918571NJL B2019     63SN      ALT201910210005                                                                                                         021Sn      00000055.4Pb      00000.0215Cu      00000.0320As      00000.0024Bi     &lt;/a0&gt;
          &lt;a1&gt;0000043.68Zn      00000.0008Fe      00000.0016Ag      000000.841Sb      00000.0206Ni      00000.0012Cd     &amp;lt;00000.0000S       00000.0005Al      00000.0001Au      00000.0001P       00000.0006In      00000.0032Co      00000.0035Tl      00000.0177Hg     &amp;lt;00000.0000Pd     &amp;lt;00000.0001Total   0000044.5802CUST ID                                 SPEC      BDE                           &lt;/a1&gt;
      &lt;/dataRow&gt;
  &lt;/dataRoot&gt;
  </code></pre>
  
  <p>The XSLT that I'm applying to the XML file is below... this works perfectly when there is only one node "a0" and all the data is in that node.  This doesn't work when XML has multiple nodes.  I need to add code into this XSLT first to check and see if there are multiple nodes in the XML file for each row, if that is true then combine the nodes into one string then proceed with the rest and if there is one node then proceed.</p>
  
  <pre><code>&lt;xsl:stylesheet version="1.0" 
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"&gt;
  &lt;xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/&gt;
  
  &lt;xsl:template match="/dataRoot"&gt;
      &lt;xsl:variable name="a0" select="dataRow[last()]/a0" /&gt;
      &lt;xsl:variable name="sAnalysisDT" select="substring($a0,5,6)" /&gt;
      &lt;xsl:variable name="dEnteredOn"&gt;
          &lt;xsl:call-template name="FormatDate"&gt;
              &lt;xsl:with-param name="DateTime" select="$sAnalysisDT" /&gt;
          &lt;/xsl:call-template&gt;
      &lt;/xsl:variable&gt;
      &lt;xsl:variable name="sSampleID" select="normalize-space(substring($a0, 41, 16))" /&gt;
      &lt;xsl:variable name="sEventCondition" select="normalize-space(substring($sSampleID, 1, 3))" /&gt;   
      &lt;xsl:variable name="sEvent"&gt;
          &lt;xsl:choose&gt;
              &lt;xsl:when test="$sEventCondition='ALT'"&gt;1&lt;/xsl:when&gt;
              &lt;xsl:otherwise&gt;2&lt;/xsl:otherwise&gt;
          &lt;/xsl:choose&gt;
      &lt;/xsl:variable&gt;
  
      &lt;xsl:variable name="common-nodes"&gt;
          &lt;EVENT&gt;&lt;xsl:value-of select="$sEvent"/&gt;&lt;/EVENT&gt;
          &lt;SAMPLE_ID&gt;&lt;xsl:value-of select="$sSampleID"/&gt;&lt;/SAMPLE_ID&gt;
          &lt;TEXT1&gt;&lt;xsl:value-of select="normalize-space(substring($a0, 129, 20))"/&gt;&lt;/TEXT1&gt;
          &lt;TEXT6&gt;&lt;xsl:value-of select="normalize-space(substring($a0, 31, 10))"/&gt;&lt;/TEXT6&gt;
          &lt;TEXT8&gt;&lt;xsl:value-of select="normalize-space(substring($a0, 71, 40))"/&gt;&lt;/TEXT8&gt;
          &lt;SUBMITTER&gt;OES Import&lt;/SUBMITTER&gt;
          &lt;OWNER&gt;ALT&lt;/OWNER&gt;
          &lt;ENTERED_ON&gt;&lt;xsl:value-of select="$dEnteredOn"/&gt;&lt;/ENTERED_ON&gt;
          &lt;ENTERED_BY&gt;OES Import&lt;/ENTERED_BY&gt;
          &lt;PROGRAM_CODE&gt;OES&lt;/PROGRAM_CODE&gt;
      &lt;/xsl:variable&gt;
      &lt;xsl:variable name="sDataString" select="translate(substring-before(substring($a0, 165), '02Cust'), '&amp;lt;', ' ')"/&gt;
  
      &lt;INBOUND&gt;
          &lt;xsl:call-template name="create-output"&gt;
              &lt;xsl:with-param name="sString" select="$sDataString"/&gt;
              &lt;xsl:with-param name="nodes" select="$common-nodes"/&gt;
          &lt;/xsl:call-template&gt;
      &lt;/INBOUND&gt;
  &lt;/xsl:template&gt;
  
  &lt;xsl:template name="create-output"&gt;
      &lt;xsl:param name="sString"/&gt;
      &lt;xsl:param name="nodes"/&gt;
      &lt;xsl:param name="len" select="18"/&gt;
      &lt;xsl:variable name="sAllString" select="substring($sString, 1, $len)"/&gt; 
      &lt;xsl:variable name="sMethod" select="substring($sAllString, 1, 2)"/&gt;
          &lt;xsl:variable name="sMethName"&gt;
              &lt;xsl:call-template name="ConvertMeName"&gt;
                  &lt;xsl:with-param name="sMeName" select="$sMethod" /&gt;
              &lt;/xsl:call-template&gt;
          &lt;/xsl:variable&gt; 
      &lt;xsl:variable name="sParameter" select="substring($sAllString, 1, 2)"/&gt;
      &lt;xsl:variable name="sParamName"&gt;
          &lt;xsl:call-template name="ConvertPaName"&gt;
              &lt;xsl:with-param name="sPaName" select="$sParameter" /&gt;
          &lt;/xsl:call-template&gt;
      &lt;/xsl:variable&gt;
  
      &lt;xsl:variable name="SResult" select="substring($sAllString, 9, 10)"/&gt;   
      &lt;!-- create node --&gt;
      &lt;INBOX_SAMPLE&gt;
          &lt;xsl:copy-of select="$nodes"/&gt;
          &lt;METHOD_NAME&gt;&lt;xsl:value-of select="$sMethName"/&gt;&lt;/METHOD_NAME&gt;
          &lt;PARAMETER_NAME&gt;&lt;xsl:value-of select="$sParamName"/&gt;&lt;/PARAMETER_NAME&gt;
          &lt;SRESULT&gt;&lt;xsl:value-of select="$SResult"/&gt;&lt;/SRESULT&gt;
      &lt;/INBOX_SAMPLE&gt;
      &lt;!-- recursive call --&gt;
      &lt;xsl:if test="string-length($sString) &gt; $len"&gt;
          &lt;xsl:call-template name="create-output"&gt;
              &lt;xsl:with-param name="sString" select="substring($sString, $len+1)"/&gt;
              &lt;xsl:with-param name="nodes" select="$nodes"/&gt;
          &lt;/xsl:call-template&gt;
      &lt;/xsl:if&gt;
  &lt;/xsl:template&gt;
  
  &lt;xsl:template name="ConvertMeName"&gt;
      &lt;xsl:param name="sMeName" /&gt;
      &lt;xsl:choose&gt;
          &lt;!-- Use section below to create any required MeName translations --&gt;
          &lt;xsl:when test="$sMeName='P '"&gt;P&lt;/xsl:when&gt;
          &lt;xsl:when test="$sMeName='Sn'"&gt;SN&lt;/xsl:when&gt;
          &lt;xsl:when test="$sMeName='Pb'"&gt;PB&lt;/xsl:when&gt;
          &lt;xsl:when test="$sMeName='As'"&gt;AS&lt;/xsl:when&gt;
          &lt;xsl:when test="$sMeName='Cu'"&gt;CU&lt;/xsl:when&gt;        
          &lt;xsl:when test="$sMeName='Bi'"&gt;BI&lt;/xsl:when&gt;        
          &lt;xsl:when test="$sMeName='Zn'"&gt;ZN&lt;/xsl:when&gt;
          &lt;xsl:when test="$sMeName='Fe'"&gt;FE&lt;/xsl:when&gt;
          &lt;xsl:when test="$sMeName='Ag'"&gt;AG&lt;/xsl:when&gt;
          &lt;xsl:when test="$sMeName='Sb'"&gt;SB&lt;/xsl:when&gt;
          &lt;xsl:when test="$sMeName='Ni'"&gt;NI&lt;/xsl:when&gt;    
          &lt;xsl:when test="$sMeName='Cd'"&gt;CD&lt;/xsl:when&gt;
          &lt;xsl:when test="$sMeName='Al'"&gt;AL&lt;/xsl:when&gt;
          &lt;xsl:when test="$sMeName='Au'"&gt;AU&lt;/xsl:when&gt;    
          &lt;xsl:when test="$sMeName='In'"&gt;IN&lt;/xsl:when&gt;        
          &lt;xsl:when test="$sMeName='S '"&gt;S&lt;/xsl:when&gt;
          &lt;xsl:when test="$sMeName='Zn'"&gt;ZN&lt;/xsl:when&gt;
          &lt;xsl:otherwise&gt;&lt;xsl:value-of select="$sMeName"/&gt;&lt;/xsl:otherwise&gt;
      &lt;/xsl:choose&gt;
  &lt;/xsl:template&gt;
  
  &lt;xsl:template name="ConvertPaName"&gt;
      &lt;xsl:param name="sPaName" /&gt;
      &lt;xsl:choose&gt;
          &lt;!-- Use section below to create any required PaName translations --&gt;
          &lt;xsl:when test="$sPaName='P'"&gt;P&lt;/xsl:when&gt;
          &lt;xsl:when test="$sPaName='Sn'"&gt;SN&lt;/xsl:when&gt;
          &lt;xsl:when test="$sPaName='Pb'"&gt;PB&lt;/xsl:when&gt;
          &lt;xsl:when test="$sPaName='As'"&gt;AS&lt;/xsl:when&gt;
          &lt;xsl:when test="$sPaName='Cu'"&gt;CU&lt;/xsl:when&gt;    
          &lt;xsl:when test="$sPaName='Bi'"&gt;BI&lt;/xsl:when&gt;    
          &lt;xsl:when test="$sPaName='Zn'"&gt;ZN&lt;/xsl:when&gt;    
          &lt;xsl:when test="$sPaName='Fe'"&gt;FE&lt;/xsl:when&gt;
          &lt;xsl:when test="$sPaName='Ag'"&gt;AG&lt;/xsl:when&gt;
          &lt;xsl:when test="$sPaName='Sb'"&gt;SB&lt;/xsl:when&gt;
          &lt;xsl:when test="$sPaName='Ni'"&gt;NI&lt;/xsl:when&gt;
          &lt;xsl:when test="$sPaName='Cd'"&gt;CD&lt;/xsl:when&gt;
          &lt;xsl:when test="$sPaName='Al'"&gt;AL&lt;/xsl:when&gt;    
          &lt;xsl:when test="$sPaName='Au'"&gt;AU&lt;/xsl:when&gt;    
          &lt;xsl:when test="$sPaName='In'"&gt;IN&lt;/xsl:when&gt;
          &lt;xsl:when test="$sPaName='S'"&gt;S&lt;/xsl:when&gt;  
          &lt;xsl:when test="$sPaName='Zn'"&gt;ZN&lt;/xsl:when&gt;        
          &lt;xsl:otherwise&gt;&lt;xsl:value-of select="$sPaName"/&gt;&lt;/xsl:otherwise&gt;
      &lt;/xsl:choose&gt;
  &lt;/xsl:template&gt;
  
  &lt;xsl:template name="FormatDate"&gt;
    &lt;xsl:param name="DateTime" /&gt;
    &lt;!-- extract the individual portions of the datetime from the position in the passed in parameter --&gt;
    &lt;xsl:variable name="year"&gt;
      &lt;xsl:value-of select="concat('20',normalize-space(substring($DateTime, 5, 2)))" /&gt;
    &lt;/xsl:variable&gt;
    &lt;xsl:variable name="month"&gt;
    &lt;xsl:value-of select="normalize-space(substring($DateTime, 3, 2))" /&gt;
    &lt;/xsl:variable&gt;
    &lt;xsl:variable name="day"&gt;
      &lt;xsl:value-of select="normalize-space(substring($DateTime, 1, 2))" /&gt;
    &lt;/xsl:variable&gt;
  
    &lt;!-- Construct new Date value that sql server will recognize 'YYYY-MON-DD hh:mm:ss' --&gt;
    &lt;xsl:value-of select="$year"/&gt;
    &lt;xsl:value-of select="'-'"/&gt;
    &lt;xsl:value-of select="$month"/&gt;
    &lt;xsl:value-of select="'-'"/&gt;
    &lt;xsl:value-of select="$day"/&gt;
  &lt;/xsl:template&gt;
  
  &lt;/xsl:stylesheet&gt;
  </code></pre>
  
  <p>Right now the XSLT works for the single node situation.  Thank you so much in advance for reading this entire question, it's lengthy but I wanted to provide all the details.</p>