Martin Honnenが示唆しているように、analyze-stringはここでは良い賭けです。ただし、メッセージの形式は非常に単純なので、XSLT1.0の単純な文字列操作関数と再帰的な名前付きテンプレートよりも複雑なものは必要ありません。これは、何が起こっているのかを説明するコメントが埋め込まれたXSLT1.0スタイルシートです。
スタイルシートの冒頭は完全に従来のものです。
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:output method="xml" indent="yes"/>
エラーメッセージの一部の定数テキストに対して2つの変数を宣言します(これらの長い定数文字列を複数回指定することを避けたい場合を除いて、特別な理由はありません)。
<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>
文字列が空でない場合は、最初の改行で文字列を分割し、2つの部分を変数と:$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のanalyze-string命令はこれよりもコンパクトになり、XSLT 2.0の正規表現により、XSLT1.0ライブラリよりも複雑な処理がはるかに便利になります。(ただし、analyze-stringの使用方法を知っていれば、質問はしませんでした。XSLT1.0のライブラリと言語が小さいことの利点の1つは、1.0の問題を解決する方が、より多くのことを理解するよりも速い場合があることです。 XSLT 2.0の複雑な構成と、それらを単純な問題に適用する方法。これは、もちろん、大小の言語に関する一般的な事実です。)
表示する入力に適用すると、上記のスタイルシートは、表示する出力をほぼ正確に生成します。
<?xml version="1.0"?>
<root><EMAILID>abcdef@gmail.com</EMAILID>
<EMAILID>abcdefgh@gmail.com</EMAILID>
<EMAILID>12345678@gmail.com</EMAILID>
<EMAILID>12345678@gmail.com</EMAILID>
<EMAILID>abcdefgh@gmail.com</EMAILID>
<EMAILID>12345678@gmail.com</EMAILID>
<EMAILID>12345678@gmail.com</EMAILID>
</root>
abcdefgh @ gmail.com@gmail.comの行は含まれていません。おそらくそれは質問のカット/ペーストエラーだと思います。
また、特定の行の電子メールアドレスがすでに送信されているかどうかもチェックしません。それが実際に不可欠である場合は、これまでに抽出されたすべての電子メールアドレスを含む2番目の引数を渡す方法が明らかであることを願っています(空白またはU + A0、または電子メールでは発生しない任意の文字で区切られます)アドレス)、これを使用して、EMAILID要素を発行する前に重複をテストします。