Преобразование списка с разделителями переменной длины в XML с помощью XSLT 1.0

Ввод текста следует преобразовать в вывод XML с помощью XSLT 1.0. Список имеет переменную длину с разделителем |.

Вход:

name=IMON_EVENT;next_state=SET_IMON;is_enabled=true; | name=MAIN_BATCH;next_state=BATCH01;is_enabled=false;priority=9;

Ожидаемый результат:

<time-triggers>
    <trigger>
        <name>IMON_EVENT</name>
        <next_state>SET_IMON</next_state>
        <is_enabled>true</is_enabled>
    </trigger>
    <trigger>
        <name>MAIN_BATCH</name>
        <next_state>BATCH01</next_state>
        <is_enabled>false</is_enabled>
        <priority>9</priority>
    </trigger>
</time-triggers>

Итак, какую версию XSLT вы используете / можете ли вы использовать? XSLT 2 имеет tokenize и xsl:analyze-string, XSLT 3 дополнительно имеет функцию analyze-string.

Martin Honnen 08.09.2018 14:18

Сначала сплит на |, затем снова разделите каждый результат на ;, затем снова разделите каждый результат на = ...

GSerg 08.09.2018 14:18

@MartinHonnen Мне нужно использовать XSLT 1.0 без функции установки узлов.

Shikha 10.09.2018 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 называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
3
96
2

Ответы 2

Для XSLT 1.0 вы можете использовать рекурсивные вызовы шаблонов, которые проверяют наличие разделителей и используют substring-before() и substring-after()

<xsl:stylesheet xmlns:xsl = "http://www.w3.org/1999/XSL/Transform"
    version = "1.0">

    <xsl:output indent = "yes"/>

    <xsl:template match = "/">
        <xsl:variable name = "triggers" select = "'name=IMON_EVENT;next_state=SET_IMON;is_enabled=true; | name=MAIN_BATCH;next_state=BATCH01;is_enabled=false;priority=9;'"/>

        <triggers>
            <xsl:call-template name = "make-trigger">
                <xsl:with-param name = "val" select = "$triggers"/>
            </xsl:call-template> 
        </triggers>   
    </xsl:template>

    <xsl:template name = "make-trigger">
        <xsl:param name = "val"/>

        <xsl:if test = "normalize-space($val)">
            <xsl:choose>
                <xsl:when test = "contains($val, '|')">
                    <trigger>
                    <xsl:call-template name = "make-elements">
                        <xsl:with-param name = "val" select = "substring-before($val, '|')"/>
                    </xsl:call-template>
                    </trigger>
                    <xsl:call-template name = "make-trigger">
                        <xsl:with-param name = "val" select = "substring-after($val, '|')"/>
                    </xsl:call-template>
                </xsl:when>
                <xsl:otherwise>
                    <trigger>
                    <xsl:call-template name = "make-elements">
                        <xsl:with-param name = "val" select = "$val"/>
                    </xsl:call-template>
                    </trigger>
                </xsl:otherwise>
            </xsl:choose>
        </xsl:if>
    </xsl:template>

    <xsl:template name = "make-elements">
        <xsl:param name = "val"/>

        <xsl:if test = "contains($val, '=')">
            <xsl:choose>
                <xsl:when test = "contains($val, ';')">
                    <xsl:call-template name = "make-element">
                        <xsl:with-param name = "val" select = "substring-before($val, ';')"/>
                    </xsl:call-template>
                    <xsl:call-template name = "make-elements">
                        <xsl:with-param name = "val" select = "substring-after($val, ';')"/>
                    </xsl:call-template>
                </xsl:when>
                <xsl:otherwise>
                    <xsl:call-template name = "make-element">
                        <xsl:with-param name = "val" select = "$val"/>
                    </xsl:call-template>
                </xsl:otherwise>
            </xsl:choose>
        </xsl:if>
    </xsl:template>

    <xsl:template name = "make-element">
        <xsl:param name = "val"/>

        <xsl:element name = "{normalize-space(substring-before($val, '='))}">
            <xsl:value-of select = "substring-after($val, '=')"/>
        </xsl:element>
    </xsl:template>

</xsl:stylesheet>

Ниже представлено решение XSLT 2.0, которое использует функцию tokenize() для разделения значений разделителями | и ; с вложенными xsl:for-each для обработки последовательности значений, xsl:analyze-string для захвата имени и значения между = и xsl:element для создания динамически именованных элементов из регулярного выражения. группы захвата.

<xsl:stylesheet xmlns:xsl = "http://www.w3.org/1999/XSL/Transform"
    version = "2.0">

  <xsl:output indent = "yes"/>

  <xsl:template match = "/">
    <xsl:variable name = "triggers" select = "'name=IMON_EVENT;next_state=SET_IMON;is_enabled=true; | name=MAIN_BATCH;next_state=BATCH01;is_enabled=false;priority=9;'"/>

    <triggers>
      <xsl:for-each  select = "tokenize($triggers, '\s*\|\s*')">
        <trigger>
          <xsl:for-each select = "tokenize(., '\s*;\s*')">
              <xsl:analyze-string select = "." regex = "(.+)=(.*)">
                  <xsl:matching-substring>
                      <xsl:element name = "{regex-group(1)}">
                          <xsl:value-of select = "regex-group(2)"/>
                      </xsl:element>
                  </xsl:matching-substring>
              </xsl:analyze-string> 
          </xsl:for-each>
        </trigger>  
      </xsl:for-each>
    </triggers>

  </xsl:template>

</xsl:stylesheet>

Как я могу сделать это в XSLT 1.0 без использования функции набора узлов?

Shikha 10.09.2018 13:07

Я добавил решение XSLT 1.0, которое использует рекурсивные вызовы шаблонов. Если вы можете использовать механизм XSLT 2.0, все станет намного проще с мощью регулярных выражений для разделения строк и возможностей сопоставления с образцом.

Mads Hansen 19.09.2018 04:36

Размещение исходной строки в XSLT-скрипте - плохая практика, особенно если вы хотите обрабатывать различные входные данные.

Если вы можете использовать XSLT версии 2.0, вам лучше использовать следующие функции:

  • unparsed-text-available - чтобы проверить, существует ли входной файл,
  • unparsed-text - для чтения содержимого этого файла в переменную.

Остальная часть скрипта (как обработать прочитанный контент) может быть такой же, как в другом ответе.

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