1

Please i want to know how i can merge two xml files into one xml file using xslt. I have these both xml files that i want to merge into an xml file as shown in the expected output.I want to include the each node Hn from the second file to the corresponding block with same number in the file 1.

file1:

<Test>
  <R1>
    <Th1>
        here are some instruction.
    </Th1>
  </R1>

  <R2>
    <Th2>
        here are some instruction.
    </Th2>
  </R2>

  <R3>
    <Th3>
        here are some instruction.
    </Th3>
  </R3>
</Test>

file 2:

<test1>
  <H1>
    here are some instruction.
  </H1>

  <H2>
    here are some instruction.
  </H2>

  <H3>
    here are some instruction.
  </H3>
</test1>    

and here is the expected output:

<test2>
  <R1>
    <H1>
        here are some instruction.
    </H1>
    <Th1>
        here are some instruction.
    </Th1>
  </R1>

  <R2>
    <H2>
        here are some instruction.
    </H2>
    <Th2>
        here are some instruction.
    </Th2>
  </R2>

  <R3>
    <H3>
        here are some instruction.
    </H3>
    <Th3>
        here are some instruction.
    </Th3>
  </R3>

</test2>

Thanks for your help.

2
  • Hello Franky, you have to make use of the document() function. Try setting up an XSLT and see how far you get. thank you, Peter Commented Sep 14, 2012 at 11:37
  • Hello peter, i'm not expert with xslt. I just started to work with xslt and i don't know more thing about it. But i will make some researches on google concerning that fucntion. Thanks already to give a trick. Commented Sep 14, 2012 at 11:53

1 Answer 1

2

I. This XSLT 1.0 transformation:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes"/>

 <xsl:variable name="vDigits" select="'0123456789'"/>
 <xsl:variable name="vDoc2" select="document('file:///c:/temp/delete/file2.xml')"/> 

 <xsl:template match="/*">
     <test2><xsl:apply-templates/></test2>
 </xsl:template>

 <xsl:template match="/*/*">
  <xsl:copy>
   <xsl:text>&#xA;</xsl:text>
   <xsl:copy-of select=
    "$vDoc2/*/*
      [translate(name(),translate(name(),$vDigits,''),'')
      =
       translate(name(current()),translate(name(current()),$vDigits,''),'')
      ]"/>
    <xsl:copy-of select="node()"/>
   </xsl:copy>
 </xsl:template>
</xsl:stylesheet>

When applied on the first XML document (file1.xml):

<Test>
  <R1>
    <Th1>
        here are some instruction.
    </Th1>
  </R1>

  <R2>
    <Th2>
        here are some instruction.
    </Th2>
  </R2>

  <R3>
    <Th3>
        here are some instruction.
    </Th3>
  </R3>
</Test>

and having the second XML document reside at c:\temp\delete\file2.xml:

<test1>
  <H1>
    here are some instruction.
  </H1>

  <H2>
    here are some instruction.
  </H2>

  <H3>
    here are some instruction.
  </H3>
</test1>

produces the wanted, correct result:

<test2>
  <R1>
<H1>
    here are some instruction.
  </H1>
    <Th1>
        here are some instruction.
    </Th1>
  </R1>

  <R2>
<H2>
    here are some instruction.
  </H2>
    <Th2>
        here are some instruction.
    </Th2>
  </R2>

  <R3>
<H3>
    here are some instruction.
  </H3>
    <Th3>
        here are some instruction.
    </Th3>
  </R3>
</test2>

Explanation:

Proper use of the "double-translate" method first demoed by Michael Kay.


II. XSLT 2.0 solution:

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes"/>

 <xsl:variable name="vDigits" select="'0123456789'"/>
 <xsl:variable name="vDoc2" select="document('file:///c:/temp/delete/file2.xml')"/> 

 <xsl:template match="/*">
     <test2><xsl:apply-templates/></test2>
 </xsl:template>

 <xsl:template match="/*/*">
  <xsl:if test="not(matches(name(), '^.+\d+$'))">
    <xsl:message terminate="yes">
     Element Name doesn't end with number: <xsl:sequence select="name()"/>
    </xsl:message>
  </xsl:if>
  <xsl:copy>
   <xsl:text>&#xA;</xsl:text>
   <xsl:copy-of select=
    "$vDoc2/*/*
      [replace(name(),'^.+(\d+)$', '$1')
      =
       replace(name(current()),'^.+(\d+)$', '$1')
      ]"/>
    <xsl:copy-of select="node()"/>
   </xsl:copy>
 </xsl:template>
</xsl:stylesheet>

Explanation:

Proper use of the standard XPath 2.0 functions matches() and replace()

Sign up to request clarification or add additional context in comments.

3 Comments

hello Dimitre, Thanks for this solution. It walks very well. But i want to know the purpose and the use of the variable name vDigits. Is there any possibility to get automatically the path for the file2.xml, so that i don't need always to store this file in c:\temp\delete\...? Thanks
@FrankyN., Yes, you can specify a global/external (child of xsl:stylesheet) xsl:param for this purpose. Such parameter can be set externally from the invoker of the XSLT transformation -- as this is implementation-dependent, you need to read the documentation of the specific XSLT processor you are using.
@FrankyN., The role of $vDigits -- it serves to find all the digits used in the element name. First we find all non-digits (in the inner translate()), then we strip-off all non-digits from the name -- in the outer translate. What remains is just all the digits that the name contains.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.