0

I've searched for the answer to this and frankly, I came up with so many possible answers that I was overwhelmed and so I'm still not sure how to proceed.

I've got two XML files that I would like to merge together and then sort based on three separate criteria.

Each file is, of course, in the same structure:

<root>
    <item>
        <number>1</number>
        <name>Name</name>
        <time>6h</time>
        <internal>NAME_01</internal>
        <flag>0</flag>
    </item>
</root>

I'm simply trying to merge the two files together and then sort. The sorting would need to be done in such an order:

  • Flag (This can be a 0 or a 1. 0 would come first.)
  • Number (Simple digit from 1 to 20. Would be sorted lowest first.)
  • Name (Simple alphabetization.)

I've seen many of the suggestions for this use XSLT which I know exactly nothing about. I'm not opposed to using it provided I'm given some instructions on how to go about implementing it. It doesn't have to be XSLT, though. I'm open to any option, simplicity would be key. Free applications (downloadable or web based) that can do this for me would be my holy grail.

An example of acceptable sorting would be:

<root>
    <item>
        <number>1</number>
        <name>Apple</name>
        <time>6h</time>
        <internal>FRUIT_APPLE_01</internal>
        <flag>0</flag>
    </item>
    <item>
        <number>1</number>
        <name>Banana</name>
        <time>2h</time>
        <internal>FRUIT_BANANA_01</internal>
        <flag>0</flag>
    </item>
    <item>
        <number>4</number>
        <name>Cabbage</name>
        <time>1h 15m</time>
        <internal>VEGETABLE_CABBAGE_02</internal>
        <flag>0</flag>
    </item>
    <item>
        <number>4</number>
        <name>Cucumber</name>
        <time>25m</time>
        <internal>FRUIT_CUCUMBER_01</internal>
        <flag>0</flag>
    </item>
    <item>
        <number>12</number>
        <name>Avocado</name>
        <time>12h</time>
        <internal>FRUIT_AVOCADO_03</internal>
        <flag>0</flag>
    </item>
    <item>
        <number>3</number>
        <name>Cat</name>
        <time>6h</time>
        <internal>MAMMAL_01</internal>
        <flag>1</flag>
    </item>
    <item>
        <number>8</number>
        <name>Iguana</name>
        <time>1h</time>
        <internal>REPTILE_04</internal>
        <flag>1</flag>
    </item>
</root>

Please let me know if I can clarify anything.

Many thanks.

Darxide
  • 13
  • 2

1 Answers1

1

Assuming you don't have duplicates in your files, this is not actually that complicated.

As you are not transforming the item elements at all, you start off by using the identity template

   <xsl:template match="@*|node()">
      <xsl:copy>
         <xsl:apply-templates select="@*|node()"/>
      </xsl:copy>
   </xsl:template>

Then, you only need to write a template to match the root element (of the first XML document), because you will be changing it by adding and re-ordering its child nodes.

In terms of merging it, just write an xsl:apply-templates to select the item elements of the current root element, and the item elements in the second XML file. This can be used in conjunction with xsl:sort instructions.

     <xsl:apply-templates select="item|document($mergeFile)/root/item">
        <xsl:sort select="flag" />
        <xsl:sort select="number" data-type="number" />
        <xsl:sort select="name" />
     </xsl:apply-templates>

Note the use of the document function to read the second XML file. In this case $mergeFile is a parameter set to the location of the second file you wish to merge with the first file currently being acted on by the XML.

And that's it! Try this XSLT

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
   <xsl:output method="xml" indent="yes"/>
   <xsl:param name="mergeFile" select="'Test2.xml'" />

   <xsl:template match="/*">
      <xsl:copy>
         <xsl:apply-templates select="item|document($mergeFile)/root/item">
            <xsl:sort select="flag" />
            <xsl:sort select="number" data-type="number" />
            <xsl:sort select="name" />
         </xsl:apply-templates>
      </xsl:copy>
   </xsl:template>

   <xsl:template match="@*|node()">
      <xsl:copy>
         <xsl:apply-templates select="@*|node()"/>
      </xsl:copy>
   </xsl:template>
</xsl:stylesheet>
Tim C
  • 70,053
  • 14
  • 74
  • 93
  • First, thanks for responding to me instead of downvoting and moving on like others seem to have done. The downvote trolls that are all over stackoverflow are one reasons I am hesitant to post here. Second, can you explain how I would go about executing the above script? I've found ways to do it but they seem only to work with one file. I'm not sure how to pass along the second file. – Darxide Feb 16 '14 at 20:06
  • There are many ways to execute the above script, depending on what platform you are using. C#, php, Java, JavaScript, etc. Although the process with will require you to apply the XSLT to a single file initially, the "document" function allows it to access another. You don't actually pass the second file itself, but you pass the file name (possibly with the full file path it is sits in another directory). So, its best to look up how to pass a parameter to XSLT for the method you are using. – Tim C Feb 16 '14 at 20:53
  • Here's an example of passing parameters in C#, for example. http://stackoverflow.com/questions/1521064/passing-parameters-to-xslt-stylesheet-via-net – Tim C Feb 16 '14 at 20:55