Создание XML на основе 2 XML и поиск значений в обоих файлах с помощью XSLT2.0

Я пытаюсь создать XML на основе двух других XML. Я опрашиваю БД, которая возвращает сведения о людях (в запросе может быть n количество людей). Окончательный XML-файл должен содержать точно такое же количество тегов данных, как и различные теги имен в XML-файле, поступающем из БД. Для примера:

1-й XML-получение этого из БД

<parent>
    <child>
        <name>John</name>
        <city>Boston</city>
    </child>
    <child>
        <name>John</name>
        <city>Seattle</city>
    </child>
    <child>
        <name>Allison</name>
        <city>Houston</city>
    </child>
</parent>

2-й XML-получение этого из другого источника

<details>
    <parent>
        <detail>
            <city>Boston</city>
            <code>abc</code>
        </detail>
        <detail>
            <city>Houston</city>
            <code>xyz</code>
        </detail>
    </parent>
    <parent>
        <detail>
            <city>Boston</city>
            <code>abc</code>
        </detail>
        <detail>
            <city>Seattle</city>
            <code>mno</code>
        </detail>
    </parent>
    <parent>
        <detail>
            <city>Houston</city>
            <code>xyz</code>
        </detail>
        <detail>
            <city>Seattle</city>
            <code>mno</code>
        </detail>
    </parent>
</details>

Сначала мне нужно создать 2 тега данных, так как есть 2 разных имени — Джон и Эллисон (эта часть уже сделана и работает нормально). Затем мне нужно проверить Джона, какие бы уникальные теги городов ни присутствовали в возвращаемых строках БД. Давайте рассмотрим 1-й XML, у нас есть Джон, связанный с Бостоном и Сиэтлом. Итак, один за другим, я проверю эти города во втором XML-коде и для каждого тега parent, который я что-то сопоставлю, я создам новый тег details и вставлю весь соответствующий контент. .

1) Если нет совпадающих записей, тег сведений не должен создаваться, так как нет совпадающих записей.

2) Тег city будет находиться под тегом parent. Значения тега city будут УНИКАЛЬНЫ внутри тега parent. Я должен сопоставлять city один за другим во втором XML и брать значения из всех соответствующих тегов city, всех родителей из второго XML и заполнять таким образом, где что угодно сопоставленный в теге parent, помещается в соответствующий тег detail в выходном XML. PFB примеры XML, которые объяснят лучше -

Окончательный ожидаемый XML-

<FinalData>
    <Data>
        <name>John</name>
        <details>
            <detail>
                <city value="Boston">abc</city>
            </detail>
            <detail>
                <city value="Boston">abc</city>
                <city value="Seattle">mno</city>
            </detail>
            <detail>
                <city value="Seattle">mno</city>
            </detail>
        </details>
    </Data>
    <Data>
        <name>Allison</name>
        <details>
            <detail>
                <city value="Houston">xyz</city>
            </detail>
            <detail>
                <city value="Houston">xyz</city>
            </detail>
        </details>
    </Data>
</FinalData>

В настоящее время мой XSLT приводит к чему-то вроде ниже -

<FinalData>
    <Data>
        <name>John</name>
        <details>
            <detail>
                <city value="Boston">abc</city>
                <city value="Boston">abc</city>
                <city value="Seattle">mno</city>
                <city value="Seattle">mno</city>
            </detail>
        </details>
    </Data>
    <Data>
        <name>Allison</name>
        <details>
            <detail>
                <city value="Houston">xyz</city>
                <city value="Houston">xyz</city>
            </detail>
        </details>
    </Data>
</FinalData>

Надеюсь, это понятно, так как я не умею давать объяснения.


person karD    schedule 29.04.2020    source источник


Ответы (1)


Используйте клавиши для разрешения перекрестных ссылок:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    exclude-result-prefixes="#all"
    version="3.0">

  <xsl:param name="details">
<details>
    <parent>
        <detail>
            <city>Boston</city>
            <code>abc</code>
        </detail>
        <detail>
            <city>Houston</city>
            <code>xyz</code>
        </detail>
    </parent>
    <parent>
        <detail>
            <city>Boston</city>
            <code>abc</code>
        </detail>
        <detail>
            <city>Seattle</city>
            <code>mno</code>
        </detail>
    </parent>
    <parent>
        <detail>
            <city>Houston</city>
            <code>xyz</code>
        </detail>
        <detail>
            <city>Seattle</city>
            <code>mno</code>
        </detail>
    </parent>
</details>      
  </xsl:param>

  <xsl:key name="parent-ref" match="parent" use="detail/city"/>
  <xsl:key name="detail-ref" match="parent/detail" use="city"/>

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

  <xsl:template match="parent">
    <FinalData>
        <xsl:for-each-group select="child" group-by="name">
            <Data>
                <xsl:copy-of select="name"/>
            </Data>
            <Details>
                <xsl:apply-templates select="key('parent-ref', current-group()/city, $details)"/>
            </Details>
        </xsl:for-each-group>
    </FinalData>
  </xsl:template>

  <xsl:template match="details/parent">
      <detail>
          <xsl:apply-templates select="key('detail-ref', current-group()/city, .)"/>
      </detail>
  </xsl:template>

  <xsl:template match="detail">
      <city value="{city}">
          <xsl:value-of select="code"/>
      </city>
  </xsl:template>

</xsl:stylesheet>

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

Для полноты второй документ встроен, но вы, конечно, можете использовать вместо него <xsl:param name="details" select="doc('details.xml')"/>.

person Martin Honnen    schedule 29.04.2020
comment
Идеально. Это работает для меня, но у меня немного проблемы с пониманием логики, так как я плохо разбираюсь в ключах, и здесь мы используем 2 ключа. Было бы здорово, если бы вы вкратце объяснили, как это работает? - person karD; 30.04.2020
comment
@Kartik, пробовали ли вы читать ключи разделов в учебнике или книге XSLT (например, cranesoftwrights .github.io/books/ptux/index.htm, если просто назвать один из доступных в Интернете), чтобы понять ключи? Возможно, начните с этого, и если вам не удастся применить введенное там введение к этому случаю, то задайте новый, конкретный вопрос. Объявление ключа дает указание процессору XSLT индексировать узлы matched с помощью выражения use, а функция key затем позволяет использовать для эффективного выбора/поиска узлов по значению ключа. - person Martin Honnen; 04.05.2020
comment
есть ли способ извлечь город из 1-го XML при его совпадении в части apply-template и не брать значение из 2-го XML, где оно соответствует шаблону? Если вы видите приведенный ниже фрагмент кода, <xsl:template match="detail"> <city value="{city}"> // здесь мне нужно значение тега city из 1-го XML, а не из 2-го. - person karD; 04.06.2020
comment
@karD, пожалуйста, задавайте новый, даже если связанный вопрос, как новый, отдельный вопрос с необходимыми деталями. - person Martin Honnen; 04.06.2020
comment
спасибо, разместил его здесь stackoverflow.com/questions/62195646/ . был бы признателен, если бы вы могли мне помочь. - person karD; 05.06.2020