第14章 Smooks の拡張
14.1. Smooks の API リンクのコピーリンクがクリップボードにコピーされました!
API
既存のすべての Smooks 機能 (Java バインド、EDI 処理など) は、明確に定義された多くの API の拡張によって構築されています。
- リーダー API
- ソース/入力データ (リーダー) を処理して、すべてのメッセージフラグメントとサブフラグメントに明確に定義された一連の階層イベント (SAX イベントモデルに基づく) として他の Smooks コンポーネントによって消費できるようにするためのもの。
- ビジター API
- ソース/入力リーダーによって生成されたメッセージフラグメント SAX イベントを消費するためのもの。
14.2. Smooks コンポーネントの設定 リンクのコピーリンクがクリップボードにコピーされました!
SmooksResourceConfiguration インスタンスを使用して設定された resources です。
14.3. namespace 固有の設定 リンクのコピーリンクがクリップボードにコピーされました!
SmooksResourceConfiguration クラスに直接マッピングされる設定) は、基本設定 namespace (http://www.milyn.org/xsd/smooks-1.1.xsd)。
14.4. namespace 固有の設定例 リンクのコピーリンクがクリップボードにコピーされました!
<smooks-resource-list xmlns="http://www.milyn.org/xsd/smooks-1.1.xsd">
<resource-config selector="">
<resource></resource>
<param name=""></param>
</resource-config>
</smooks-resource-list>
selector属性は、リソースを選択する機能です (たとえば、ビジター実装の XPath にすることができます)。resource要素は実際のリソースです。これは、Java クラス名またはテンプレートなどの他の形式のリソースにすることができます。このセクションの残りの部分では、リソースは Java クラス名であると想定されます。param要素は、resource 要素に定義されたリソースの設定パラメーターです。
14.5. ランタイム表現 リンクのコピーリンクがクリップボードにコピーされました!
14.6. 設定アノテーション リンクのコピーリンクがクリップボードにコピーされました!
<param> 要素の詳細を設定する必要があります。これは、@ConfigParam および @Config アノテーションを使用すると、実行されます。
14.7. @ConfigParam アノテーション リンクのコピーリンクがクリップボードにコピーされました!
@ConfigParam アノテーションは、アノテーション付きのプロパティ自身と同じ名前を持つ <param> 要素から名前付きパラメーターを反射的に注入します。名前は異なる場合がありますが、デフォルトの動作はコンポーネントプロパティーの名前に一致します。
14.8. @ConficParam の利点 リンクのコピーリンクがクリップボードにコピーされました!
- <param> 値をアノテーション付きのコンポーネントプロパティーに設定する前に、そのデコードを処理します。Smooks は、すべての主要な型 (int、Double、File、Enum など) に DataDecoder を提供しますが、すぐに使用できるデコーダーが特定のデコード要件をカバーしていない場合は、カスタム DataDecoder を実装および使用できます (例:
@ConfigParam(decoder = MyQuirkyDataDecoder.class))。カスタムデコーダーが登録されている場合、Smooks はカスタムデコーダーを自動的に使用します (つまり、このアノテーションでデコーダープロパティーを定義する必要はありません)。Smooks が、特定のデータ型をデコードするために、DataDecoder 実装を自動的に見つけられるように、DataDecoder 実装を登録する方法の詳細については、DataDecoder Javadocs を参照してください。 configプロパティのchoice制約をサポートし、設定値が定義された選択値の 1 つではない場合、設定例外を生成します。たとえば、ONとOFFの制約付きの値セットを持つプロパティーがあるとします。このアノテーションの Choice プロパティーを使用して、設定を制約したり、例外を発生させたりすることができます。(たとえば、@ConfigParam(choice = {"ON", "OFF"})です。)@ConfigParam(defaultVal = "true")など、デフォルトの設定値を指定できます。@ConfigParam(use = Use.OPTIONAL)など、プロパティー設定値が必須かオプションかを指定できます。デフォルトでは、すべてのプロパティーは、REQUIREDですが、defaultValを設定すると、プロパティーは、OPTIONALと暗黙的にマークされます。
14.9. @ConfigParam アノテーションの使用 リンクのコピーリンクがクリップボードにコピーされました!
DataSeeder とそれに対応する Smooks 設定を示しています。
public class DataSeeder
{
@ConfigParam
private File seedDataFile;
public File getSeedDataFile()
{
return seedDataFile;
}
// etc...
}
<smooks-resource-list xmlns="http://www.milyn.org/xsd/smooks-1.1.xsd">
<resource-config selector="dataSeeder">
<resource>com.acme.DataSeeder</resource>
<param name="seedDataFile">./seedData.xml</param>
</resource-config>
</smooks-resource-list>
14.10. @Config アノテーション リンクのコピーリンクがクリップボードにコピーされました!
@Config アノテーションは、コンポーネントリソースに関連付けられた完全な SmooksResourceConfiguration インスタンスをアノテーション付きのコンポーネントプロパティに反射的に注入します。タイプ SmooksResourceConfiguration ではないコンポーネントプロパティーにこのアノテーションを追加すると、エラーが発生します。
14.11. @Config アノテーションの使用 リンクのコピーリンクがクリップボードにコピーされました!
public class MySmooksComponent
{
@Config
private SmooksResourceConfiguration config;
// etc...
14.12. @Initialize と @Uninitialize リンクのコピーリンクがクリップボードにコピーされました!
@Initialize アノテーションを提供しています。
@Uninitialize アノテーションを提供しています。
14.13. 基本的な初期化/初期化解除シーケンス リンクのコピーリンクがクリップボードにコピーされました!
smooks = new Smooks(..);
// Initialize all annotated components
@Initialize
// Use the smooks instance through a series of filterSource invocations...
smooks.filterSource(...);
smooks.filterSource(...);
smooks.filterSource(...);
... etc ...
smooks.close();
// Uninitialize all annotated components
@Uninitialize
14.14. @Initialize と @Uninitialize の使用 リンクのコピーリンクがクリップボードにコピーされました!
概要
この例では、初期化時にデータベースへの複数の接続を開いて、Smooks インスタンスを閉じる際、それらのデータベースリソースをすべて解放する必要があるコンポーネントがあるとします。
public class MultiDataSourceAccessor
{
@ConfigParam
private File dataSourceConfig;
Map<String, Datasource> datasources = new HashMap<String, Datasource>();
@Initialize
public void createDataSources()
{
// Add DS creation code here....
// Read the dataSourceConfig property to read the DS configs...
}
@Uninitialize
public void releaseDataSources()
{
// Add DS release code here....
}
// etc...
}
@Initialize および @Uninitialize アノテーションを使用する場合は、次の点に注意する必要があります。
@Initializeおよび@Uninitializeメソッドは、引数なしのパブリックメソッドである必要があります。@ConfigParamプロパティーは、最初の@Initializeメソッドが呼び出される前に、すべて初期化されます。したがって、@ConfigParamコンポーネントプロパティーを初期化プロセスへの入力として使用できます。@Uninitializeメソッドは、すべてSmooks.closeメソッドの呼び出しに応答して、呼び出されます。
14.15. カスタム設定 namespace の定義 リンクのコピーリンクがクリップボードにコピーされました!
<resource-config> 基本設定を使用して、検証可能なコンポーネントの XSD ベースのカスタム設定をすべて一般的な Smooks リソースとして扱うのではなく、サポートできます。
14.16. カスタム設定 namespace の使用 リンクのコピーリンクがクリップボードにコピーされました!
- 基本 http://www.milyn.org/xsd/smooks-1.1.xsd 設定 namespace を拡張するコンポーネントの設定 XSD を記述します。この XSD は、コンポーネントのクラスパスで提供する必要があります。
/META-INF/フォルダーに配置され、namespace URI と同じパスを持つ必要があります。たとえば、拡張 namespace URI が http://www.acme.com/schemas/smooks/acme-core-1.0.xsd の場合は、/META-INF/schemas/smooks/acme-core-1.0.xsdのクラスパスに物理 XSD ファイルを指定する必要があります。 - カスタム namespace 設定を
SmooksResourceConfigurationインスタンスにマッピングする Smooks 設定 namespace マッピング設定ファイルを記述します。このファイルは、マッピングする namespace の名前に基づいて (慣例により)、名前を付ける必要があり、XSD と同じフォルダー内のクラスパスに物理的に配置する必要があります。上記の例を拡張すると、Smooks マッピングファイルは、/META-INF/schemas/smooks/acme-core-1.0.xsd-smooks.xmlになります。-smooks.xml接尾辞に注意してください。
14.17. ソースリーダーの実装 リンクのコピーリンクがクリップボードにコピーされました!
org.xml.sax.XMLReader インターフェイスを実装していることです。ただし、リーダー実装を設定できるようにする場合は、リーダーが、org.milyn.xml.SmooksXMLReader インターフェースを実装する必要があります。org.milyn.xml.SmooksXMLReader は org.xml.sax.XMLReader の拡張です。既存の org.xml.sax.XMLReader 実装を使用することも、新しいものを実装することも簡単です。
14.18. Smooks で使用するソースリーダーの実装 リンクのコピーリンクがクリップボードにコピーされました!
- 次のように、まず、基本的なリーダークラスを実装する必要があります。
public class MyCSVReader implements SmooksXMLReader { // Implement all of the XMLReader methods... }特に興味深いものは、org.xml.sax.XMLReaderインターフェイスの 2 つのメソッドです。setContentHandler(ContentHandler)は Smooks Core によって呼び出されます。リーダーのorg.xml.sax.ContentHandlerインスタンスを設定します。org.xml.sax.ContentHandlerインスタンスメソッドは、parse(InputSource)メソッド内から呼び出されます。parse(InputSource): これは、ソースデータ入力ストリームを受け取り、解析し (つまり、この例の場合は、CSVストリーム)、setContentHandler(ContentHandler)メソッドで提供されるorg.xml.sax.ContentHandlerインスタンスの呼び出しで SAX イベントストリームを生成するメソッドです。
詳細については、http://download.oracle.com/javase/6/docs/api/org/xml/sax/ContentHandler.html を参照してください。 - CSV レコードに関連付けられたフィールドの名前を使用して、CSV リーダーを設定します。カスタムリーダー実装の設定は、いずれの Smooks コンポーネントでも同じです。以下の例を参照してください。
public class MyCSVReader implements SmooksXMLReader { private ContentHandler contentHandler; @ConfigParam private String[] fields; // Auto decoded and injected from the "fields" <param> on the reader config. public void setContentHandler(ContentHandler contentHandler) { this.contentHandler = contentHandler; } public void parse(InputSource csvInputSource) throws IOException, SAXException { // TODO: Implement parsing of CSV Stream... } // Other XMLReader methods... } - 基本的なリーダー実装スタブができると、単体テストの作成を開始して、新しいリーダー実装をテストできます。これを行うには、CSV 入力が必要です。
names.csvという名前のファイル内の名前の単純なリストを特徴とする以下の例を確認してください。Tom,Jones Mike,Jones Mark,Jones - テスト Smooks 設定を使用して、MyCSVReader で Smooks を設定します。前述のとおり、Smooks では、すべてがリソースであり、基本的な
<resource-config>設定を行うことができます。これは、問題なく動作しますが、少し「うるさい」ため、Smooks は、特にリーダーを設定するために、基本的な<reader>設定要素を提供しています。テストの設定は、mycsvread-config.xmlで次のようになります。<smooks-resource-list xmlns="http://www.milyn.org/xsd/smooks-1.1.xsd"> <reader class="com.acme.MyCSVReader"> <params> <param name="fields">firstname,lastname</param> </params> </reader> </smooks-resource-list> - JUnit テストクラスを実装します。
public class MyCSVReaderTest extends TestCase { public void test() { Smooks smooks = new Smooks(getClass().getResourceAsStream("mycsvread-config.xml")); StringResult serializedCSVEvents = new StringResult(); smooks.filterSource(new StreamSource(getClass().getResourceAsStream("names.csv")), serializedCSVEvents); System.out.println(serializedCSVEvents); // TODO: add assertions etc } } parseメソッドを実装します。public class MyCSVReader implements SmooksXMLReader { private ContentHandler contentHandler; @ConfigParam private String[] fields; // Auto decoded and injected from the "fields" <param> on the reader config. public void setContentHandler(ContentHandler contentHandler) { this.contentHandler = contentHandler; } public void parse(InputSource csvInputSource) throws IOException, SAXException { BufferedReader csvRecordReader = new BufferedReader(csvInputSource.getCharacterStream()); String csvRecord; // Send the start of message events to the handler... contentHandler.startDocument(); contentHandler.startElement(XMLConstants.NULL_NS_URI, "message-root", "", new AttributesImpl()); csvRecord = csvRecordReader.readLine(); while(csvRecord != null) { String[] fieldValues = csvRecord.split(","); // perform checks... // Send the events for this record... contentHandler.startElement(XMLConstants.NULL_NS_URI, "record", "", new AttributesImpl()); for(int i = 0; i < fields.length; i++) { contentHandler.startElement(XMLConstants.NULL_NS_URI, fields[i], "", new AttributesImpl()); contentHandler.characters(fieldValues[i].toCharArray(), 0, fieldValues[i].length()); contentHandler.endElement(XMLConstants.NULL_NS_URI, fields[i], ""); } contentHandler.endElement(XMLConstants.NULL_NS_URI, "record", ""); csvRecord = csvRecordReader.readLine(); } // Send the end of message events to the handler... contentHandler.endElement(XMLConstants.NULL_NS_URI, "message-root", ""); contentHandler.endDocument(); } // Other XMLReader methods... }- 単体テストクラスを実行して、コンソールに次の出力を表示します (フォーマット済み)。
<message-root> <record> <firstname>Tom</firstname> <lastname>Jones</lastname> </record> <record> <firstname>Mike</firstname> <lastname>Jones</lastname> </record> <record> <firstname>Mark</firstname> <lastname>Jones</lastname> </record> </message-root>この後は、テストの拡張、リーダー実装コードの強化などのケースです。その後、リーダーを使用して、Smooks でサポートされているさまざまな操作を実行できます。
14.19. java-binding-config.xml を使用したリーダーの設定例 リンクのコピーリンクがクリップボードにコピーされました!
java-binding-config.xml) を使用すると、名前を PersonName オブジェクトのList にバインドできます。
<smooks-resource-list xmlns="http://www.milyn.org/xsd/smooks-1.1.xsd" xmlns:jb="http://www.milyn.org/xsd/smooks/javabean-1.4.xsd">
<reader class="com.acme.MyCSVReader">
<params>
<param name="fields">firstname,lastname</param>
</params>
</reader>
<jb:bean beanId="peopleNames" class="java.util.ArrayList" createOnElement="message-root">
<jb:wiring beanIdRef="personName" />
</jb:bean>
<jb:bean beanId="personName" class="com.acme.PersonName" createOnElement="message-root/record">
<jb:value property="first" data="record/firstname" />
<jb:value property="last" data="record/lastname" />
</jb:bean>
</smooks-resource-list>
public class MyCSVReaderTest extends TestCase
{
public void test_java_binding()
{
Smooks smooks = new Smooks(getClass().getResourceAsStream("java-binding-config.xml"));
JavaResult javaResult = new JavaResult();
smooks.filterSource(new StreamSource(getClass().getResourceAsStream("names.csv")), javaResult);
List<PersonName> peopleNames = (List<PersonName>) javaResult.getBean("peopleNames");
// TODO: add assertions etc
}
}
14.20. リーダーを使用するためのヒント リンクのコピーリンクがクリップボードにコピーされました!
- リーダーインスタンスが同時に使用されることはありません。Smooks Coreは、メッセージごとに新しいインスタンスを作成するか、
readerPoolSizeFilterSettingsプロパティに従って、インスタンスをプールおよび再利用します。 - リーダーは、現在のフィルタリングコンテキストの Smooks
ExecutionContextにアクセスする必要がある場合、org.milyn.xml.SmooksXMLReaderインターフェイスを実装する必要があります。 - ソースデータがバイナリーデータストリームである場合、リーダーは、
org.milyn.delivery.StreamReaderインターフェイスを実装する必要があります。 GenericReaderConfiguratorインスタンスを使用して、ソースコード (単体テストなど) 内でリーダーを設定し、Smooksインスタンスに設定できます。- 基本的な <reader> 設定は問題ありませんが、カスタム CSV リーダー実装用にカスタム設定 namespace (XSD) を定義できます。このトピックは、ここでは扱いません。ソースコードを確認して、Smooks に付属するリーダー実装の拡張設定 namespace (
EDIReader、CSVReader、JSONReaderなど) を確認します。これから、独自のカスタムリーダーでこれを行う方法を考え出すことができるはずです。
14.21. バイナリーソースリーダー リンクのコピーリンクがクリップボードにコピーされました!
org.milyn.delivery.StreamReader インターフェイスを実装する必要があります。これは、InputStream が提供されるように、Smooks ランタイムに指示する単なるマーカーインターフェイスです。
parse メソッドの実装が、InputSource からのInputStream を使用し (つまり、InputSource.getCharacterStream() ではなく、InputSource..getByteStream() を呼び出し)、デコードされたバイナリーデータから XML イベントを生成する必要がある点では異なります。
14.22. バイナリーソースリーダーの実装 リンクのコピーリンクがクリップボードにコピーされました!
- バイナリーソースリーダーを実装するには、次の
parseメソッド実装を確認してください。public static class BinaryFormatXXReader implements SmooksXMLReader, StreamReader { @ConfigParam private String xProtocolVersion; @ConfigParam private int someOtherXProtocolConfig; // etc... public void parse(InputSource inputSource) throws IOException, SAXException { // Use the InputStream (binary) on the InputSource... InputStream binStream = inputSource.getByteStream(); // Create and configure the data decoder... BinaryFormatXDecoder xDecoder = new BinaryFormatXDecoder(); xDecoder.setProtocolVersion(xProtocolVersion); xDecoder.setSomeOtherXProtocolConfig(someOtherXProtocolConfig); xDecoder.setXSource(binStream); // Generate the XML Events on the contentHandler... contentHandler.startDocument(); // Use xDecoder to fire startElement, endElement etc events on the contentHandler (see previous section)... contentHandler.endDocument(); } // etc.... } - 他のリーダーと同様、Smooks 設定に
BinaryFormatXXReaderリーダーを設定します。<smooks-resource-list xmlns="http://www.milyn.org/xsd/smooks-1.1.xsd"> <reader class="com.acme.BinaryFormatXXReader"> <params> <param name="xProtocolVersion">2.5.7</param> <param name="someOtherXProtocolConfig">1</param> ... etc... </params> </reader> ... Other Smooks configurations e.g. <jb:bean> configs for binding the binary data into Java objects... </smooks-resource-list> - Smooks の実行コードを実行します (
StreamSourceに提供されるInputStreamに注意してください)。この場合、XML オブジェクトと Java オブジェクトの 2 つの結果が生成されます。StreamResult xmlResult = new StreamResult(xmlOutWriter); JavaResult javaResult = new JavaResult(); InputStream xBinaryInputStream = getXByteStream(); smooks.filterSource(new StreamSource(xBinaryInputStream), xmlResult, javaResult); // etc... Use the beans in the javaResult...
14.23. ビジター実装 リンクのコピーリンクがクリップボードにコピーされました!
ExecutionContext および ApplicationContext コンテキストオブジェクトでコラボレーションして、共通の目標を達成します。
14.24. サポート対象のビジター実装 リンクのコピーリンクがクリップボードにコピーされました!
org.milyn.delivery.sax.SAXVisitorサブインターフェイスに基づく SAX ベースの実装。org.milyn.delivery.dom.DOMVisitorサブインターフェイスに基づく DOM ベースの実装。
14.25. SAX と DOM のビジター実装 リンクのコピーリンクがクリップボードにコピーされました!
Smooks.filterSource メソッドの複数の同時呼び出しで同時に使用できる必要があります。現在の Smooks.filterSource 実行に関連するすべての状態は、ExecutionContext に保存する必要があります。
14.26. SAX ビジター API リンクのコピーリンクがクリップボードにコピーされました!
SAXVisitor 実装が取得および処理できる org.xml.sax.ContentHandler SAX イベントに基づいています。SAXVisitor 実装によって解決されるユースケースに応じて、これらのインターフェイスの 1 つまたはすべてを実装する必要がある場合があります。
14.27. SAX ビジター API インターフェイス リンクのコピーリンクがクリップボードにコピーされました!
org.milyn.delivery.sax.SAXVisitBefore- 対象のフラグメント要素の
startElementSAX イベントを取得します。public interface SAXVisitBefore extends SAXVisitor { void visitBefore(SAXElement element, ExecutionContext executionContext) throws SmooksException, IOException; } org.milyn.delivery.sax.SAXVisitChildren- 対象のフラグメント要素の文字ベースの SAX イベント、および子フラグメント要素の
startElementイベントに対応する Smooks 生成 (疑似) イベントを取得します。public interface SAXVisitChildren extends SAXVisitor { void onChildText(SAXElement element, SAXText childText, ExecutionContext executionContext) throws SmooksException, IOException; void onChildElement(SAXElement element, SAXElement childElement, ExecutionContext executionContext) throws SmooksException, IOException; } org.milyn.delivery.sax.SAXVisitAfter- 対象のフラグメント要素の
endElementSAX イベントを取得します。public interface SAXVisitAfter extends SAXVisitor { void visitAfter(SAXElement element, ExecutionContext executionContext) throws SmooksException, IOException; }
14.28. SAX ビジター API の例 リンクのコピーリンクがクリップボードにコピーされました!
XML を使用した API イベントの図解
これにより、3 つのインターフェイスが org.milyn.delivery.sax.SAXElementVisitor インターフェイス内で 1 つのインターフェイスにまとめられます。
<message>
<target-fragment> <!-- SAXVisitBefore.visitBefore -->
Text!! <!-- SAXVisitChildren.onChildText -->
<child> <!-- SAXVisitChildren.onChildElement -->
</child>
</target-fragment> <!-- SAXVisitAfter.visitAfter -->
</message>
org.milyn.delivery.sax.SAXElement タイプは、すべてのメソッド呼び出しで渡されます。このオブジェクトには、属性とその値を含む、対象のフラグメント要素に関する詳細が含まれています。また、テキストの蓄積を管理するためのメソッド、および Smooks.filterSource(Source, Result) メソッド呼び出しで渡された可能性がある StreamResult インスタンスに関連する Writer へのアクセスが含まれています。
14.29. SAX によるテキスト蓄積 リンクのコピーリンクがクリップボードにコピーされました!
14.30. org.milyn.delivery.sax.SAXElement リンクのコピーリンクがクリップボードにコピーされました!
org.milyn.delivery.sax.SAXElement は、常に対象の要素に関連する属性データを含みますが、フラグメントの子テキストデータを含みません。SAX イベント (SAXVisitChildren.onChildText) が SAXVisitBefore.visitBefore イベントと SAXVisitAfter.visitAfter イベントの間に発生します。テキストイベントは、SAXElement に蓄積されません。その結果、パフォーマンスが大幅に低下する可能性があるためです。この欠点は、SAXVisitor 実装がフラグメントのテキストコンテンツにアクセスする必要がある場合、対象のフラグメントのテキストを蓄積するように、Smooks に明示的に指示する必要があることです。これは、SAXVisitor の SAXVisitBefore.visitBefore メソッド実装内から SAXElement.accumulateText メソッドを呼び出すと、実行されます。
14.31. テキスト蓄積の例 リンクのコピーリンクがクリップボードにコピーされました!
public class MyVisitor implements SAXVisitBefore, SAXVisitAfter
{
public void visitBefore(SAXElement element, ExecutionContext executionContext)
throws SmooksException, IOException
{
element.accumulateText();
}
public void visitAfter(SAXElement element, ExecutionContext executionContext)
throws SmooksException, IOException
{
String fragmentText = element.getTextContent();
// ... etc ...
}
}
14.32. @TextConsumer アノテーション リンクのコピーリンクがクリップボードにコピーされました!
@TextConsumer アノテーションは、SAXVisitBefore.visitBefore メソッドを使用する代わりに、SAXVisitor 実装をアノテーションするために、使用することができます。
14.33. @TextConsumer の例 リンクのコピーリンクがクリップボードにコピーされました!
@TextConsumer
public class MyVisitor implements SAXVisitAfter
{
public void visitAfter(SAXElement element, ExecutionContext executionContext)
throws SmooksException, IOException
{
String fragmentText = element.getTextContent();
// ... etc ...
}
}
SAXVisitAfter.visitAfter イベントの終了後、公開されます。
14.34. StreamResult の書き込み/シリアル化 リンクのコピーリンクがクリップボードにコピーされました!
概要
Smooks.filterSource(Source, Result) メソッドは、多くの異なる Result 型実装のうちの 1 つ以上を取ることができ、そのうちの 1 つが javax.xml.transform.stream.StreamResult クラスです。Smooks は、StreamResult インスタンスでソースを流入させ、再び流出させます。
Smooks.filterSource(Source, Result) メソッドに提供される任意の StreamResult インスタンスにシリアル化します。Smooks.filterSource(Source, Result) メソッドに提供されたソースが XML ストリームであり、StreamResult インスタンスが Result インスタンスの 1 つとして提供された場合は、Smooks インスタンスが 1 つ以上のフラグメントを変更する 1 つ以上の SAXVisitor 実装で設定されていないかぎり、ソース XML は未変更の StreamResult に書き出されます。
14.35. StreamResult の書き込み/シリアル化の設定 リンクのコピーリンクがクリップボードにコピーされました!
- デフォルトのシリアル化動作をオンまたはオフにするには、フィルター設定にアクセスし、そのように設定します。
- メッセージフラグメントの 1 つのシリアル化された形式を変更するには、
SAXVisitorを実装して、変換を実行し、XPath のような式を使用して、メッセージフラグメントをターゲットとします。 - メッセージフラグメントのシリアル化された形式を変更するには、提供されているテンプレートコンポーネントのいずれかを使用します。これらのコンポーネントは、
SAXVisitor実装でもあります。
14.36. SAXVisitor の実装 リンクのコピーリンクがクリップボードにコピーされました!
- フラグメントのシリアル化された形式を変換するための
SAXVisitorを実装するには、SAXVisitor実装がStreamResultに書き込まれるように、Smooks をプログラミングします。これは、Smooks が 1 つのフラグメントで複数のSAXVisitor実装のターゲティングをサポートしているためですが、フラグメントごとにStreamResultに書き込むことができるSAXVisitorは、1 つだけです。 - 2 つ目の
SAXVisitorがStreamResultに書き込もうとすると、SAXWriterAccessExceptionが発生し、Smooks 設定を変更する必要があります。 - 記述する
StreamResultを指定するには、SAXVisitorが、StreamResultへのWriterの所有権を取得する必要があります。これは、SAXVisitBefore.visitBeforeメソッド実装内から、SAXElement.getWriter(SAXVisitor)メソッドを呼び出し、thisをSAXVisitorパラメーターとして渡すと、実行されます。
14.37. SAXVisitor の実装例 リンクのコピーリンクがクリップボードにコピーされました!
public class MyVisitor implements SAXElementVisitor
{
public void visitBefore(SAXElement element, ExecutionContext executionContext)
throws SmooksException, IOException
{
Writer writer = element.getWriter(this);
// ... write the start of the fragment...
}
public void onChildText(SAXElement element, SAXText childText,
ExecutionContext executionContext)
throws SmooksException, IOException
{
Writer writer = element.getWriter(this);
// ... write the child text...
}
public void onChildElement(SAXElement element, SAXElement childElement,
ExecutionContext executionContext)
throws SmooksException, IOException
{
}
public void visitAfter(SAXElement element, ExecutionContext executionContext)
throws SmooksException, IOException
{
Writer writer = element.getWriter(this);
// ... close the fragment...
}
}
14.38. SAXElement.setWriter リンクのコピーリンクがクリップボードにコピーされました!
Writer インスタンスをリセットするために必要なサブフラグメントのシリアル化を制御できるため、サブフラグメントのシリアル化を流用できます。
Writer の所有権を獲得するための SAXElement.getWriter メソッドを呼び出すためだけに、SAXVisitBefore.visitBefore メソッドを実装することは非効率的です。このため、@StreamResultWriter アノテーションがあります。@TextConsumer アノテーションと組み合わせて使用すると、SAXVisitAfter.visitAfter メソッドを実装するだけで十分です。
14.39. StreamResultWriter の例 リンクのコピーリンクがクリップボードにコピーされました!
@StreamResultWriter
public class MyVisitor implements SAXVisitAfter
{
public void visitAfter(SAXElement element, ExecutionContext executionContext)
throws SmooksException, IOException
{
Writer writer = element.getWriter(this);
// ... serialize to the writer ...
}
}
14.40. SAXToXMLWriter リンクのコピーリンクがクリップボードにコピーされました!
SAXToXMLWriter クラスを提供します。SAXElement データを XML としてシリアル化するプロセスを簡素化します。このクラスでは、SAXVisitor 実装を記述できます。
14.41. SAXToXMLWriter の例 リンクのコピーリンクがクリップボードにコピーされました!
@StreamResultWriter
public class MyVisitor implements SAXElementVisitor
{
private SAXToXMLWriter xmlWriter = new SAXToXMLWriter(this, true);
public void visitBefore(SAXElement element, ExecutionContext executionContext)
throws SmooksException, IOException
{
xmlWriter.writeStartElement(element);
}
public void onChildText(SAXElement element, SAXText childText, ExecutionContext
executionContext) throws SmooksException, IOException
{
xmlWriter.writeText(childText, element);
}
public void onChildElement(SAXElement element, SAXElement childElement,
ExecutionContext executionContext) throws SmooksException, IOException
{
}
public void visitAfter(SAXElement element, ExecutionContext executionContext)
throws SmooksException, IOException
{
xmlWriter.writeEndElement(element);
}
}
14.42. SAXToXMLWriter の設定 リンクのコピーリンクがクリップボードにコピーされました!
SAXToXMLWriterでSAXVisitor実装を記述する場合は、SAXToXMLWriterコンストラクターにブール値を設定します。encodeSpecialCharsargであり、rewriteEntitiesフィルター設定に基づいて、設定する必要があります。@StreamResultWriterアノテーションをクラスからSAXToXMLWriterインスタンス宣言に移動します。この結果、Smooks は、SAXToXMLWriterインスタンスを作成し、関連する Smooks インスタンスのrewriteEntitiesフィルター設定で初期化されます。@TextConsumer public class MyVisitor implements SAXVisitAfter { @StreamResultWriter private SAXToXMLWriter xmlWriter; public void visitAfter(SAXElement element, ExecutionContext executionContext) throws SmooksException, IOException { xmlWriter.writeStartElement(element); xmlWriter.writeText(element); xmlWriter.writeEndElement(element); } }
14.43. ビジター設定 リンクのコピーリンクがクリップボードにコピーされました!
SAXVisitor 設定は、テスト目的に役立ち、他の Smooks コンポーネントとまったく同様に機能します。Smooks ビジターインスタンスを設定する場合は、設定 selector は、XPath 式と同様に解釈されます。ビジターインスタンスは、Smooks インスタンスのプログラムコード内で設定できます。
14.44. ビジター設定の例 リンクのコピーリンクがクリップボードにコピーされました!
SAXVisitor 実装を使用します。
@TextConsumer
public class ChangeItemState implements SAXVisitAfter
{
@StreamResultWriter
private SAXToXMLWriter xmlWriter;
@ConfigParam
private String newState;
public void visitAfter(SAXElement element, ExecutionContext executionContext)
throws SmooksException, IOException
{
element.setAttribute("state", newState);
xmlWriter.writeStartElement(element);
xmlWriter.writeText(element);
xmlWriter.writeEndElement(element);
}
}
OK の<order-item> フラグメントをトリガーするように、ChangeItemState を宣言的に設定すると、次のようになります。
<smooks-resource-list
xmlns="http://www.milyn.org/xsd/smooks-1.1.xsd">
<resource-config selector="order-items/order-item[@status = 'OK']">
<resource>com.acme.ChangeItemState </resource>
<param name="newState">COMPLETED</param>
</resource-config>
</smooks-resource-list>
ChangeItemState コンポーネントに定義できます。カスタム設定 namespace コンポーネントは次のように設定されます。
<smooks-resource-list xmlns="http://www.milyn.org/xsd/smooks-1.1.xsd"
xmlns:order="http://www.acme.com/schemas/smooks/order.xsd">
<order:changeItemState itemElement="order-items/order-item[@status = 'OK']"
newState="COMPLETED" />
</smooks-resource-list>
Smooks smooks = new Smooks();
smooks.addVisitor(new ChangeItemState().setNewState("COMPLETED"),
"order-items/order-item[@status = 'OK']");
smooks.filterSource(new StreamSource(inReader), new StreamResult(outWriter));
14.45. ExecutionLifecycleCleanable リンクのコピーリンクがクリップボードにコピーされました!
ExecutionLifecycleCleanable ライフサイクルインターフェイスを実装するビジターコンポーネントはポスト Smooks.filterSource ライフサイクル操作を実行できます。以下の例を参照してください。
public interface ExecutionLifecycleCleanable extends Visitor
{
public abstract void executeExecutionLifecycleCleanup(
ExecutionContext executionContext);
}
executeExecutionLifecycleCleanup 呼び出しに注意)。
smooks = new Smooks(..);
smooks.filterSource(...);
// ** VisitorXX.executeExecutionLifecycleCleanup **
smooks.filterSource(...);
// ** VisitorXX.executeExecutionLifecycleCleanup **
smooks.filterSource(...);
// ** VisitorXX.executeExecutionLifecycleCleanup **
... etc ...
Smooks.filterSource 実行ライフサイクルの周囲にスコープされたリソースを関連する ExecutionContext のためにクリーンアップできます。
14.46. VisitLifecycleCleanable リンクのコピーリンクがクリップボードにコピーされました!
VisitLifecycleCleanable ライフサイクルインターフェイスを実装するビジターコンポーネントはポスト SAXVisitAfter.visitAfter ライフサイクル操作を実行できます。
public interface VisitLifecycleCleanable extends Visitor
{
public abstract void executeVisitLifecycleCleanup(ExecutionContext executionContext);
}
executeVisitLifecycleCleanup 呼び出しに注意)。
smooks.filterSource(...);
<message>
<target-fragment> < --- VisitorXX.visitBefore
Text!! < --- VisitorXX.onChildText
<child> < --- VisitorXX.onChildElement
</child>
</target-fragment> < --- VisitorXX.visitAfter
** VisitorXX.executeVisitLifecycleCleanup **
<target-fragment> < --- VisitorXX.visitBefore
Text!! < --- VisitorXX.onChildText
<child> < --- VisitorXX.onChildElement
</child>
</target-fragment> < --- VisitorXX.visitAfter
** VisitorXX.executeVisitLifecycleCleanup **
</message>
VisitorXX.executeExecutionLifecycleCleanup
smooks.filterSource(...);
<message>
<target-fragment> < --- VisitorXX.visitBefore
Text!! < --- VisitorXX.onChildText
<child> < --- VisitorXX.onChildElement
</child>
</target-fragment> < --- VisitorXX.visitAfter
** VisitorXX.executeVisitLifecycleCleanup **
<target-fragment> < --- VisitorXX.visitBefore
Text!! < --- VisitorXX.onChildText
<child> < --- VisitorXX.onChildElement
</child>
</target-fragment> < --- VisitorXX.visitAfter
** VisitorXX.executeVisitLifecycleCleanup **
</message>
VisitorXX.executeExecutionLifecycleCleanup
SAXVisitor 実装の 1 つのフラグメント実行の周囲にスコープされたリソースを関連する ExecutionContext のためにクリーンアップできます。
14.47. ExecutionContext リンクのコピーリンクがクリップボードにコピーされました!
ExecutionContext は状態情報を保存するためのコンテキストオブジェクトです。Smooks.filterSource メソッドの 1 回の実行に特化して、スコープされています。すべての Smooks ビジター実装は、1 つの Smooks.filterSource 実行のコンテキスト内でステートレスである必要があり、ビジター実装を Smooks.filterSource メソッドの複数の同時実行で使用できるようにします。ExecutionContext インスタンスに保存されているすべてのデータは、Smooks.filterSource 実行の完了時、失われます。ExecutionContext は、すべてのビジター API メッセージイベント呼び出しで提供されます。
14.48. ApplicationContext リンクのコピーリンクがクリップボードにコピーされました!
ApplicationContext は状態情報を保存するためのコンテキストオブジェクトです。関連する Smooks インスタンスの周囲にスコープされます。つまり、1 つの Smooks インスタンスにつき、1 つの ApplicationContext インスタンスのみが存在します。このコンテキストオブジェクトは、複数の Smooks.filterSource 実行で維持およびアクセスする必要があるデータを保存するために、使用できます。コンポーネント (SAXVisitor コンポーネントを含む) は、ApplicationContext クラスプロパティを宣言し、@AppContext アノテーションを付けて、関連する ApplicationContext インスタンスにアクセスできます。以下の例を参照してください。
public class MySmooksComponent
{
@AppContext
private ApplicationContext appContext;
// etc...
}