#xml #xslt
#xml #xslt
Вопрос:
У меня есть следующий узел, который мне нужно проанализировать с использованием XSLT 1.0 из xml-файла
<log>Passed -ID:1 -Log:
Passed -ID:2 -Log:Suite
File/Folder
Failed -ID:3 -Log:Suite
Validate Install Failed
Passed -ID:4 -Log:
</log>
Вот -ID: -Log:
как вы можете видеть, может быть записан в одной строке или в нескольких строках.
В результате я хотел бы получить другой XML-файл, в котором будут проанализированы данные с узла. Если запись с идентификатором была передана, то мне нужно написать «/>. Если запись не удалась, мне нужно написать
<testcase name="<ID Name>">
<failure message="<Log Message>"/>
</testcase>
Другими словами, мне нужно получить этот XML-файл.
<xml>
<testcase name="1"/>
<testcase name="2"/>
<testcase name="3">
<failure message="Suite Validate Install Failed"/>
</testcase>
<testcase name="4"/>
</xml>
Как вы думаете, какой способ сделать это лучше всего?
XML-файл на самом деле очень большой, и я предоставил здесь только один узел, который мне нужно проанализировать. Я использую xslt, потому что я получаю другую информацию от других узлов, которая мне также нужна для результирующих XML-файлов.
Спасибо.
Комментарии:
1. Боюсь, что XSL может анализировать XML-файлы только для генерации текстового вывода, а не наоборот.
2. вам действительно нужно делать это с помощью XSLT? Входной файл кажется очень простым XML, и на самом деле вы хотите обработать текст внутри одного
log
элемента. Итак, вы можете захотеть написать некоторый код на языке программирования, который упрощает обработку текста и получение XML в качестве выходных данных. У вас есть несколько вариантов: Perl, Java, …3. @Cobra_Fast, спасибо. Я уже написал комментарии к вашему ответу, но, похоже, вы его удалили. Вы можете проанализировать XML-файлы, чтобы получить другие XML-файлы.
4. @MacroS, спасибо. XML-файл на самом деле очень большой, и я предоставил здесь только один узел, который мне нужно проанализировать. Я использую xslt, потому что я получаю другую информацию от других узлов, которая мне также нужна для результирующих XML-файлов.
5.Если вам требуется использовать чистый XSLT для выполнения той задачи, которая у вас есть с XSLT 2.0
tokenize()
. Можете ли вы использовать XSLT 2.0?
Ответ №1:
XSLT — неподходящая технология для этой задачи. XSLT великолепно преобразует структуру XML-документов (обычно в другой XML-документ, но преобразование XML в текст также возможно). XSLT не подходит для синтаксического анализа текста и манипулирования им.
У вас есть некоторый структурированный текст, который случайно находится внутри XML-элемента.
Я бы выбрал другой метод преобразования, регулярное выражение или простые методы синтаксического анализа строк.
Комментарии:
1. Я обновил первоначальный вопрос информацией, почему я использую xslt.
2. Я понимаю вашу точку зрения, но текущий вопрос OP был очень выполним. XSLT 2.0 действительно недооценен в задачах регулярных выражений. Смотрите мой ответ.
Ответ №2:
Следующий XSLT демонстрирует, как разделить log
содержимое в токенах, просто используя tokenize()
. Вероятно, есть лучшие варианты с XSLT 2.0 (например xsl:analyze-string
), но из-за использования tokenize()
только это решение применимо также к XSLT 1.0, расширенному с помощью шаблонов EXSLT.
XSLT 2.0 протестирован на Saxon-B 9.0.0.2J
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/">
<xml>
<xsl:variable name="string" select="."/>
<xsl:variable name="pass" select="tokenize($string,'Passed -ID:')[not(position()=1)]"/>
<xsl:for-each select="$pass">
<xsl:choose>
<xsl:when test="contains(.,'Failed -ID:')">
<xsl:variable name="failure" select="tokenize(.,'Failed -ID:')"/>
<xsl:for-each select="$failure">
<xsl:choose>
<xsl:when test="position()=1">
<testcase name="{tokenize(.,'s-Log:')[1]}"/>
</xsl:when>
<xsl:otherwise>
<xsl:variable name="tc" select="tokenize(.,'s-Log:')"/>
<testcase name="{$tc[1]}">
<failure message="{$tc[2]}"/>
</testcase>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</xsl:when>
<xsl:otherwise>
<testcase name="{tokenize(.,'s-Log:')[1]}"/>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
<xsl:apply-templates/>
</xml>
</xsl:template>
<xsl:template match="log"/>
</xsl:stylesheet>
Приведенный выше XSLT применен к следующему входному:
<log>Passed -ID:1 -Log:
Passed -ID:2 -Log:Suite
File/Folder
Failed -ID:3 -Log:Suite
Validate Install Failed
Passed -ID:4 -Log:
Failed -ID:5 -Log:aaaaaa
Failed -ID:6 -Log:dfsfsdf
Failed -ID:7 -Log:dsfsfs
fsdfsdfsdfsdfs
Passed -ID:8 -Log:dfsdfsf
Failed -ID:9 -Log:dfsdfs
</log>
Выдает следующий вывод:
<xml>
<testcase name="1"/>
<testcase name="2"/>
<testcase name="3">
<failure message="Suiteamp;#xA;Validate Install Failedamp;#xA;"/>
</testcase>
<testcase name="4"/>
<testcase name="5">
<failure message="aaaaaaamp;#xA;"/>
</testcase>
<testcase name="6">
<failure message="dfsfsdfamp;#xA;"/>
</testcase>
<testcase name="7">
<failure message="dsfsfsamp;#xA;fsdfsdfsdfsdfsamp;#xA;"/>
</testcase>
<testcase name="8"/>
<testcase name="9">
<failure message="dfsdfsamp;#xA;"/>
</testcase>
</xml>
Обратите внимание, что amp;#xA;
это связано с появлением перевода строк исходного текста, поскольку мы помещаем содержимое внутри значения атрибута. Чтобы избавиться от этого, было бы лучше включить сообщение в качестве содержимого элемента failure
. В любом случае, в следующей статье рассматриваются сложные пробелы.