необходимо объединить данные из двух файлов XML на основе идентификатора записи

у меня есть следующие два файла xml. Файл A:

<breakfast_menu>
    <food>
        <id>1</id>
        <name>Belgian Waffles</name>
        <price>$5.95</price>
        <calories>650</calories>
    </food>
    <food>
        <id>2</id>
        <name>Strawberry Belgian Waffles</name>
        <price>$7.95</price>
        <calories>900</calories>
    </food>
</breakfast_menu>

и файл B:

<breakfast_menu>
    <food>
        <id>1</id>
        <description>here we have already a description element</description>
        <otherData>s3650</otherData>
    </food>
    <food>
        <id>2</id>
        <otherData>s3250</otherData>
        <otherData2>g508</otherData2>
        <otherData3>sidi6098</otherData3>
    </food>
</breakfast_menu>

то, чего я не могу достичь, - это для каждой записи, соответствующей на основе идентификатора записи, взять всю информацию из XML-файла с именем A и поместить всю эту информацию в элемент описания файла B, но также сохранить элемент, из которого он пришел. Если соответствующая запись не имеет элемента описания, мы добавляем его. Если он уже есть, то мы должны знать, где начинается информация, взятая из файла A, с текстовым разделителем, то есть «-followingInfoTakenFromFileA-». Итак, с учетом вышеизложенного, желаемый результат должен быть таким:

 <breakfast_menu>
    <food>
        <id>1</id>
        <description>here we have already a description element-followingInfoTakenFromFileA-name:Belgian Waffles-price:$5.95-calories:650</description>
        <otherData>s3650</otherData>
    </food>
    <food>
        <id>2</id>
        <otherData>s3250</otherData>
        <otherData2>g508</otherData2>
        <otherData3>sidi6098</otherData3>
        <description>name:Strawberry Belgian Waffles-price:$7.95-calories:900</description>
    </food>
</breakfast_menu>

person Community    schedule 25.07.2019    source источник
comment
Ну, поскольку вы отметили вопрос как xslt-3.0 и использовали термин слияние в своем вопросе, вы посмотрели в функции XSLT 3, такие как слияние w3.org/TR/xslt-30/#merging < / а>? Похоже, вы должны быть в состоянии придумать какой-то подход к своим образцам, чтобы хотя бы показать нам, где именно вы застряли.   -  person Martin Honnen    schedule 25.07.2019
comment
Отредактируйте свой вопрос и покажите нам свой XSLT-код вместе с полученным результатом.   -  person Martin Honnen    schedule 25.07.2019
comment
код, который у меня сейчас есть, не работает, поэтому я вообще не могу получить никаких результатов, вроде все испортил :(   -  person    schedule 25.07.2019


Ответы (1)


Кажется, учитывая отсортированные id ключи слияния, простая задача для xsl:merge:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    exclude-result-prefixes="#all"
    expand-text="yes"
    version="3.0">

  <xsl:param name="doc-A">
<breakfast_menu>
    <food>
        <id>1</id>
        <name>Belgian Waffles</name>
        <price>$5.95</price>
        <calories>650</calories>
    </food>
    <food>
        <id>2</id>
        <name>Strawberry Belgian Waffles</name>
        <price>$7.95</price>
        <calories>900</calories>
    </food>
</breakfast_menu>
  </xsl:param>

  <xsl:mode on-no-match="shallow-copy"/>

  <xsl:output method="xml" indent="yes"/>

  <xsl:template match="/*">
    <xsl:copy>
        <xsl:merge>
            <xsl:merge-source for-each-item="." select="food">
                <xsl:merge-key select="id"/>
            </xsl:merge-source>
            <xsl:merge-source for-each-item="$doc-A" select="//food">
                <xsl:merge-key select="id"/>
            </xsl:merge-source>
            <xsl:merge-action>
                <xsl:copy>
                    <xsl:apply-templates select="*">
                        <xsl:with-param name="merge-data" 
                          select="let $data := string-join(current-merge-group()[2]/(* except id)!(name() || ':' || .), '-')
                                  return if (description)
                                         then '-followingInfoTakenFrom' || document-uri(root(current-merge-group()[2])) || $data
                                         else $data"/>
                    </xsl:apply-templates>
                </xsl:copy>
            </xsl:merge-action>
        </xsl:merge>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="food/description">
      <xsl:param name="merge-data"/>
      <xsl:copy>{.}{$merge-data}</xsl:copy>
  </xsl:template>

  <xsl:template match="food[not(description)]/*[last()]">
      <xsl:param name="merge-data"/>
      <xsl:next-match/>
      <description>{$merge-data}</description>
  </xsl:template>

</xsl:stylesheet>

https://xsltfiddle.liberty-development.net/pPzifqo

В этих примерах первый документ встроен в качестве параметра для автономности образца, но в реальном мире вы можете загрузить его с URL-адреса, например, <xsl:param name="doc-A" select="doc('fileA.xml')"/>.

person Martin Honnen    schedule 25.07.2019
comment
просто для полноты ответа, как следует изменить приведенное выше, если у кого-то были несортированные ключи слияния идентификаторов? вот более новый пример: xsltfiddle.liberty-development.net/pPzifqq Или это должен быть вместо этого новый вопрос? - person ; 01.08.2019
comment
@raka, задайте новый вопрос с необходимыми деталями ввода XML, вывода, который вы хотите, кода, который у вас есть, вывода или ошибок, которые вы получаете, если только использование sort-before-merge="yes" на xsl:merge-sources, которые у вас есть, не решит проблему. - person Martin Honnen; 01.08.2019
comment
похоже, это работает. Если я увижу что-то странное в выводе, я дам вам знать, спасибо - person ; 01.08.2019