Как объединить два XML-файла с помощью XSLT1.0

#xml #xslt

#xml #xslt

Вопрос:

Я пытаюсь объединить два XML-файла с помощью XSLT1.0. Я пытаюсь объединить FileOne и Filetwo для объединения в новый XML-файл. Результирующий XML должен содержать один элемент из файла two на основе значения из тега измерения. Любая помощь была бы очень признательна

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>
  

Мой ожидаемый результат таков

 <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>
  

пожалуйста, обратите внимание, что ожидаемый результат

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

Я попробовал следующий код

 <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
  

мой ожидаемый результат должен содержать <measPeriods> тег from Fileone.xml , если значение в <measurements>/<measurement> совпадает

отредактировал свое решение на

 <?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>
  

теперь я правильно получаю тег элемента, но

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

все еще не подходит

Комментарии:

1. Ваша таблица стилей отражает логику, противоположную ожидаемому результату и определению проблемы. Кроме того, ключ слияния не только measurements .

2. Как мне объединить на основе нескольких ключей?

3. Изначально я сохранил <xsl:copy> <xsl:apply-templates select=»scheduleItem[not(measurements / измерение = $updateMeasurement/ измерения / измерение)]» /> <xsl:apply-templates select=»$updateMeasurement» /> </xsl:copy> но это привело к другому результату.. Пытался поэкспериментировать с другой логикой

4. отредактировал мое решение

Ответ №1:

Судя по входным XML-файлам, он Fileone.xml содержит подмножество записей из Filetwo.xml . Более простым подходом будет написать XSL и применить его к Filetwo.xml (поскольку в нем есть все записи, и нам нужно заменить только несколько) и получить доступ, Fileone.xml используя document() функцию.

Для совпадающего значения <measurement> вы можете использовать <xsl:choose></xsl:choose> для копирования period из Fileone.xml , а для несоответствующего значения — сохранить period из Filetwo.xml . Ниже находится <xsl:choose> блок.

 <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>
  

Здесь current() используется для доступа к правильному узлу и его measurement значению соответствующего родственного файла.

Полный XSLT выглядит следующим образом

 <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>
  

Вывод ниже показывает, что period for PGW0001 был заменен на соответствующий узел из 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>
  

Комментарии:

1. Спасибо Aniket.. Это решение сработало замечательно. Еще одно небольшое сомнение, когда я выполняю это в Linux с помощью команды xsltproc, кажется, что весь вывод находится в одной строке.. есть ли способ избежать этого?

2. <xsl:метод вывода= «xml», версия = «1.0», кодировка = «UTF-8», отступ = «yes» /> это изменило отступ на выходе.. Спасибо за ваши усилия, аникет.. Очень признателен. Я опытный разработчик Java, впервые пробующий свои силы на XSLT, и мне было трудно выучить этот нефункциональный язык..

3. Если ответ сработал для вас, не могли бы вы принять ответ. Как принять ответ