динамический рекурсивный xslt для обновления XML из другого XML - PullRequest
0 голосов
/ 25 марта 2019

Фон / Резюме: у меня есть очень большой вложенный (Job-XML) XML. Мы выполняем процесс, который позволяет пользователям вносить изменения в данные (визуальный элемент XML), затем нам необходимо отобразить эти изменения обратно в XML, чтобы мы могли отправить обновление в XML обратно в исходную систему. Пользователь может изменить 1 вещь или 1 миллион вещей на любом уровне документа, который они видят.

Платформа, которую мы используем, которая позволяет пользователям вносить изменения, создает список тегов и их значений (Список изменений), которые пользователь изменил. мы сопоставили эти теги с исходным местоположением XML, но делать это в преобразователе Java будет громоздким и неинтересным в обслуживании.

в идеале я хочу сгенерировать XML из сторонней платформы XML (Change XML), которая имеет местоположения в исходном XML для обновления и идентификаторы, указывающие, какую часть исходного XML (Jobs XML) следует изменить.

Задача : Для каждого из модов задан файл Changes.xml с модификациями - замените это поле в Jobs.xml значением этого мода, если этот элемент соответствует условиям идентификатора, вызванным в модификации.

Я уже подумал, что я могу динамически выбирать Xpath, учитывая список Xpath, и также обновлять это значение динамически. Который работает, ЕСЛИ не было условий на подбор, но есть.

Я могу использовать XSL 1-3, не имеет значения.

<?xml version="1.0" encoding="UTF-8"?>
<!--CHANGES.XML -->
<accounts>
<changes>
        <modifications>
            <modification>
                <parentpath>accounts/locationArea/thisloc</parentpath>

                <mods>
                    <mod>
                        <path>/accounts/locationArea/thisloc/jobs/job</path>
                        <field>salary</field>
                        <val>1000</val>
                    </mod>

                </mods>
                <identifiers>
                    <identifier>
                        <path>accounts/locationArea/thisloc</path>
                        <field>key</field>
                        <val>1</val>
                    </identifier>
                    <identifier>
                        <path>accounts/locationArea/thisloc/jobs/job</path>
                        <field>building</field>
                        <val>1</val>
                    </identifier>
                    <identifier>
                        <path>accounts/locationArea/thisloc/jobs/job</path>
                        <field>role</field>
                        <val>Kitchen</val>
                    </identifier>
                </identifiers>
            </modification>
            <modification>
                <parentpath>accounts/locationArea/thisloc</parentpath>

                <mods>
                    <mod>
                        <path>/accounts/locationArea/thisloc</path>
                        <field>manager</field>
                        <val>Sam</val>
                    </mod>
<mod>
                        <path>/accounts/locationArea/thisloc</path>
                        <field>updated</field>
                        <val>true</val>
                    </mod>
                </mods>
                <identifiers/>
            </modification>
        </modifications>
    </changes>
</accounts>
<?xml version="1.0" encoding="UTF-8"?>
<!--Jobs.XML, this is the one we need to edit -->
<accounts>
<locationArea>
        <thisloc>
            <title>locaton1</title>
            <manager>Dean</manager>
            <key>1</key>
            <jobs>
                <job>
                    <tag>1</tag>
                    <building>1</building>
                    <role>BA</role>
                    <salary>100</salary>
                </job>
                <job>
                    <tag>2</tag>
                    <building>1</building>
                    <role>IT</role>
                    <salary>200</salary>
                </job>
                <job>
                    <tag>3</tag>
                    <building>1</building>
                    <role>Kitchen</role>
                    <salary>300</salary>
                </job>
            </jobs>
        </thisloc>
        <thisloc>
            <title>locaton2</title>
            <manager>Smith</manager>
                        <updated>false</updated>
            <key>2</key>
            <jobs>
                <job>
                    <tag>1</tag>
                    <building>1</building>
                    <role>Kitchen</role>
                    <salary>300</salary>
                </job>
                <job>
                    <tag>2</tag>
                    <building>2</building>
                    <role>Mail</role>
                    <salary>400</salary>
                </job>
            </jobs>
        </thisloc>
    </locationArea>
</accounts>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:my="http://myns">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>
 <xsl:param name="changesXML" select="doc('changes.xml')"/>
    <xsl:variable name="changes" select="$changesXML/accounts/changes/modifications/modification/mods/mod"/>

   <xsl:template name="dynomatch" match="*[$changes/path]/*[local-name()=$changes/field]/text()">
        <xsl:value-of select="$changes/val"/>
  </xsl:template>
</xsl:stylesheet>

Я хочу, чтобы результаты выглядели так:

  • (1) «зарплата» для роли кухни для ТОЛЬКО ключа местоположения 1 была обновлена ​​с 300 тоже 1000
  • (2) «менеджер» для всех мест был изменен на «Сэм»
  • и (3) значение «обновлено» было установлено в значение «истина» для всех местоположений и добавлено для тех, кто пропускал тег все вместе.
<?xml version="1.0" encoding="UTF-8"?>
<accounts>
<locationArea>
        <thisloc>
            <title>locaton1</title>
            <manager>Sam</manager>
                        <updated>true</updated>
            <key>1</key>
            <jobs>
                <job>
                    <tag>1</tag>
                    <building>1</building>
                    <role>BA</role>
                    <salary>100</salary>
                </job>
                <job>
                    <tag>2</tag>
                    <building>1</building>
                    <role>IT</role>
                    <salary>200</salary>
                </job>
                <job>
                    <tag>3</tag>
                    <building>1</building>
                    <role>Kitchen</role>
                    <salary>350</salary>
                </job>
            </jobs>
        </thisloc>
        <thisloc>
            <title>locaton2</title>
            <manager>Sam</manager>
                        <updated>true</updated>
            <key>2</key>
            <jobs>
                <job>
                    <tag>1</tag>
                    <building>1</building>
                    <role>Kitchen</role>
                    <salary>300</salary>
                </job>
                <job>
                    <tag>2</tag>
                    <building>2</building>
                    <role>Mail</role>
                    <salary>400</salary>
                </job>
            </jobs>
        </thisloc>
    </locationArea>
</accounts>

1 Ответ

1 голос
/ 26 марта 2019

Если честно, и как человек, который считает XSLT очень универсальным, это похоже на работу для процедурного языка. С XSLT вы фильтруете, поэтому на каждом узле из входного документа (jobs.xml) вы должны просмотреть список изменений и решить, соответствует ли текущий узел всем критериям любого из узлов изменения. Если ничего другого, это будет довольно медленно.

XSLT не может выполнять обновления на месте. Он всегда создает новый вывод из ввода, хотя его можно использовать для простого копирования части узлов из ввода в вывод. Однако кажется более естественным открыть исходный документ, а затем выполнить итерацию списка изменений, выполнить поиск одного или нескольких узлов, соответствующих списку критериев, манипулировать значениями и добавить / обновить атрибут «updated».

Для интерпретации списка критериев требуется достаточное количество информации. Например, / изменения / модификации / модификации [1] / идентификаторы / идентификатор [1] и идентификатор [2] имеют разные пути, поэтому один квалифицирует родительский элемент, а другой ссылается на элемент, который необходимо изменить. Все это должно быть закодировано в некоторой логике, которая фактически сравнивает пути и выполняет сопоставление, и делать это с XSLT будет очень болезненно.

...