この記事の対象者
この記事は、経験豊富なODI(Oracle Data Integrator)開発者を対象としています。 このセクションでは、BeanShell置換の実行順序に関連する文書化されていない側面について説明します。
これはパート1の続きです。
これはパート1の続きです。
BeanShell置換の各レベルを個別に処理した後、一緒に使用した場合にこれらのレベルが互いにどのように整合するかを確認します。 ここでは、文字通り互いに浸透している、異なる同一の置換間の密接な協力についてのみ話します。 互いに埋め込まれている場合、どのように解釈しますか?
交差する置換の不可能性
これは最も明白なルールです。 ここでは完全性のためにのみ言及されています。 間違った例を次に示します。
<? /* 1 */ <% /* 2 */ /* 1 */ ?> /* 2 */ %>
このようなコードはエラーにつながります。 置換は、XMLドキュメントの要素と同様に、階層的にのみネストできます。
<? /* 1 */ <% /* 2 */ /* 2 */ %> /* 1 */ ?>
早いうちに
置換をネストする最も簡単で自然な方法は、前のものを後のものの中に配置することです。 実行されると、以前のものはテキストに変わるか削除されます(置換コードが出力ストリームに何も出力しない場合、実行の結果は置換の削除になります) 後の置換は、構文に違反するアーティファクトなしで「クリーン」のままです。 たとえば、コード
<? String v_sess_info = " <%=odiRef.getSession("SESS_NO")%>; <%=odiRef.getSession("NNO")%>"; ?>
最初のパスの後、次のようになります。
<? String v_sess_info = " 123123123555; 3"; ?>
ここでは、文字列の連結を実行せずに、odiRefメソッドの結果がテキストに埋め込まれ、後で変数に割り当てられます。 ドキュメントで、SubstitutionAPI関数はほとんどの場合Stringを返すodiRefオブジェクトのメソッドであることがわかります。 ただし、特定の置換レベルでのみ特定の機能を実行できることを直接示すものはどこにもありません。 さらに、1つの引数を持つ同じ関数は1つのレベルで機能し、他のレベルでは別のレベルでのみ機能します。 これについては、次のいずれかの記事で説明します。
したがって、たとえば「@」レベルで、SubstitutionAPIが%置換を使用してのみ返すことができる値を取得する必要がある場合、ネスト置換が目的の結果を取得する唯一の方法です。
後でより早く
たとえば、実行しているインタープリターが-<置換>に突然遭遇すると、誤って実行を停止します。 当然、彼はここでBeanShellコードを見ることを期待しています。 つまり、逆投資は不可能と思われますが、それでも可能です。
置換コードをテキスト文字列内のメタキャラクターと一緒に非表示にし、この文字列をストリームに挿入すると、実行された?-Substitutionはコード内に@ -substitutionを残します。 次のパスでは、成功します。 例:
<?/* */ String fieldProcessing(String fldName, String srcTyp, String dstTyp){ ... return changedFldName; }?> ... <%=odiRef.getColList(0,"\t","<?=fieldProcessing("+'"'+"[COL_NAME]"+'"'+","+'"'+"[SOURCE_DT]"+'"'+","+'"'+"[DEST_DT]"+'"'+")?>","\n\t,","")%> ...
odiRef.getColList関数などには、名前、タイプ、フィールドの形式、データモデルに入力されたフィールドのコメント、およびその他の属性にアクセスできるさまざまなニーモニックがあります。 しかし、フィールドのリストに基づいたコード生成のロジック全体はSubstitutionAPI内にあり、これに介入することはもはやできないように思われます。 また、まれに、次のものが必要になる場合があります。
- フィールド名のプレフィックスまたはインフィックスを削除または追加します。
- ソースとターゲットのタイプまたはタイプの相関に応じて、解釈の結果を変更します。
- モデルに入力されている場合は、フィールドタイトルを使用します。 ただし、入力しない場合は、フィールド名を使用します(たとえば、CSVファイルのヘッダーを生成するのに役立ちます)。
- 何らかの機能を備えたモデルでマークされたフィールドに特別な処理ルールを提供します。
- およびその他の名手タスク。
このためには、コードを生成するときに中間結果が取得され、次の置換が実行されたときに目的の結果が得られることが必要です。 最初のパスの後の上記の例は、
<?/* */ String fieldProcessing(String fldName, String srcTyp, String dstTyp){ ... return changedFldName; }?> ... <?=fieldProcessing("FIELD1","NUMBER","NUMBER")?>, <?=fieldProcessing("FIELD2","NUMBER","CHAR")?>, <?=fieldProcessing("FIELD3","CHAR","CHAR")?>, ...
埋め込み可能なロジックが単純な場合、odiRef.getColListを呼び出すことで、行内に実装できます。 しかし、文字列でコードを表示することには多くの問題が伴います(文字列内の二重引用符でさえ、マルチパス解釈のために\ u0022が常に機能するとは限らないため、トラブルにつながる可能性があります)。 したがって、このロジックを呼び出す関数に配置することをお勧めします。
その場でスタンピング
ある置換が別の置換を「印刷」でき、後者が機能する場合、同じ置換レベルのままでこれを実行できますか? それはあなたができることが判明しました。 SubstitutionAPIの機能自体がこの機会を利用すると信じる理由があります。 たとえば、「%」レベルで使用されるodiRef.getOption関数は、%置換を含む結果(オプション値)を提供できます。 そして、彼らは素晴らしい仕事をします! これは最も明白な例です。 しかし、さまざまな種類のエラーを引き起こし、レベル「%」と「?」でログからどのように気付くことができますかodiRef関数は目に見えないsnpRefに変わり、「%」が「?」知っています。
インタープリターをループしてみましょう:
<% Long n = 0L; String code1="/*<"+"%=n%"+">*/"; String code2="<"+"%"+"if(n++>10){out.print(code1);}else{out.print(code2);}"+"%"+">"; %> <%=code2%>
nが10を超えるまで、同じコードの出力が発生します。 しかし、これはa%の置換でもあり、すべてが最初から始まります。 コードの反復解釈は、n = 11で終了します。 次に、値nのコメントが出力されます。 ODIオペレーターに表示される最終コードは、「/ * 12 * /」です。 この例で、10の代わりに100を入力すると、巡回解釈の結果は次のようになります。
### KEY com.sunopsis.res.gen / ODI-15015: Too much recursion in this text resolution.### (Command 0) out.print("\n") ; if(n++>100){out.print(code1);}else{out.print(code2);} ****** ORIGINAL TEXT ****** <%if(n++>100){out.print(code1);}else{out.print(code2);}%>
つまり、反復の制限は10〜100です。このステップで[エラーを無視]オプションをオンにしてこのコードをプロシージャに入力し、次のステップで変数nの値を表示できます(たとえば、次のようになります:/ * <%= n%> * /) 。 次に、このような再帰的置換の実際の深さを調べます。 彼女は、驚くほど素晴らしいではありません。
ちなみに、%置換の実行中に発生した例外はセッションを停止しなかったことに注意してください。これは、ログにより、トークン解析エラーからの最終実行中にクラッシュが後で発生したことが間接的に明確になるためです:1行目の字句エラー、列2。遭遇:「#」»。
最後の例には実用的な価値はありませんが、順列メカニズムの仕組みを理解するための鍵となります。
結論として、後の置換から前の置換を含むコードを印刷することは不可能であると言うだけです。 つまり、これを行うことは可能ですが、この方法で挿入された置換は、最終実行までそのまま残り、対応するインタープリターが既に存在し、ひづめをタップするとセッションの次のステップに進んでいるため、既にそこに構文を「壊します」。 彼はポーンのように、前方にのみ動き、斜めにヒットします。 また、条件付き解釈を考慮し、複雑な構造のファイルへのデータのアップロードを含む、その使用例が示される次のパートを書くことも辞退します。