简体   繁体   中英

How to merge two xml files using XSLT1.0

I am trying to merge two xml files using XSLT1.0. I am trying to merge FileOne and Filetwo to merge to a new xml file. The resultant xml should contain one element from file two based on the value from measurement tag. Any help would be greatly appreciated

Fileone.xml

<Schedule name="NE3S">
    <Item scheduleId="1" startDate="2013-01-01" stopDate="2037-12-31">
        <measurements>
            <measurement>PGW0001</measurement>
        </measurements>
        <measPeriods>
            <period day="0" duration="0" hour="0" interval="15" minutes="0"/>
        </measPeriods>
    </Item>
    <Item scheduleId="2" startDate="2013-01-01" stopDate="2037-12-31">
        <measurements>
            <measurement>PGW0002</measurement>
        </measurements>
        <measPeriods>
            <period day="0" duration="0" hour="0" interval="60" minutes="0"/>
        </measPeriods>
    </Item>
</Schedule>

Filetwo.xml

<Schedule name="NE3S">
    <Item scheduleId="1" startDate="2013-01-01" stopDate="2037-12-31">
        <measurements>
        <measurement>PGW0001</measurement>
    </measurements>
    <measPeriods>
        <period day="0" duration="0" hour="0" interval="60" minutes="0"/>
    </measPeriods>
    </Item>
    <Item scheduleId="2" startDate="2013-01-01" stopDate="2037-12-31">
        <measurements>
            <measurement>PGD0001</measurement>
        </measurements>
    <measPeriods>
        <period day="0" duration="0" hour="0" interval="60" minutes="0"/>
    </measPeriods>
    </Item>
    <Item scheduleId="3" startDate="2013-01-01" stopDate="2037-12-31">
        <measurements>
            <measurement>PGW0002</measurement>
        </measurements>
        <measPeriods>
            <period day="0" duration="0" hour="0" interval="60" minutes="0"/>
        </measPeriods>
    </Item>
</Schedule>

My expected output is

<Schedule name="NE3S">
    <Item scheduleId="1" startDate="2013-01-01" stopDate="2037-12-31">
        <measurements>
            <measurement>PGW0001</measurement>
        </measurements>
        <measPeriods>
            <period day="0" duration="0" hour="0" interval="15" minutes="0"/>
        </measPeriods>
    </Item>
    <Item scheduleId="2" startDate="2013-01-01" stopDate="2037-12-31">
        <measurements>
            <measurement>PGD0001</measurement>
        </measurements>
        <measPeriods>
            <period day="0" duration="0" hour="0" interval="60" minutes="0"/>
        </measPeriods>
    </Item>
    <Item scheduleId="3" startDate="2013-01-01" stopDate="2037-12-31">
        <measurements>
            <measurement>PGW0002</measurement>
        </measurements>
        <measPeriods>
            <period day="0" duration="0" hour="0" interval="60" minutes="0"/>
        </measPeriods>
    </Item>
</Schedule>

please note that expected output

<measPeriods>
  <period day="0" duration="0" hour="0" interval="15" minutes="0"/>
</measPeriods>

I tried the following code

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:param name="fileName" select="'/opt/Filetwo.xml'" />
<xsl:param name="updates" select="document($fileName)" />

<xsl:variable name="updateMeasurement" select="$updates/Schedule/Item" />

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

<xsl:template match="Schedule">
    <xsl:copy>
      <xsl:apply-templates select="Item[not(measurements/measurement = $updateMeasurement/measurements/measurement)]" />
      <xsl:apply-templates select="/Schedule/Item//measurements" />
      <xsl:apply-templates select="$updates/Schedule/Item/measPeriods" />
    </xsl:copy>
  </xsl:template>
</xsl:stylesheet>


xsltproc merge.xslt /opt/Fileone.xml > /opt/FileThree.xml

my expected output should have the <measPeriods> tag from Fileone.xml if the value in <measurements>/<measurement> matches

edited my solution to

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0"
encoding="UTF-8" indent="yes"/>

<xsl:variable name="addresses"
select="document('/opt/esymac/extras/esymacstarter/schedule/MJ.netact.xml_backup')"/>
   <xsl:template match="/measSchedule">
        <measSchedule name="NE3S">
        <xsl:for-each select="scheduleItem">
           <xsl:variable name="id" select="@scheduleId"/>
           <xsl:variable name="startDate" select="@startDate"/>
           <xsl:variable name="stopDate" select="@stopDate"/>
           <xsl:variable name="day" select="measPeriods/period/@day"/>
           <xsl:variable name="duration" select="measPeriods/period/@duration"/>
           <xsl:variable name="hour" select="measPeriods/period/@hour"/>
           <xsl:variable name="minutes" select="measPeriods/period/@minutes"/>

           <xsl:variable name="interval"
select="$addresses/measSchedule/scheduleItem/measurements[$counterId =
@measurement]/measPeriods/@interval"/>
             <Item scheduleId="{$id}" startDate="{$startDate}" stopDate="{$stopDate}">
             <measurements>
                <measurement><xsl:value-of select="measurements/measurement"/></measurement>
             </measurements>
             <measPeriods>
                   <period day="{$day}" duration="{$duration}" hour="{$hour}" interval="{$interval}" minutes="{$minutes}"/>
             </measPeriods>
             </Item>
    </xsl:for-each>
</measSchedule>
</xsl:template>

</xsl:stylesheet>

now i am getting Item tag properly but

<period day="{$day}" duration="{$duration}" hour="{$hour}" interval="{$interval}" minutes="{$minutes}"/>

is still not proper

From the input XMLs, it looks like Fileone.xml has a subset of records from the Filetwo.xml . An easier approach will be write the XSL and apply it on Filetwo.xml (since it has all the records and we have to replace only few) and access Fileone.xml using the document() function.

For the matching value of <measurement> , you can use the <xsl:choose></xsl:choose> to copy period from Fileone.xml and for the non-matching value, retain period from Filetwo.xml . Below is the <xsl:choose> block.

<xsl:choose>
    <xsl:when test="$extSchedule/Item/measurements/measurement = current()/ancestor::Item/measurements/measurement">
        <xsl:copy-of select="$extSchedule/Item[measurements/measurement = current()/ancestor::Item/measurements/measurement]/measPeriods/period" />
    </xsl:when>
    <xsl:otherwise>
        <xsl:apply-templates select="period" />
    </xsl:otherwise>
</xsl:choose>

Here current() is used to access the correct node and its corresponding sibling's measurement value.

The complete XSLT is as below

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" />
    <xsl:strip-space elements="*" />

    <xsl:param name="fileName" select="document('Fileone.xml')" />
    <xsl:variable name="extSchedule" select="$fileName/Schedule" />

    <xsl:template match="@* | node()">
        <xsl:copy>
            <xsl:apply-templates select="@* | node()" />
        </xsl:copy>
    </xsl:template>
    <xsl:template match="measPeriods">
        <xsl:copy>
            <xsl:choose>
                <xsl:when test="$extSchedule/Item/measurements/measurement = current()/ancestor::Item/measurements/measurement">
                    <xsl:copy-of select="$extSchedule/Item[measurements/measurement = current()/ancestor::Item/measurements/measurement]/measPeriods/period" />
                </xsl:when>
                <xsl:otherwise>
                    <xsl:apply-templates select="period" />
                </xsl:otherwise>
            </xsl:choose>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

The output below shows the period for PGW0001 has been replaced with the corresponding node from Fileone.xml .

<Schedule name="NE3S">
    <Item scheduleId="1" startDate="2013-01-01" stopDate="2037-12-31">
        <measurements>
            <measurement>PGW0001</measurement>
        </measurements>
        <measPeriods>
            <period day="0" duration="0" hour="0" interval="15" minutes="0" />
        </measPeriods>
    </Item>
    <Item scheduleId="2" startDate="2013-01-01" stopDate="2037-12-31">
        <measurements>
            <measurement>PGD0001</measurement>
        </measurements>
        <measPeriods>
            <period day="0" duration="0" hour="0" interval="60" minutes="0" />
        </measPeriods>
    </Item>
    <Item scheduleId="3" startDate="2013-01-01" stopDate="2037-12-31">
        <measurements>
            <measurement>PGW0002</measurement>
        </measurements>
        <measPeriods>
            <period day="0" duration="0" hour="0" interval="60" minutes="0" />
        </measPeriods>
    </Item>
</Schedule>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM