文書の過去の版を表示しています。
KETTLE_XML_MISSING_TAG_YIELDS_NULL_VALUEの件
KETTLE_XML_MISSING_TAG_YIELDS_NULL_VALUEをYにしていると、ステップ「XMLデータ取得(Get data from XML)」でXPathに関数を使えない。
Pentaho 9.4 でも Pentaho 10.2でも再現する。
音声解説
Google NotebookLMで音声解説を作ってもらいました。動画はまだ英語のみなんだけど近日中に他言語にも対応するとの事。
パラメタ整理
データベースでの空データとnullの扱いを調整するためのパラメタ KETTLE_EMPTY_STRING_DIFFERS_FROM_NULL の追加が発端の模様。
https://github.com/pentaho/pentaho-kettle/commit/6d0e66de465e25f2623614e2e9971f42be3673bc
区別が必要になったためか、他にもパラメタが新設された。KETTLE_XML_MISSING_TAG_YIELDS_NULL_VALUEもそのうちの一つ。
# | プロパティ | 説明 | デフォルト | 設定値等 |
---|---|---|---|---|
1 | KETTLE_EMPTY_STRING_DIFFERS_FROM_NULL | Pentaho全体でのnull値扱い指定 | N | デフォルトはnullとemptyを区別しない Yを指定するとnullとemptyを区別する |
2 | KETTLE_DO_NOT_NORMALIZE_NULL_STRING_TO_EMPTY | nullの文字列をemptyに変換するか否か | N | デフォルトはnullをemptyへ変換する Yを指定するとnullをemptyへ変換しない |
3 | KETTLE_XML_EMPTY_TAG_YIELDS_EMPTY_VALUE | 空タグ時、値にnullを生成するか否か | N | デフォルトはnullを生成する Yを指定するとnullを生成しない(empty) |
4 | KETTLE_XML_MISSING_TAG_YIELDS_NULL_VALUE | 指定タグが無い場合nullを生成するか否か | N | デフォルトはemptyを生成する Yを指定するとnullを生成する |
empty : ISBLANK()=Trueになる値
推理
KETTLE_XML_MISSING_TAG_YIELDS_NULL_VALUE=Y で事が起こるのは、XPathの関数をノード(タグ)だと思って探しに行く処理になっているのではないかと。
※このパラメタ有効時は、すべてノード(タグ)だと思って処理しているもしくは関数が来ることを想定していない
GitHubリポジトリのコードが現行と一致すると仮定する。
KETTLE_XML_MISSING_TAG_YIELDS_NULL_VALUE=Y の時はSelectSingleNodeメソッドを使うようだけど、ノード検索メソッドならXPath関数は当然ヒットしない。
ValueOfメソッドはXPath関数の評価まで面倒を見てくれているんじゃないかな。
追加検証
うるさい人が湧いたので実際にコード書いて確かめよう。
検証用のコードはこちら。
- xpathCheck.java
package xpathCheck; import org.dom4j.Document; import org.dom4j.io.SAXReader; public class XPathCheck { public static void main(String[] args) { boolean xmlMissingTagYieldsNullValue = false; // KETTLE_XML_MISSING_TAG_YIELDS_NULL_VALUE=N を模す※デフォルト String filePath = "D:\\pleiades\\sampledata\\Sample.xml"; String xpathExpression = "count(/root/employees/employee)"; SAXReader rdr = new SAXReader() ; String nodeValue; try { Document doc = rdr.read(filePath); // KETTLE_XML_MISSING_TAG_YIELDS_NULL_VALUE 問題処理の再現 if(xmlMissingTagYieldsNullValue) { nodeValue = doc.selectSingleNode(xpathExpression) != null ? doc.valueOf(xpathExpression) : null; } else { nodeValue = doc.valueOf(xpathExpression); } System.out.println("XPath: " + xpathExpression); System.out.println("Node Value: " + nodeValue); } catch (Exception e) { e.printStackTrace(); } } }
入力データはこちら。
- Sample.xml
<root> <employees> <employee> <name>hoge</name> <desc>hogehoge</desc> </employee> <employee> <name>fuga</name> <desc>fugafuga</desc> </employee> </employees> </root>
まずデフォルト時(Nが指定された状態)での実行結果。
さて次はオプション指定(Yが指定された状態)状態にする。この個所をfalse→trueに変更して実行。
boolean xmlMissingTagYieldsNullValue = true; // KETTLE_XML_MISSING_TAG_YIELDS_NULL_VALUE=Y を模す※オプション指定状態
実行結果。見た覚えのあるエラーが出てますでしょ?
念のため、関数ではなく存在しないノードの検索にしてみましょうか。
String xpathExpression = "/root/employees/employee/age";
実行結果。修正者は関数の時もこの状態が来ると思ってあのコードにしたんでしょうね。やっぱりテストケース不足です。
暫定修正
ぶっちゃけ、valueOf()の処理結果とオプション指定を見て、emptyをnullに変えりゃよかったんですよ。
- xpathCheck2.java
package xpathCheck; import org.dom4j.Document; import org.dom4j.io.SAXReader; public class XPathCheck { public static void main(String[] args) { boolean xmlMissingTagYieldsNullValue = true; // KETTLE_XML_MISSING_TAG_YIELDS_NULL_VALUE=Y を模す String filePath = "D:\\pleiades\\sampledata\\Sample.xml"; String xpathExpression = "count(/root/employees/employee)"; SAXReader rdr = new SAXReader() ; String nodeValue; try { Document doc = rdr.read(filePath); // 暫定的な修正例 nodeValue = doc.valueOf(xpathExpression); if((xmlMissingTagYieldsNullValue)&&(nodeValue.length() == 0)) nodeValue = null; System.out.println("XPath: " + xpathExpression); System.out.println("Node Value: " + nodeValue); } catch (Exception e) { e.printStackTrace(); } } }
関数の結果も返るし、
存在しないノードの結果はnullになる。
String xpathExpression = "/root/employees/employee/age";