次の XML インスタンスがあるとします。
<entities>
<person><name>Jack</name></person>
<person><name></name></person>
<person></person>
</entities>
次のコードを使用して、(a) 人物を反復処理し、(b) 各人物の名前を取得します。
XPathExpression expr = xpath.compile("/entities/person");
NodeList nodes = (NodeList) expr.evaluate(doc, XPathConstants.NODESET);
for (int i = 0 ; i < nodes.getLength() ; i++) {
Node node = nodes.item(i);
String innerXPath = "name/text()";
String name = xpath.compile(innerXPath).evaluate(node);
System.out.printf("%2d -> name is %s.\n", i, name);
}
上記のコードは、2 人称の場合 (名前の空の文字列) と 3 人称の場合 (name 要素がまったくない) を区別できず、単純に次のように出力します。
0 -> name is Jack.
1 -> name is .
2 -> name is .
innerXPath
別の表現を使用してこれら 2 つのケースを区別する方法はありますか? このSOの質問では、XPathの方法は空のリストを返すようですが、私もそれを試しました:
String innerXPath = "if (name) then name/text() else ()";
...そして、出力は同じです。
innerXPath
では、これら 2 つのケースを異なる表現で区別する方法はありますか? クラスパスに Saxon HE があるので、XPath 2.0 機能も使用できます。
アップデート
したがって、受け入れられた回答に基づいて私ができる最善のことは次のとおりです。
XPathExpression expr = xpath.compile("/entities/person");
NodeList nodes = (NodeList) expr.evaluate(doc, XPathConstants.NODESET);
for (int i = 0 ; i < nodes.getLength() ; i++) {
Node node = nodes.item(i);
String innerXPath = "name";
NodeList names = (NodeList) xpath.compile(innerXPath).evaluate(node, XPathConstants.NODESET);
String nameValue = null;
if (names.getLength()>1) throw new RuntimeException("impossible");
if (names.getLength()==1)
nameValue = names.item(0).getFirstChild()==null?"":names.item(0).getFirstChild().getNodeValue();
System.out.printf("%2d -> name is [%s]\n", i, nameValue);
}
上記のコードは次を出力します。
0 -> name is [Jack]
1 -> name is []
2 -> name is [null]
私の見解では、ロジックはXPathとJavaコードの両方に広がっており、ホスト言語および API に依存しない表記法としてのXPathの有用性を制限しているため、これはあまり満足のいくものではありません。私の特定の使用例は、プロパティ ファイルに XPath のコレクションを保持し、実行時にそれらを評価して、その場しのぎの追加処理なしで必要な情報を取得することでした。どうやらそれは不可能です。