CDATA не является XML и не может быть обработано напрямую с помощью XSLT. В XSLT 3.0 есть функция parse-xml-fragment
, которая может предварительно обрабатывать CDATA или иным образом экранировать XML. Однако вы говорите, что:
Я планирую использовать блокнот ++ xmltools
AFAIK, это ограничит вас XSLT 1.0. В таком случае вам нужно обработать ввод XML дважды .
Сначала примените это преобразование и сохраните результат в файл:
XSLT 1,0 [1]
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<!-- identity transform -->
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="steps | expectedresults">
<xsl:copy>
<xsl:value-of select="." disable-output-escaping="yes"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Это должно привести к следующему XML:
XML [2]
<?xml version="1.0" encoding="UTF-8"?>
<testcases>
<testcase name="Simple">
<steps><p>1. do something</p>
<p>2. do more</p>
<p>3. even more</p></steps>
<expectedresults><p>1. result</p>
<p>2. more result</p>
<p>3 again</p></expectedresults>
</testcase>
</testcases>
Теперь к полученному файлу можно применить следующую таблицу стилей:
XSLT 1.0 [2]]
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"
cdata-section-elements="step_number actions expectedresults execution_type"/>
<xsl:strip-space elements="*"/>
<!-- identity transform -->
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="testcase">
<xsl:copy>
<xsl:attribute name="name">
<xsl:value-of select="@name" />
<xsl:text> new</xsl:text>
</xsl:attribute>
<xsl:for-each select="steps/p">
<step>
<xsl:variable name="i" select="position()"/>
<step_number>
<xsl:value-of select="$i"/>
</step_number>
<actions>
<xsl:text><p></xsl:text>
<xsl:value-of select="substring-after(., '. ')" />
<xsl:text></p></xsl:text>
</actions>
<expectedresults>
<xsl:text><p></xsl:text>
<xsl:value-of select="substring-after(../following-sibling::expectedresults/p[$i], '. ')"/>
<xsl:text></p></xsl:text>
</expectedresults>
<execution_type>1</execution_type>
</step>
</xsl:for-each>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
, чтобы получить:
Окончательный результат
<?xml version="1.0" encoding="UTF-8"?>
<testcases>
<testcase name="Simple new">
<step>
<step_number><![CDATA[1]]></step_number>
<actions><![CDATA[<p>do something</p>]]></actions>
<expectedresults><![CDATA[<p>result</p>]]></expectedresults>
<execution_type><![CDATA[1]]></execution_type>
</step>
<step>
<step_number><![CDATA[2]]></step_number>
<actions><![CDATA[<p>do more</p>]]></actions>
<expectedresults><![CDATA[<p>more result</p>]]></expectedresults>
<execution_type><![CDATA[1]]></execution_type>
</step>
<step>
<step_number><![CDATA[3]]></step_number>
<actions><![CDATA[<p>even more</p>]]></actions>
<expectedresults><![CDATA[<p>again</p>]]></expectedresults>
<execution_type><![CDATA[1]]></execution_type>
</step>
</testcase>
</testcases>
Примечания:
Мой результат несколько отличается от того, который вы показываете. Тем не менее, я считаю, что это то, что вы хотели;
Я изменил ввод, добавив точку после 3 в <p>3 again</p>
.
Добавлено:
Если то, что я прочитал, соответствует действительности, и ваш инструмент фактически использует XSLT-процессор libxslt
, то вы можете сделать все это за один проход с помощью EXSLT str:split()
функция расширения, поддерживаемая libxslt
:
XSLT 1.0 + EXSLT
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:str="http://exslt.org/strings"
extension-element-prefixes="str">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"
cdata-section-elements="step_number actions expectedresults execution_type"/>
<xsl:strip-space elements="*"/>
<!-- identity transform -->
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="testcase">
<xsl:variable name="steps" select="str:split(steps, '<p>')"/>
<xsl:variable name="expectedresults" select="str:split(expectedresults, '<p>')"/>
<xsl:copy>
<xsl:attribute name="name">
<xsl:value-of select="@name" />
<xsl:text> new</xsl:text>
</xsl:attribute>
<xsl:for-each select="$steps">
<step>
<xsl:variable name="i" select="position()"/>
<step_number>
<xsl:value-of select="$i"/>
</step_number>
<actions>
<xsl:text><p></xsl:text>
<xsl:value-of select="substring-after(., '. ')" />
</actions>
<expectedresults>
<xsl:text><p></xsl:text>
<xsl:value-of select="substring-after($expectedresults[$i], '. ')"/>
</expectedresults>
<execution_type>1</execution_type>
</step>
</xsl:for-each>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>