pankaj_ar
pankaj_ar

Reputation: 765

Merge 2 xml files using XSLT in unix

I have 2 XML files as shown below:

File1.xml

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<Schedule name="myOffice">
  <taskItem taskId="1" startDate="2013-01-01" stopDate="2037-12-31">
    <measurements>
      <measurement>USD</measurement>
    </measurements>
    <timings>
      <period day="0" duration="0" hour="0" interval="28" minutes="0"/>
    </timings>
  </taskItem>
  <taskItem taskId="2" startDate="2013-01-01" stopDate="2037-12-31">
    <measurements>
      <measurement>Rupee</measurement>
    </measurements>
    <timings>
      <period day="0" duration="0" hour="0" interval="15" minutes="0"/>
    </timings>
  </taskItem>
</Schedule>

File2.xml

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<Schedule name="myOffice">
  <taskItem taskId="1" startDate="2015-12-01" stopDate="2037-12-31">
    <measurements>
      <measurement>Rupee</measurement>
    </measurements>
    <timings>
      <period day="5" duration="10" hour="0" interval="20" minutes="0"/>
    </timings>
  </taskItem>
</Schedule>

I am using XSLT to get the following output:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<Schedule name="myOffice">
  <taskItem taskId="1" startDate="2013-01-01" stopDate="2037-12-31">
    <measurements>
      <measurement>USD</measurement>
    </measurements>
    <timings>
      <period day="0" duration="0" hour="0" interval="28" minutes="0"/>
    </timings>
  </taskItem>
  <taskItem taskId="2" startDate="2013-01-01" stopDate="2037-12-31">
    <measurements>
      <measurement>Rupee</measurement>
    </measurements>
    <timings>
      <period day="5" duration="10" hour="0" interval="20" minutes="0"/>
    </timings>
  </taskItem>
</Schedule>

But getting this as output:

<Schedule name="myOffice">
  <taskItem taskId="1" startDate="2015-12-01" stopDate="2037-12-31">
    <measurements>
      <measurement>Rupee</measurement>
    </measurements>
    <timings>
      <period day="5" duration="10" hour="0" interval="20" minutes="0"/>
    </timings>
  </taskItem>
</Schedule>

I am not able to get where I am lagging....

My idea is, based on field Measurement, I have to update attributes stopDate in taskItem, and day,duration,hour,interval,minutes in period tag.

My XSLT file is

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

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

  <xsl:template match="taskItem//measurement">
    <xsl:copy>
      <xsl:apply-templates select="@* | node()" />
      <xsl:apply-templates
        select="document('file1.xml')
              /Schedule/taskItem/timings/period[@day = current()/../../timings/period/@day and
                                                @duration = current()/../../timings/period/@duration and 
                                                @hour = current()/../../timings/period/@hour and
                                                @interval = current()/../../timings/period/@interval and
                                                @minutes = current()/../../timings/period/@minutes]/*" />
    </xsl:copy>
  </xsl:template>

</xsl:stylesheet>

I am executing the command in unix as follows:

xsltproc xs.xslt file2.xml

Upvotes: 0

Views: 138

Answers (2)

TrapII
TrapII

Reputation: 2275

This is my (verbose) solution from what I understood. I explicitly update each attributes/fields so you can tweak this solution to adapt it to your needs. The taskId and startDate from the taskItem are taken from file1.xml. The stopDate and timings are take from file2.xml. You must call this XSLT sheet with file1.xml as parameter.

 <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output indent="yes" omit-xml-declaration="yes"/>
  <xsl:template match="@*|node()">
    <xsl:copy>
      <xsl:apply-templates select="@*|node()" />
    </xsl:copy>
  </xsl:template>
  <!-- For all taskItem in file1.xml -->
  <xsl:template match="taskItem">
    <!-- Get all taskItems from file2.xml -->
    <xsl:variable name="tiother" select="document('file2.xml')/Schedule/taskItem" />
    <!-- Get measurement text from current and other taskItems (from file1.xml and file2.xml) -->
    <xsl:variable name="namethis" select="./measurements/measurement/text()" />
    <xsl:variable name="nameother" select="$tiother/measurements/measurement/text()" />
    <xsl:choose>
      <!-- if the measurement texts are the same -->
      <xsl:when test="$namethis = $nameother">
        <!-- Yes ? create a new taskItem updated -->
        <xsl:element name="taskItem">
          <!-- Get taskId from the current task item (the one in file1.xml) -->
          <xsl:attribute name="taskId"><xsl:value-of select="./@taskId"/></xsl:attribute>
          <!-- Get startDate from the current task item (the one in file1.xml) -->
          <xsl:attribute name="startDate"><xsl:value-of select="./@startDate"/></xsl:attribute>
          <!-- Get stopDate from the other task item (the one in file2.xml) -->
          <xsl:attribute name="stopDate"><xsl:value-of select="$tiother/@stopDate"/></xsl:attribute>
          <!-- Get the measurements from the current task item (the one in file1.xml) -->
          <xsl:copy-of select="./measurements"/>
          <!-- Get the timings from the other task item (the one in file2.xml) -->
          <xsl:copy-of select="$tiother/timings"/>
        </xsl:element>
      </xsl:when>
      <xsl:otherwise>
        <!-- No ? just copy the current taskItem -->
        <xsl:copy-of select="."/>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>
</xsl:stylesheet>

Upvotes: 1

michael.hor257k
michael.hor257k

Reputation: 117175

I think you want to do:

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

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

<xsl:template match="timings">
    <xsl:variable name="match" select="document('file2.xml')/Schedule/taskItem[measurements/measurement=current()/../measurements/measurement]/timings"/>
    <xsl:choose>
        <xsl:when test="$match">
            <xsl:copy-of select="$match"/>
        </xsl:when>
        <xsl:otherwise>
            <xsl:copy-of select="."/>
        </xsl:otherwise>
    </xsl:choose>
</xsl:template>

</xsl:stylesheet>

and specify file1.xml as the file to be processed.

Upvotes: 1

Related Questions