Как говорит Мартин Honnen, анализировать строка является хорошей ставкой здесь. Но формат вашего сообщения настолько прост, что вам не нужно ничего сложнее, чем простые функции манипуляции с строками XSLT 1.0 и рекурсивный именованный шаблон. Вот таблица стилей XSLT 1.0 со встроенными комментариями, чтобы объяснить, что происходит.
Начало таблицы стилей совершенно обычный:
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:output method="xml" indent="yes"/>
Мы объявляем две переменные для некоторых из постоянного текста в сообщении об ошибке (без особой причины, кроме желания, чтобы не дать эти длинные постоянные строки больше один раз):
<xsl:variable name="prefix"
select="' com.sun.mail.smtp.SMTPAddressFailedException: 550 5.1.1 <'"/>
<xsl:variable name="suffix"
select="'>: Recipient address rejected: User unknown in virtual alias table'"/>
root
элемент размножается:
<xsl:template match="root">
<root>
<xsl:apply-templates/>
</root>
</xsl:template>
Элемент Error_Message
передает свое строковое значение указанному шаблону extract-email-addresses
, что делает его название (подробнее см. Ниже).
<xsl:template match="Error_Message">
<xsl:call-template
name="extract-email-addresses">
<xsl:with-param name="s"
select="string(.)"/>
</xsl:call-template>
</xsl:template>
В err_mesage
элемент и текстовые узлы подавляются:
<xsl:template match="err_mesage | text()"/>
extract-email-addresses
Шаблон принимает строку в качестве параметра, который по умолчанию пустая строка.
<xsl:template name="extract-email-addresses">
<xsl:param name="s" select="''"/>
Мы собираемся откусить кусочек строки s
в то время, обрабатывать часть мы откусившие, и повторялись на отдыхе. Итак, первое, что мы делаем, это проверить, закончились ли мы. Если $s
- пустая строка, ничего не остается делать; мы останавливаем рекурсию и позволяем стеку выскочить.
<xsl:choose>
<xsl:when test="$s = ''">
<!--* end of string, we are done. *-->
</xsl:when>
Когда строка не пуста, мы разбиваем строку $s
на первой строки, назначая две части к переменным $s1
и $rest
:
<xsl:otherwise>
<xsl:variable name="s1"
select="substring-before($s,'
')"/>
<xsl:variable name="rest"
select="substring-after($s,'
')"/>
Сейчас мы ищем различные формы линии могу взять.Большинство линий в сообщении об ошибке является шаблонными игнорироваться:
<xsl:choose>
<xsl:when test="$s1 = 'Error sending mail message. Cause: javax.mail.SendFailedException: Invalid Addresses;'">
<!--* this line is of no
* interest, continue *-->
</xsl:when>
<xsl:when test="$s1 = ' nested exception is:'">
<!--* skip this line *-->
</xsl:when>
<xsl:when test="$s1 = ';'">
<!--* skip this line *-->
</xsl:when>
<xsl:when test="$s1 = ''">
<!--* skip this line *-->
</xsl:when>
Когда мы видим строку, начинающиеся с меткой для SMTPAddressFailedException и заканчивая шаблонный об отказе от адреса получателя, мы берем подстроку что происходит после префикса и перед суффиксом, и завернуть его в EMAILID
элемент:
<xsl:when test="starts-with($s1,$prefix)
and
contains($s1,$suffix)">
<EMAILID>
<xsl:value-of select="
substring-before(
substring-after($s1,$prefix),
$suffix)
"/>
</EMAILID>
<xsl:text>
</xsl:text>
</xsl:when>
Если мы видим любую другую форму линии, то вход не как ожидалось, поэтому мы генерируем диагностическое сообщение и сохранить движение:
<xsl:otherwise>
<xsl:message>Unrecognized line: |<xsl:value-of
select="$s1"/>|</xsl:message>
</xsl:otherwise>
</xsl:choose>
Что бы мы ни делали первую линию, мы теперь повторялись обрабатывать оставшуюся часть строки в строке:
<xsl:call-template name="extract-email-addresses">
<xsl:with-param name="s" select="$rest"/>
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
XSLT инструкция 2,0 проанализируют строки, конечно, будет более компактной, чем это , а регулярные выражения XSLT 2.0 делают гораздо более удобным выполнение сложных задач, чем библиотека XSLT 1.0. (Но если вы знали, как использовать аналитическую строку, вы бы не задали ваш вопрос. Одно из преимуществ меньшей библиотеки и языка в XSLT 1.0 заключается в том, что иногда быстрее решать проблему с 1.0, чем понимать больше сложные конструкции XSLT 2.0 и способы их применения к простой проблеме. Конечно, это общий факт о малых и больших языках.)
Применительно к введенному вами вводу, только что указанная таблица производит почти точный вывод вы показываете:
<?xml version="1.0"?>
<root><EMAILID>[email protected]</EMAILID>
<EMAILID>[email protected]</EMAILID>
<EMAILID>[email protected]</EMAILID>
<EMAILID>[email protected]</EMAILID>
<EMAILID>[email protected]</EMAILID>
<EMAILID>[email protected]</EMAILID>
<EMAILID>[email protected]</EMAILID>
</root>
Он не включает строку для abcdefgh @ gmail.com @ gmail.com; Я предполагаю, что, возможно, это ошибка разреза/вставки в вопросе.
Он также не проверяет, не был ли выслан электронный адрес в данной строке; если это необходимо на практике, я надеюсь, что вам очевидно, как передать второй аргумент, содержащий все электронные адреса, извлеченные до сих пор (с разделителями пробелов или U + A0 или любой символ, который вам нравится, не может появиться в электронном письме адрес) и использовать его для проверки дубликатов перед выпуском элемента EMAILID.
Интересное использование для XML-файла. Если вы сами создаете эти XML-файлы, подумайте об их изменении, чтобы они содержали фактические структурированные данные, а не многострочный текст. Если вы не создаете XML, используйте другой инструмент, который лучше подходит для обработки кусков простого текста, то есть языка программирования, отличного от XSLT. – Tomalak
его из исключения JavaEmail, и я должен генерировать недопустимые адреса электронной почты в ожидаемом формате. – user1658369
Можете ли вы хотя бы использовать процессор XSLT 2.0, такой как Saxon 9? В этом случае вы можете попробовать свою удачу с помощью 'xsl: analysis-string'. –