Ввод текста следует преобразовать в вывод 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>
Сначала сплит на |
, затем снова разделите каждый результат на ;
, затем снова разделите каждый результат на =
...
@MartinHonnen Мне нужно использовать XSLT 1.0 без функции установки узлов.
Для 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 без использования функции набора узлов?
Я добавил решение XSLT 1.0, которое использует рекурсивные вызовы шаблонов. Если вы можете использовать механизм XSLT 2.0, все станет намного проще с мощью регулярных выражений для разделения строк и возможностей сопоставления с образцом.
Размещение исходной строки в XSLT-скрипте - плохая практика, особенно если вы хотите обрабатывать различные входные данные.
Если вы можете использовать XSLT версии 2.0, вам лучше использовать следующие функции:
unparsed-text-available
- чтобы проверить, существует ли входной файл,unparsed-text
- для чтения содержимого этого файла в переменную.Остальная часть скрипта (как обработать прочитанный контент) может быть такой же, как в другом ответе.
Итак, какую версию XSLT вы используете / можете ли вы использовать? XSLT 2 имеет
tokenize
иxsl:analyze-string
, XSLT 3 дополнительно имеет функциюanalyze-string
.