XSLT выводит два документа на основе переменной массива

У меня есть xml-файл с такой структурой:

<?xml version = "1.1" encoding = "UTF-8" standalone = "no"?>
<databaseChangeLog xmlns = "http://www.liquibase.org/xml/ns/dbchangelog" xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"
                   xsi:schemaLocation = "http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.6.xsd">

    <changeSet author = "system" id = "65D7AFA9-17F1-4406-997E-D2B42A0E9008" dbms = "oracle">
        <sql>GRANT SELECT,INSERT,UPDATE,DELETE ON ${dbSchema}.CATALOG TO ${appUser}</sql>
        <rollback>REVOKE SELECT,INSERT,UPDATE,DELETE ON ${dbSchema}.CATALOG FROM ${appUser}</rollback>
    </changeSet>
    <changeSet author = "system" id = "E2731435-DCEE-4B7E-BA60-20A87E75227A" dbms = "oracle">
        <sql>GRANT SELECT,INSERT,UPDATE,DELETE ON ${dbSchema}.CATALOGATTRIBUTE TO ${appUser}</sql>
        <rollback>REVOKE SELECT,INSERT,UPDATE,DELETE ON ${dbSchema}.CATALOGATTRIBUTE FROM ${appUser}</rollback>
    </changeSet>
    <changeSet author = "system" id = "65D7AFA9-17F1-4406-997E-D2B42A0E9008" dbms = "oracle">
        <createTable ...>
    </changeSet>

</databaseChangeLog>

Я хотел бы вывести все changeSet, где sql содержит один из tables, в один документ, а все остальные (которые не содержат имя таблицы) в другой документ. Я думал о том, чтобы добавить что-то к переменной и в конце напечатать две переменные, но это не работает (или я не знаю, как обрабатывать дальше).

<xsl:transform version = "2.0" xmlns:xsl = "http://www.w3.org/1999/XSL/Transform"
               xpath-default-namespace = "http://www.liquibase.org/xml/ns/dbchangelog"
               xmlns = "http://www.liquibase.org/xml/ns/dbchangelog"
               xmlns:uuid = "http://uuid.util.java"
               exclude-result-prefixes = "uuid">

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

    <xsl:variable name = "tables"
                  select = "('CATALOG','CATALOGATTRIBUTE','EVENTTYPES')"/>

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


    <xsl:template match = "changeSet[sql]">
        <xsl:variable name = "changeSet" select = "."/>
        <xsl:variable name = "sql" select = "sql"/>
        <xsl:for-each select = "$tables">
            <!--<xsl:variable name = "selected" select = "sql[contains(text(),concat('${dbSchema}.', ., ' '))]"/>-->
            <xsl:variable name = "tableName">
                <xsl:value-of select = "."/>
                <xsl:value-of select = "' '"/>
            </xsl:variable>
            <xsl:choose>
                <xsl:when test = "contains($sql, $tableName)">
                    <xsl:copy-of select = "$changeSet"/>
                </xsl:when>
                <xsl:otherwise>

                </xsl:otherwise>
            </xsl:choose>
        </xsl:for-each>
    </xsl:template>
</xsl:transform>

можно как-то собрать все changeSet которые совпадают tables а потом все changeSets которые не совпадают?

ps: я использую Saxon-HE-9.8.0-14 для обработки.

Спасибо

Вы можете выбрать, например. //changeSet[$sql[every $table in $tables satisfies contains($sql, $table)]], чтобы выбрать все changeSet элементы, где строковое значение элементов sql содержит каждую строку в переменной tables. Не уверен, что это поможет. Вы не объяснили, какой результат вы хотите.

Martin Honnen 28.05.2019 12:22

Мартин, я пытался поместить ваш сопоставитель в шаблон, но он жалуется Variable sql has not been declared (or its declaration is not in scope). Я хотел бы иметь оба результата, если это возможно (может быть, разделить их на файлы?).

bilak 28.05.2019 12:28

Извините, я как-то поставил доллар перед sql, должен был быть //changeSet[sql[every $table in $tables satisfies contains(., $table)]].

Martin Honnen 28.05.2019 12:47

хм, может быть, я делаю что-то не так, но, возможно, печатает весь документ без применения шаблона. Можете ли вы опубликовать пример? Я пытался что-то вроде этого: <xsl:template match = "changeSet[sql[every $table in $tables satisfies contains(., $table)]]"> <xsl:copy> <xsl:copy-of select = "changeSet"/> </xsl:copy> </xsl:template>

bilak 28.05.2019 12:50

Обратите внимание, что CATALOGATTRIBUTE содержит CATALOG, поэтому, если вы собираетесь использовать contains() в качестве теста, отдельное тестирование CATALOGATTRIBUTE излишне.

michael.hor257k 28.05.2019 12:53

да, я знаю, что я изменил содержание на contains(., concat('${dbSchema}.',$table, ' ')), но это все еще не сработало для меня.

bilak 28.05.2019 13:06

Я думаю, что было бы лучше токенизировать содержимое sql перед сравнением.

michael.hor257k 28.05.2019 13:08
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
7
32
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Рассмотрим следующий пример упрощенный:

XML

<databaseChangeLog>
    <changeSet>
        <sql>ALPHA,BRAVO,CHARLIE</sql>
    </changeSet>
    <changeSet>
        <sql>BRAVO,CHARLIE,DELTA</sql>
    </changeSet>
    <changeSet>
        <sql>DELTA,ECHO,FOXTROT</sql>
    </changeSet>
    <changeSet>
        <sql>FOXTROT,GOLF,HOTEL</sql>
    </changeSet>
</databaseChangeLog>

XSLT 2.0

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

<xsl:param name = "tables" select = "('BRAVO', 'GOLF')"/>

<xsl:template match = "/databaseChangeLog">
    <xsl:variable name = "group1" select = "changeSet[some $t in $tables satisfies contains(sql, $t)]" />
    <xsl:copy>
        <group1>
            <xsl:copy-of select = "$group1"/>
        </group1>
        <group2>
            <xsl:copy-of select = "changeSet except $group1"/>
        </group2>
    </xsl:copy>
</xsl:template>

</xsl:stylesheet>

Результат

<?xml version = "1.0" encoding = "UTF-8"?>
<databaseChangeLog>
   <group1>
      <changeSet>
        <sql>ALPHA,BRAVO,CHARLIE</sql>
      </changeSet>
      <changeSet>
        <sql>BRAVO,CHARLIE,DELTA</sql>
      </changeSet>
      <changeSet>
        <sql>FOXTROT,GOLF,HOTEL</sql>
      </changeSet>
   </group1>
   <group2>
      <changeSet>
        <sql>DELTA,ECHO,FOXTROT</sql>
      </changeSet>
   </group2>
</databaseChangeLog>

Демо: https://xsltfiddle.liberty-development.net/jyRYYiP


Лучшим решением было бы использовать tokenize():

XSLT 2.0

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

<xsl:param name = "tables" select = "('BRAVO', 'GOLF')"/>

<xsl:template match = "/databaseChangeLog">
    <xsl:variable name = "group1" select = "changeSet[tokenize(sql, ',') = $tables]" />
    <xsl:copy>
        <group1>
            <xsl:copy-of select = "$group1"/>
        </group1>
        <group2>
            <xsl:copy-of select = "changeSet except $group1"/>
        </group2>
    </xsl:copy>
</xsl:template>

</xsl:stylesheet>

Демо: https://xsltfiddle.liberty-development.net/jyRYYiP/1

Другие вопросы по теме