第3章 入力データの消費

Smooks は ストリームリーダー を使用してソースメッセージのデータストリームより SAX イベントのストリームを生成します。ストリームリーダーは XMLReader インターフェース (または SmooksXMLReader インターフェース) を実装するクラスです。
デフォルトでは、Smooks は XMLReader (XMLReaderFactory.createXMLReader()) を使用しますが、XML 以外のデータソースを読み取るよう設定するには、専用の XML リーダーを設定します。
リーダーを設定してハンドラ、機能、 およびパラメータのセットを使用することも可能です。完全な設定例は次の通りです。
<reader class="com.acme.ZZZZReader">
    <handlers>
        <handler class="com.X" />
        <handler class="com.Y" />
    </handlers>
    <features>
        <setOn feature="http://a" />
        <setOn feature="http://b" />
        <setOff feature="http://c" />
        <setOff feature="http://d" />
    </features>
    <params>
        <param name="param1">val1</param>
        <param name="param2">val2</param>
    </params>
</reader>
デフォルトでは、Smooks は XML データを読み取ります。デフォルトの XML リーダーに機能を設定するには、設定のクラス名を省略します。
<reader>
    <features>
        <setOn feature="http://a" />
        <setOn feature="http://b" />
        <setOff feature="http://c" />
        <setOff feature="http://d" />
    </features>
</reader>
CSV リーダーを設定するには、http://www.milyn.org/xsd/smooks/csv-1.2.xsd 設定名前空間を使用します。
基本的な設定は次の通りです。
<?xml version="1.0"?>
<smooks-resource-list xmlns="http://www.milyn.org/xsd/smooks-1.1.xsd" xmlns:csv="http://www.milyn.org/xsd/smooks/csv-1.2.xsd">
 
    <!--
    Configure the CSV to parse the message into a stream of SAX events.
    -->
    <csv:reader fields="firstname,lastname,gender,age,country" separator="|" quote="'" skipLines="1" />
 
</smooks-resource-list>
上記の設定は次のような形式のイベントストリームを生成します。
<csv-set>
    <csv-record>
        <firstname>Tom</firstname>
        <lastname>Fennelly</lastname>
        <gender>Male</gender>
        <age>21</age>
        <country>Ireland</country>
    </csv-record>
    <csv-record>
        <firstname>Tom</firstname>
        <lastname>Fennelly</lastname>
        <gender>Male</gender>
        <age>21</age>
        <country>Ireland</country>
    </csv-record>
</csv-set>
名前のコンマ区切りリストを fields 属性に使用してフィールドを定義します。
フィールド名は、以下の XML 要素名と同じ命名ルールに従う必要があります。
  • アルファベット、数字、およびその他の文字を使用できます。
  • 数字または句読文字で始まる名前は使用できません。
  • 「xml」(または XML や Xml など) で始まる名前は使用できません。
  • 空白文字は使用できません。
rootElementName および recordElementName 属性を設定すると、csv-set および csv-record 要素名を編集することが可能です。これらの名前にも同じルールが適用されます。
フィールドごとに文字列操作の関数を定義することが可能です。これらの関数は、データが SAX イベントに変換される前に実行されます。フィールド名の後に定義し、2 つの関数を疑問符で区切ります。
<?xml version="1.0"?>
<smooks-resource-list xmlns="http://www.milyn.org/xsd/smooks-1.1.xsd" xmlns:csv="http://www.milyn.org/xsd/smooks/csv-1.2.xsd">
 
    <csv:reader fields="lastname?trim.capitalize,country?upper_case" />
 
</smooks-resource-list>
CSV レコードのフィールドを無視するよう Smooks を設定するには、$ignore$ トークンをフィールドの設定値として指定します。無視するフィールド数を指定するには、 $ignore$ トークンの後ろに値を追加します( $ignore$3 の場合、 後続の 3 フィールドが無視されます)。 $ignore$+ を指定すると、 CSV レコードの最後まですべてのフィールドが無視されます。
<?xml version="1.0"?>
<smooks-resource-list xmlns="http://www.milyn.org/xsd/smooks-1.1.xsd" xmlns:csv="http://www.milyn.org/xsd/smooks/csv-1.2.xsd">
 
    <csv:reader fields="firstname,$ignore$2,age,$ignore$+" />
 
</smooks-resource-list>
CSV レコードを Java オブジェクトにバインドするのは比較的簡単です。
次のような CSV レコードがあるとします。
Tom,Fennelly,Male,4,Ireland
Mike,Fennelly,Male,2,Ireland
このコードを使用して、ある個人へレコードをバインドします。
public class Person {
    private String firstname;
    private String lastname;
    private String country;
    private Gender gender;
    private int age;
}
 
public enum Gender {
    Male, 
    Female;
}
この設定を使用します。
<?xml version="1.0"?>
<smooks-resource-list xmlns="http://www.milyn.org/xsd/smooks-1.1.xsd" xmlns:csv="http://www.milyn.org/xsd/smooks/csv-1.2.xsd">
 
    <csv:reader fields="firstname,lastname,gender,age,country">
        <!-- Note how the field names match the property names on the Person class. -->
        <csv:listBinding BeanId="people" class="org.milyn.csv.Person" />
    </csv:reader>
 
</smooks-resource-list>
この設定を実行するには、次のコードを使用します。
Smooks smooks = new Smooks(configStream);
JavaResult result = new JavaResult();
 
smooks.filterSource(new StreamSource(csvStream), result);
 
List<Person> people = (List<Person>) result.getBean("people");

Smooks also supports creation of Maps from the CSV record set:

<?xml version="1.0"?>
<smooks-resource-list xmlns="http://www.milyn.org/xsd/smooks-1.1.xsd" xmlns:csv="http://www.milyn.org/xsd/smooks/csv-1.2.xsd">
 
    <csv:reader fields="firstname,lastname,gender,age,country">
        <csv:mapBinding BeanId="people" class="org.milyn.csv.Person" keyField="firstname" />
    </csv:reader>
 
</smooks-resource-list>
上記の設定は person インスタンスのマップを生成します。各個人の firstname 値へ入力されます。これは次のように実行されます。
Smooks smooks = new Smooks(configStream);
JavaResult result = new JavaResult();
 
smooks.filterSource(new StreamSource(csvStream), result);
 
Map<String, Person> people = (Map<String, Person>) result.getBean("people");
 
Person tom = people.get("Tom");
Person mike = people.get("Mike");
仮想モデルもサポートされるため、class 属性を java.util.Map として定義し、 CSV フィールドの値をマップインスタンスにバインドできます。 その後、 マップインスタンスはリストまたはマップに追加されます。
プログラムを用いて CSV リーダーを設定することも可能です。これには複数の方法を使用できます。
次のコードは、個人のレコードセットを読み取るよう設定された CSV リーダーを用いて Smooks を設定し、レコードを person インスタンスのリストへバインドします。
Smooks smooks = new Smooks();
 
smooks.setReaderConfig(new CSVReaderConfigurator("firstname,lastname,gender,age,country")
                  .setBinding(new CSVBinding("people", Person.class, CSVBindingType.LIST)));
 
JavaResult result = new JavaResult();
smooks.filterSource(new StreamSource(csvReader), result);
 
List<Person> people = (List<Person>) result.getBean("people");
Java バインディングの設定は任意です。 代わりに、 プログラムを用いて Smooks インスタンスを設定し、他のビジター実装を使用して CSV レコードセットを処理することが可能です。
CSV レコードのデータを反映する Java タイプのリストまたはマップへ CSV レコードをバインディングしたい場合、CSVListBinder または CSVMapBinder クラスを使用できます。
// Note: The binder instance should be cached and reused...
CSVListBinder binder = new CSVListBinder("firstname,lastname,gender,age,country", Person.class);
 
List<Person> people = binder.bind(csvStream);

CSVMapBinder:

// Note: The binder instance should be cached and reused...
CSVMapBinder binder = new CSVMapBinder("firstname,lastname,gender,age,country", Person.class, "firstname");
 
Map<String, Person> people = binder.bind(csvStream);
バインディング処理を更に制御する必要がある場合、 低レベル API の使用に戻ります。
http://www.milyn.org/xsd/smooks/fixed-length-1.3.xsd 設定名前空間より、固定長のリーダーを設定します。
<?xml version="1.0"?>
<smooks-resource-list xmlns="http://www.milyn.org/xsd/smooks-1.1.xsd" xmlns:fl="http://www.milyn.org/xsd/smooks/fixed-length-1.3.xsd">
 
    <!--
    Configure the Fixed length to parse the message into a stream of SAX events.
    -->
    <fl:reader fields="firstname[10],lastname[10],gender[1],age[2],country[2]" skipLines="1" />
 
</smooks-resource-list>
入力ファイルの例は次の通りです。
#HEADER
Tom       Fennelly  M 21 IE
Maurice  Zeijen     M 27 NL
生成されるイベントストリームは次の通りです。
<set>
    <record>
        <firstname>Tom       </firstname>
        <lastname>Fennelly  </lastname>
        <gender>M</gender>
        <age> 21</age>
        <country>IE</country>
    </record>
    <record>
        <firstname>Maurice  </firstname>
        <lastname>Zeijen     </lastname>
        <gender>M</gender>
        <age>27</age>
        <country>NL</country>
    </record>
</set>
前の例と同様に、文字列操作関数を定義できます。
<?xml version="1.0"?>
<smooks-resource-list xmlns="http://www.milyn.org/xsd/smooks-1.1.xsd" xmlns:fl="http://www.milyn.org/xsd/smooks/fixed-length-1.3.xsd">
 
    <!--
    Configure the fixed length reader to parse the message into a stream of SAX events.
    -->
    <fl:reader fields="firstname[10]?trim,lastname[10]trim.capitalize,gender[1],age[2],country[2]" skipLines="1" />
 
</smooks-resource-list>
また、前の例と同様にフィールドを無視することも可能です。
<?xml version="1.0"?>
<smooks-resource-list xmlns="http://www.milyn.org/xsd/smooks-1.1.xsd" xmlns:fl="http://www.milyn.org/xsd/smooks/fixed-length-1.3.xsd">
 
    <fl:reader fields="firstname,$ignore$[2],age,$ignore$[10]" />
 
</smooks-resource-list>
固定長レコードの一部は次のようになります。
Tom       Fennelly  M 21 IE
Maurice  Zeijen     M 27 NL
これらを次のように個人へバインドします。
public class Person {
    private String firstname;
    private String lastname;
    private String country;
    private String gender;
    private int age;
}
この設定を使用します。
<?xml version="1.0"?>
<smooks-resource-list xmlns="http://www.milyn.org/xsd/smooks-1.1.xsd"  xmlns:fl="http://www.milyn.org/xsd/smooks/fixed-length-1.3.xsd">
 
    <fl:reader fields="firstname[10]?trim,lastname[10]?trim,gender[1],age[3]?trim,country[2]">
        <!-- Note how the field names match the property names on the Person class. -->
        <fl:listBinding BeanId="people" class="org.milyn.fixedlength.Person" />
    </fl:reader>
 
</smooks-resource-list>
次のように実行します。
Smooks smooks = new Smooks(configStream);
JavaResult result = new JavaResult();
 
smooks.filterSource(new StreamSource(fixedLengthStream), result);
 
List<Person> people = (List<Person>) result.getBean("people");
固定長レコードセットよりマップを作成することも可能です。
<?xml version="1.0"?>
<smooks-resource-list xmlns="http://www.milyn.org/xsd/smooks-1.1.xsd"  xmlns:fl="http://www.milyn.org/xsd/smooks/fixed-length-1.3.xsd">
 
    <fl:reader fields="firstname[10]?trim,lastname[10]?trim,gender[1],age[3]?trim,country[2]">
        <fl:mapBinding BeanId="people" class="org.milyn.fixedlength.Person" keyField="firstname" />
    </fl:reader>
 
</smooks-resource-list>
次のように作成された person インスタンスのマップを実行します。
Smooks smooks = new Smooks(configStream);
JavaResult result = new JavaResult();
 
smooks.filterSource(new StreamSource(fixedLengthStream), result);
 
Map<String, Person> people = (Map<String, Person>) result.getBean("people");
 
Person tom = people.get("Tom");
Person mike = people.get("Maurice");
仮想モデルもサポートされるため、class 属性を java.util.Map として定義し、固定長フィールドの値をマップインスタンスにバインドできます。 その後、 マップインスタンスはリストまたはマップに追加されます。
プログラムを用いて固定長のリーダーを設定することも可能です。
このコードは、個人のレコードセットを読み取り、そのレコードセットを person インスタンスのリストへバインドする固定長リーダーを設定します。
Smooks smooks = new Smooks();
 
smooks.setReaderConfig(new FixedLengthReaderConfigurator("firstname[10]?trim,lastname[10]?trim,gender[1],age[3]?trim,country[2]")
                  .setBinding(new FixedLengthBinding("people", Person.class, FixedLengthBindingType.LIST)));
 
JavaResult result = new JavaResult();
smooks.filterSource(new StreamSource(fixedLengthStream), result);
 
List<Person> people = (List<Person>) result.getBean("people");
Java バインディングの設定は強制ではありません。代わりに、プログラムを用いて Smooks インスタンスを設定し、他のビジター実装を使用して固定長のレコードセット上でさまざまな処理を実行することができます。
固定長レコードのデータを反映する Java タイプのリストまたはマップへ固定長レコードを直接バインディングしたい場合、FixedLengthListBinder または the FixedLengthMapBinder クラスを使用できます。
// Note: The binder instance should be cached and reused...
FixedLengthListBinder binder = new FixedLengthListBinder("firstname[10]?trim,lastname[10]?trim,gender[1],age[3]?trim,country[2]", Person.class);
 
List<Person> people = binder.bind(fixedLengthStream);

FixedLengthMapBinder:

// Note: The binder instance should be cached and reused...
FixedLengthMapBinder binder = new FixedLengthMapBinder("firstname[10]?trim,lastname[10]?trim,gender[1],age[3]?trim,country[2]", Person.class, "firstname");
 
Map<String, Person> people = binder.bind(fixedLengthStream);
バインディング処理を更に制御する必要がある場合、 低レベル API の使用に戻ります。
Smooks の EDI 処理は、 http://www.milyn.org/xsd/smooks/edi-1.2.xsd 設定名前空間よりサポートされます。
設定例は次の通りです。
<?xml version="1.0"?>
<smooks-resource-list xmlns="http://www.milyn.org/xsd/smooks-1.1.xsd" xmlns:edi="http://www.milyn.org/xsd/smooks/edi-1.2.xsd">    
 <!--
    Configure the EDI Reader to parse the message stream into a stream of SAX events.
    -->
    <edi:reader mappingModel="edi-to-xml-order-mapping.xml" validate="false"/>
</smooks-resource-list>
  • mappingModel: EDI メッセージを Smooks によって処理できる SAX イベントのストリームへ変換するための EDI マッピングモデルを定義します。
  • validate: この属性は、 EDI パーサーのデータタイプ検証を有効または無効にします (検証はデフォルトでは on になっています)。 EDI データが Java オブジェクトモデルにバインドされている場合、EDI リーダー上のデータタイプ検証を off にするとよいでしょう (jb:bean のように Java バインディングを使用)。 これは、 バインディングレベルで検証が行われるからです。
EDI から SAX へのイベントマッピング処理は、EDI リーダーへ提供されるマッピングモデルが基となります (このモデルは常に http://www.milyn.org/xsd/smooks/edi-1.2.xsd のスキーマを使用する必要があります。このスキーマより、グループ内のグループ、 繰り返しの断片、 繰り返しの断片グループなど、断片グループがサポートされることを確認できます。必ずスキーマを再確認するようにしてください)。
medi:segment 要素は、minOccursmaxOccurs の 2 つの任意属性をサポートします (両方ともデフォルト値は 1 になります)。これらの属性を使用して、断片の特徴を制御します。 maxOccurs の値を -1 にすると、 (バインドされていない) EDI メッセージがある場所で断片を何回でも繰り返すことができます。
segmentGroup 要素を使用して断片グループを追加できます。断片グループはグループの最初の断片と照合されます。断片グループにはネストされた segmentGroup 要素が含まれることがありますが、segmentGroups の最初の要素は断片でなければなりません。segmentGroup 要素は minOccurs および maxOccurs の濃度 をサポートします。 任意の xmlTag 属性もサポートされます。 この属性が存在する場合、xmlTag 属性値の名前を持つ要素に挿入される、一致した断片グループによって XML が生成されます。
断片は次の方法の 1 つによって合致されます。
  • 断片コード (segcode) 上の完全一致。
  • 完全な断片上の正規表現パターンの合致。segcode="1A\*a.*" のように、segcode 属性が正規表現パターンを定義します。
  • required: フィールド、コンポーネント、およびサブコンポーネントの設定は、required 属性をサポートします。この属性は、フィールド、コンポーネント、またはサブコンポーネントに値が必要であることを知らせます。
  • デフォルトでは、値は必要ありません (フィールド、コンポーネント、およびサブコンポーネント)。
  • truncatable: 断片、フィールド、およびコンポーネントの設定は truncatable 属性をサポートします。断片では、後続のフィールドが指定されず「required」でない場合は (前述の「required」属性を参照) パーサーエラーは生成されません。 フィールド/コンポーネントおよびコンポーネント/サブコンポーネントの場合でも同様です。
  • デフォルトでは、断片、フィールドおよびコンポーネントは省略できません。
よって、メッセージに存在するフィールド、コンポーネント、サブコンポーネントは次の状態のいずれかとなります。
  • 値と存在 (required="true")
  • 値なしで存在 (required="false")
  • 存在しない (required="false" and truncatable="true")
メッセージグループの多くは同じ断片定義を使用します。 断片を一度定義し、 トップレベルの設定にインポートできると、重複を避けることができるため、時間を節約することができます。以下は、インポート機能を示す簡単な設定になります。

<?xml version="1.0" encoding="UTF-8"?>
<medi:edimap xmlns:medi="http://www.milyn.org/schema/edi-message-mapping-1.2.xsd">
 
    <medi:import truncatableSegments="true" truncatableFields="true" truncatableComponents="true" resource="example/edi-segment-definition.xml" namespace="def"/>
 
    <medi:description name="DVD Order" version="1.0"/>
 
    <medi:delimiters segment="
" field="*" component="^" sub-component="~" escape="?"/>
 
    <medi:segments xmltag="Order">
        <medi:segment minOccurs="0" maxOccurs="1" segref="def:HDR" segcode="HDR" xmltag="header"/>
        <medi:segment minOccurs="0" maxOccurs="1" segref="def:CUS" segcode="CUS" xmltag="customer-details"/>
        <medi:segment minOccurs="0" maxOccurs="-1" segref="def:ORD" segcode="ORD" xmltag="order-item"/>
    </medi:segments>
 
</medi:edimap>
今後の再利用を容易にするため、断片および子断片が含まれる断片を別ファイルへ分離することができます。
  • segref: インポートする断片を参照する namespace:name が含まれます。
  • truncatableSegments: インポートされたリソースマッピングファイルに指定された truncatableSegments を上書きします。
  • truncatableFields: インポートされたリソースマッピングファイルに指定された truncatableFields を上書きします。
  • truncatableComponents: インポートされたリソースマッピングファイルに指定された truncatableComponents を上書きします。
field、component、および sub-component 要素は type 属性をサポートします。 この属性によってデータタイプの指定が可能になります。この属性は 2 つのサブ属性によって構成されます。
  • type: type 属性は基本的なデータタイプを指定します。
  • typeParameters: typeParameters 属性は、指定されたタイプの DataDecoder に対するデータデコードパラメータを指定します。
この例はタイプのサポートを表しています。
<?xml version="1.0" encoding="UTF-8"?>
<medi:edimap xmlns:medi="http://www.milyn.org/schema/edi-message-mapping-1.2.xsd">
 
    <medi:description name="Segment Definition DVD Order" version="1.0"/>
 
    <medi:delimiters segment="
" field="*" component="^" sub-component="~" escape="?"/>
 
    <medi:segments xmltag="Order">
 
        <medi:segment segcode="HDR" xmltag="header">
            <medi:field xmltag="order-id"/>
            <medi:field xmltag="status-code" type="Integer"/>
            <medi:field xmltag="net-amount" type="BigDecimal"/>
            <medi:field xmltag="total-amount" type="BigDecimal"/>
            <medi:field xmltag="tax" type="BigDecimal"/>
            <medi:field xmltag="date" type="Date" typeParameters="format=yyyyHHmm"/>
        </medi:segment>
 
    </medi:segments>
 
</medi:edimap>
タイプシステムは次のような用途で使用できます。
  • フィールド検証。
  • Edifact Java Compilation
EDIReaderConfigurator を用いて EDIReader を使用するよう、プログラムを用いて Smooks インスタンスを設定することが可能です。
Smooks smooks = new Smooks();
 
// Create and initialise the Smooks config for the parser...
smooks.setReaderConfig(new EDIReaderConfigurator("/edi/models/invoice.xml"));
 
// Use the smooks as normal
smooks.filterSource(....);
Edifact Java Compiler は、EDI から Java への変換プロセスを大幅に簡易化できます。Edifact Java Compiler は以下を生成します。
  • EDI マッピングモデルの Java オブジェクトモデル。
  • EDI マッピングモデルによって記述される EDI メッセージのインスタンスより Java Object モデルへ投入する Smooks Java バインディング設定。
  • EDI データを Java オブジェクトモデルへバインドする Edifact Java Compiler の使用を大変容易にするファクトリクラス。
Edifact Java Compiler を使用すると、次のような簡単な Java コードの書き込みが可能になります。
// Create an instance of the EJC generated Factory class.  This should normally be cached and reused...
OrderFactory orderFactory = OrderFactory.getInstance();
 
// Bind the EDI message stream data into the EJC generated Order model...
Order order = orderFactory.fromEDI(ediStream);
 
// Process the order data...
Header header = order.getHeader();
Name name = header.getCustomerDetails().getName();
List<OrderItem> orderItems = order.getOrderItems();
Maven または Ant より Edifact Java Compiler を実行できます。
Maven 下で実行するには、POM ファイルにプラグインを追加します。
<build>
    <plugins>
        <plugin>
            <groupId>org.milyn</groupId>
            <artifactId>maven-ejc-plugin</artifactId>
            <version>1.2</version>
            <configuration>
                <ediMappingFile>edi-model.xml</ediMappingFile>
                <packageName>com.acme.order.model</packageName>
            </configuration>
            <executions>
                <execution><goals><goal>generate</goal></goals></execution>
            </executions>
        </plugin>
    </plugins>
</build>
プラグインには 3 つの設定パラメータがあります。
  • ediMappingFile: Maven プロジェクト内にある EDI マッピングモデルファイルへのパスになります (これは任意です。 デフォルトのパスは src/main/resources/edi-model.xml になります)。
  • packageName: 生成された Java アーティファクトが格納される Java パッケージです (Java オブジェクトモデルとファクトリクラス)。
  • destDir: 生成されたアーティファクトが作成されコンパイルされるディレクトリになります (これは任意です。 デフォルトは target/ejc になります)。
Ant 下で実行するには、EJC タスクを作成し、実行します。次のコードはその方法を表しています。
<target name="ejc">
 
    <taskdef resource="org/milyn/ejc/ant/anttasks.properties">
        <classpath><fileset dir="/smooks-1.2/lib" includes="*.jar"/></classpath>
    </taskdef>
 
    <ejc edimappingmodel="src/main/resources/edi-model.xml"
         destdir="src/main/java"
         packagename="com.acme.order.model"/>
 
    <!-- Ant as usual from here on... compile and jar the source... -->
 
</target>
Edifact Java Compiler の詳細について知りたい場合、EJC の例である UN/EDIFACT を確認するのが最も簡単な方法です。
Smooks は以下の方法で UN/EDIFACT メッセージインターチェンジに対するサポートを提供します。
  • 正式な UN/EDIFACT メッセージ定義の ZIP ディレクトリから生成された、事前生成された EDI マッピングモデル。これにより、UN/EDIFACT メッセージインターチェンジを消費しやすい XML 形式へ変換できます。
  • 純粋な Java を使用した UN/EDIFACT インターチェンジの読み書きを容易にする、事前生成された Java バインディング。
UN/EDIFACT インターチェンジは、ベース edi:reader の特殊な亜種を介してサポートされます。このリーダーを設定するには、次のように http://www.milyn.org/xsd/smooks/unedifact-1.4.xsd 名前空間を設定します。
<?xml version="1.0"?>
<smooks-resource-list xmlns="http://www.milyn.org/xsd/smooks-1.1.xsd" xmlns:unedifact="http://www.milyn.org/xsd/smooks/unedifact-1.4.xsd">
 
    <unedifact:reader mappingModel="urn:org.milyn.edi.unedifact:d03b-mapping:v1.4" ignoreNewLines="true" />
 
</smooks-resource-list>
mappingModel 属性は、マッピングモデルの ZIP セットの Maven アーティファクトを参照する URN を定義します。Maven アーティファクトはリーダーによって使用されます。
UN/EDIFACT インターチェンジを消費するよう (UNEdifactReaderConfigurator を介してなど)、プログラムを用いて Smooks を設定することも可能です。
Smooks smooks = new Smooks();
 
smooks.setReaderConfig(new UNEdifactReaderConfigurator("urn:org.milyn.edi.unedifact:d03b-mapping:v1.4"));
格納するアプリケーションのクラスパスに以下が含まれるようにする必要があります。
  • 必要な EDI マッピングモデル。
  • Smooks EDI カートリッジ
次の例は、この設定が必要とする可能性がある Maven 依存関係の一部を表しています。
<dependency>
    <groupId>org.milyn</groupId>
    <artifactId>milyn-smooks-edi</artifactId>
    <version>1.4</version>
</dependency>
 
<!-- Required Mapping Models -->
<dependency>
    <groupId>org.milyn.edi.unedifact</groupId>
    <artifactId>d93a-mapping</artifactId>
    <version>v1.4</version>
</dependency>
<dependency>
    <groupId>org.milyn.edi.unedifact</groupId>
    <artifactId>d03b-mapping</artifactId>
    <version>v1.4</version>
</dependency>
アプリケーションが EDI マッピングモデルの ZIP セットをクラスパスに追加した後、このモデルを使用するよう Smooks を設定できます。設定を行うには、URN を unedifact:reader 設定の mappingModel 属性値として使用し、Maven アーティファクトを参照します。
<?xml version="1.0"?>
<smooks-resource-list xmlns="http://www.milyn.org/xsd/smooks-1.1.xsd" xmlns:unedifact="http://www.milyn.org/xsd/smooks/unedifact-1.4.xsd"
 
    <unedifact:reader mappingModel="urn:org.milyn.edi.unedifact:d03b-mapping:v1.4" ignoreNewLines="true" />
 
</smooks-resource-list>

注記

mappingModel 属性は、コンマ区切りの EDI マッピングモデルの URN を複数定義できます。複数定義すると、異なるディレクトリに定義された複数の UN/EDIFACT メッセージに対応するインターチェンジを、UN/EDIFACT リーダーが処理しやすくなります。
マッピングモデルの ZIP セットはすべての UN/EDIFACT ディレクトリが使用可能です。これらの ZIP セットは Maven SNAPSHOT および Central レポジトリより取得し、標準の Maven 依存関係管理を使用してアプリケーションに追加します。
たとえば、D93A マッピングモデルの ZIP セットをアプリケーションのクラスパスに追加するには、次の依存関係をアプリケーションの POM ファイルに設定します。
<!-- The mapping model sip set for the D93A directory... -->
<dependency>
    <groupId>org.milyn.edi.unedifact</groupId>
    <artifactId>d93a-mapping</artifactId>
    <version>v1.4</version>
</dependency>
次の手順では、この ZIP セットを使用するよう Smooks を設定します。次のコードのように、unedifact: リーダーの設定を Smooks の設定に追加します。
<unedifact:reader mappingModel="urn:org.milyn.edi.unedifact:d93a-mapping:v1.4" />
Maven アーティファクトの依存関係情報を基にした URN を使用して、どのようにリーダーを設定するか注目してください。
また、複数のマッピングモデルの ZIP セットをアプリケーションのクラスパスに追加することができます。これには、コンマ区切りの URN にてすべての ZIP セットを unedifact:reader 設定に追加します。
事前生成された Java バインディングモデルセットにはツールが提供されています (マッピングモデル ZIP セットごとに 1 つ)。このツールを使用し、大変簡単な生成されたファクトリクラスを用いて UN/EDIFACT インターチェンジを処理します。
次のコード例は、D03B UN/EDIFACT メッセージインターチェンジの処理方法を表しています。
Reading:

// Create an instance of the EJC generated factory class... cache this and reuse !!!
D03BInterchangeFactory factory = D03BInterchangeFactory.getInstance();
 
// Deserialize the UN/EDIFACT interchange stream to Java...
UNEdifactInterchange interchange = factory.fromUNEdifact(ediInStream);
 
// Need to test which interchange syntax version.  Supports v4.1 at the moment...
if(interchange instanceof UNEdifactInterchange41) {
    UNEdifactInterchange41 interchange41 = (UNEdifactInterchange41) interchange;
 
    for(UNEdifactMessage41 message : interchange41.getMessages()) {
        // Process the messages...
 
        Object messageObj = message.getMessage();
 
        if(messageObj instanceof Invoic) {
            // It's an INVOIC message....
            Invoic invoic = (Invoic) messageObj;
            ItemDescription itemDescription = invoic.getItemDescription();
            // etc etc....
        } else if(messageObj instanceof Cuscar) {
            // It's a CUSCAR message...
        } else if(etc etc etc...) {
            // etc etc etc...
        }
    }
}


Writing:

factory.toUNEdifact(interchange, ediOutStream);
マッピングモデル ZIP セットと同様、Smooks には Maven SNAPSHOT および Central レポジトリを介して配布される、事前生成の UN/EDIFACT Java オブジェクトモデルが含まれています。
Maven を使用する場合、D03B メッセージインターチェンジを処理するにはそのディレクトリのバインディング依存関係を追加する必要があります。
<dependency>
    <groupId>org.milyn.edi.unedifact</groupId>
    <artifactId>d03b-binding</artifactId>
    <version>v1.4</version>
</dependency>
JSON データを処理するには、JSON リーダーを設定する必要があります。
<?xml version="1.0"?>
<smooks-resource-list xmlns="http://www.milyn.org/xsd/smooks-1.1.xsd" xmlns:json="http://www.milyn.org/xsd/smooks/json-1.1.xsd">
 
    <json:reader/>
 
</smooks-resource-list>
次の設定オプションを使用すると、root、document、および array 要素の XML 名を設定できます。
  • rootName: root 要素の名前です。デフォルトは yaml です。
  • elementName: sequence 要素の名前です (デフォルトは element です)。
JSON では、XML 要素名では使用できない文字をキー名に使用できます。リーダーはこの問題に対して複数の解決法を提供します。リーダーは、空白文字、不正な文字、数字で始まるキー名の数字を検索し、置き換えることが可能です。リーダーを使用して、キー名を完全に異なる名前に置き換えることも可能です。次のコード例は、このような機能をすべて表しています。
<?xml version="1.0"?>
<smooks-resource-list xmlns="http://www.milyn.org/xsd/smooks-1.1.xsd" xmlns:json="http://www.milyn.org/xsd/smooks/json-1.1.xsd">
 
    <json:reader keyWhitspaceReplacement="_" keyPrefixOnNumeric="n" illegalElementNameCharReplacement=".">
        <json:keyMap>
            <json:key from="some key">someKey</json:key>
            <json:key from="some&key" to="someAndKey" />
        </json:keyMap>
    </json:reader>
 
</smooks-resource-list>
  • keyWhitspaceReplacement: JSON マップキーの空白文字を置換する文字になります。デフォルトでは定義されていないため、リーダーは自動的に空白文字を検索しません。
  • keyPrefixOnNumeric: JSON のノード名が数字で始まる場合、 このプレフィックス文字を追加します。デフォルトでは定義されていないため、リーダーは数字で始まる要素名を検索しません。
  • illegalElementNameCharReplacement: JSON の要素名で不正な文字が見つかった場合、この値に置き換えられます。
希望する場合、次の任意の設定を設定することも可能です。
  • nullValueReplacement: JSON の null 値を置き換える文字列です。 デフォルトは空の文字列です。
  • encoding: リーダーによって処理される JSON メッセージ InputStream のデフォルトのエンコードです。

    注記

    この機能は廃止されました。代わりに、java.io.ReaderSmooks.filterSource() メソッドに提供して JSON ストリームのソース文字のエンコードを管理する必要があります。
JSON 設定を読み取るよう、プログラムを用いて Smooks を設定するには、JSONReaderConfigurator クラスを使用します。
Smooks smooks = new Smooks();
 
smooks.setReaderConfig(new JSONReaderConfigurator()
        .setRootName("root")
        .setArrayElementName("e"));
 
// Use Smooks as normal...

YAML ファイルを処理したい場合は、処理できるリーダーを設定する必要があります。
<?xml version="1.0"?>
<smooks-resource-list xmlns="http://www.milyn.org/xsd/smooks-1.1.xsd" xmlns:yaml="http://www.milyn.org/xsd/smooks/yaml-1.4.xsd">
 
    <yaml:reader/>
 
</smooks-resource-list>
YAML ストリームには複数のドキュメントが含まれることがあります。リーダーは document 要素を root 要素の子として追加し、これに対応します。空の YAML ドキュメントが 1 つ含まれ、XML でシリアライズされた YAML ストリームは次のようになります。
<yaml>
    <document>
    </document>
</yaml>
次のオプションを設定すると root、document、および array 要素の XML 要素名を設定できます。
  • rootName: root 要素の名前です。デフォルトは yaml です。
  • documentName: document 要素の名前です。デフォルトは document です。
  • elementName: sequence 要素の名前です。デフォルトは element です。
YAML では、XML 要素名では使用できない文字をキー名に使用できます。リーダーはこの問題に対して複数の解決法を提供します。リーダーは、空白文字、不正な文字、数字で始まるキー名の数字を検索し、置き換えることが可能です。リーダーを使用して、キー名を完全に異なる名前に置き換えることも可能です。次のコード例は、このような機能をすべて表しています。
<?xml version="1.0"?>
<smooks-resource-list xmlns="http://www.milyn.org/xsd/smooks-1.1.xsd" xmlns:yaml="http://www.milyn.org/xsd/smooks/yaml-1.4.xsd">
 
    <yaml:reader keyWhitspaceReplacement="_" keyPrefixOnNumeric="n" illegalElementNameCharReplacement=".">
        <yaml:keyMap>
            <yaml:key from="some key">someKey</yaml:key>
            <yaml:key from="some&key" to="someAndKey" />
        </yaml:keyMap>
    </yaml:reader>
 
</smooks-resource-list>
  • keyWhitspaceReplacement: YAML マップキーの空白文字を置換する文字になります。 デフォルトでは定義されません。
  • keyPrefixOnNumeric: YAML のノード名が数字で始まる場合、 このプレフィックス文字を追加します。デフォルトでは定義されません。
  • illegalElementNameCharReplacement: YAML の要素名で不正な文字が見つかった場合、この値に置き換えられます。デフォルトでは定義されません。
YAML は アンカーエイリアス の概念を使用します。YAML リーダーは、3 つのストラテジを介してアンカーとエイリアスに対応できます。aliasStrategy 設定オプションより希望のストラテジを定義します。このオプションには以下の値の 1 つを使用できます。
  • REFER: リーダーは、アンカーまたはエイリアスを持つ要素上で参照属性を作成します。アンカーを持つ要素は、アンカーからの名前が属性値として含まれる id. 属性を取得します。エイリアスを持つ要素は、アンカーからの名前が属性値として含まれる ref 属性を取得します。anchorAttributeName および aliasAttributeName プロパティを設定して、アンカーおよびエイリアスの属性名を定義できます。
  • RESOLVE: リーダーは、エイリアスを見つけた時にアンカーの値またはデータ構造を解決します。そのため、アンカーの SAX イベントは alias 要素の子イベントとして繰り返されます。大量のアンカーまたはアンカーと大量のデータ構造が YAML ドキュメントに含まれている場合、メモリーの問題が発生する可能性があります。
  • REFER_RESOLVE: REFER と RESOLVE の組み合わせになります。アンカーおよびエイリアス属性が設定され、アンカーの値またはデータ構造も解決されます。アンカーの名前にビジネス的な意味合いがある場合にこのオプションは便利です。
YAML リーダーはデフォルトで REFER ストラテジを使用します。
YamlReaderConfigurator クラスを利用して YAML 設定を読み取るよう、プログラムを用いて Smooks を設定することができます。
Smooks smooks = new Smooks();
 
smooks.setReaderConfig(new YamlReaderConfigurator()
        .setRootName("root")
        .setDocumentName("doc")
        .setArrayElementName("e"))
        .setAliasStrategy(AliasStrategy.REFER_RESOLVE)
        .setAnchorAttributeName("anchor")
        .setAliasAttributeName("alias");
 
// Use Smooks as normal...
Smooks は Java オブジェクトグラフを別の Java オブジェクトグラフに変換することができます。 Smooks は SAX 処理モデルを使用してこれを実行します。 そのため、 中間のオブジェクトモデルは構築されず、 ソース Java オブジェクトグラフは直接 SAX イベントのストリームに変換されます。 これらの SAX イベントはターゲットの Java オブジェクトグラフへ投入するために使用されます。
HTML Smooks Report Generator ツールを使用する場合、ソースオブジェクトモデルが作成したイベントストリームは次のようになります。
<example.srcmodel.Order>
    <header>
        <customerNumber>
            </customerNumber>
            <customerName>
        </customerName>
    </header>
    <orderItems>
        <example.srcmodel.OrderItem>
            <productId>
            </productId>
            <quantity>
            </quantity>
            <price>
            </price>
        </example.srcmodel.OrderItem>
    </orderItems>
</example.srcmodel.Order>
ここで、Smooks の Java Bean リソースをこのイベントストリームへ向けます。
このトランスフォーメーションを実行するための Smooks 設定 (smooks-config.xml) は次の通りです。
<?xml version="1.0"?>
<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">
 
    <jb:bean BeanId="lineOrder" class="example.trgmodel.LineOrder" createOnElement="example.srcmodel.Order">
        <jb:wiring property="lineItems" BeanIdRef="lineItems" />
        <jb:value property="customerId" data="header/customerNumber" />
        <jb:value property="customerName" data="header/customerName" />
    </jb:bean>
 
    <jb:bean BeanId="lineItems" class="example.trgmodel.LineItem[]" createOnElement="orderItems">
        <jb:wiring BeanIdRef="lineItem" />
    </jb:bean>
 
 
    <jb:bean BeanId="lineItem" class="example.trgmodel.LineItem" createOnElement="example.srcmodel.OrderItem">
        <jb:value property="productCode" data="example.srcmodel.OrderItem/productId" />
        <jb:value property="unitQuantity" data="example.srcmodel.OrderItem/quantity" />
        <jb:value property="unitPrice" data="example.srcmodel.OrderItem/price" />
    </jb:bean>
 
</smooks-resource-list>
ソースオブジェクトモデルは、 org.milyn.delivery.JavaSource オブジェクトより Smooks へ提供されます。コンストラクタをソースモデルのルートオブジェクトへ渡してこのオブジェクトを作成します。結果として生じる Java ソースオブジェクトは Smooks#filter メソッドで使用されます。その結果となるコードは次の通りです。
protected LineOrder runSmooksTransform(Order srcOrder) throws IOException, SAXException {
    Smooks smooks = new Smooks("smooks-config.xml");
    ExecutionContext executionContext = smooks.createExecutionContext();
 
    // Transform the source Order to the target LineOrder via a
    // JavaSource and JavaResult instance...
    JavaSource source = new JavaSource(srcOrder);
    JavaResult result = new JavaResult();
 
    // Configure the execution context to generate a report...
    executionContext.setEventListener(new HtmlReportGenerator("target/report/report.html"));
 
    smooks.filterSource(executionContext, source, result);
 
    return (LineOrder) result.getBean("lineOrder");
}
CSV および固定長リーダーを使用すると、データが SAX イベントへ変換される前に入力データ上で文字列操作関数を実行できます。次の関数を使用することができます。
  • upper_case: 文字列の大文字バージョン返します。
  • lower_case: 文字列の小文字バージョンを返します。
  • cap_first: 最初の言葉が大文字になっている文字列を返します。
  • uncap_first: 最初の文字が大文字でない文字列を返します。cap_first とは逆になります。
  • capitalize: すべての言葉が大文字の文字列を返します。
  • trim: 最初と最後に空白文字のない文字列を返します。
  • left_trim: 最初に空白文字のない文字列を返します。
  • right_trim: 最後に空白文字のない文字列を返します。
trim.upper_case のように、ピリオドで区切って関数をつなげることが可能です。
フィールドごとに関数を定義する方法は、使用するリーダーによって異なります。