2013-07-24 3 views
6

以下のサンプルコードでは、 '// elementName'という形式のXPathは、ソースxmlに名前空間接頭辞下のコード)。xmlに名前空間プレフィックスがある場合、特定のXPath式だけがノードを見つけるのはなぜですか?

ソースxmlに名前空間接頭辞がない場合、リストされたすべてのXPath式がノードを返します(testNoNS()参照)。

私はNamespaceContext(testWithNSContext()のように)を設定し、xmlを名前空間認識ドキュメントとして解析し、XPathで名前空間接頭辞を使用することでこれを解決できることは分かっています。しかし、私は実際のコードがネームスペースプレフィックスの有無にかかわらずxmlを処理する必要があるので、これをしたくありません。

それがあるだけで、なぜ私の質問は次のとおりです。

  • //テスト
  • // child1の
  • // grandchild1
  • // child2のはまだnullを返し

testWithNS()の他のすべての例はノードを返しますか?

出力

testNoNS() 
test = found 
/test = found 
//test = found 
//test/* = found 
//test/child1 = found 
//test/child1/grandchild1 = found 
//test/child2 = found 
//child1 = found 
//grandchild1 = found 
//child1/grandchild1 = found 
//child2 = found 

testWithNS() 
test = found 
/test = found 
//test = *** NOT FOUND *** 
//test/* = found 
//test/child1 = found 
//test/child1/grandchild1 = found 
//test/child2 = found 
//child1 = *** NOT FOUND *** 
//grandchild1 = *** NOT FOUND *** 
//child1/grandchild1 = found 
//child2 = *** NOT FOUND *** 

testWithNSContext() 
ns1:test = found 
/ns1:test = found 
//ns1:test = found 
//ns1:test/* = found 
//ns1:test/ns1:child1 = found 
//ns1:test/ns1:child1/ns1:grandchild1 = found 
//ns1:test/ns1:child2 = found 
//ns1:child1 = found 
//ns1:grandchild1 = found 
//ns1:child1/ns1:grandchild1 = found 
//ns1:child2 = found 

コード私は今、サクソン人はこの

にXPahtFactoryラインを変更する使用して同じコードをテストしている

サクソンテスト以下

import java.io.StringReader; 
import java.util.Iterator; 

import javax.xml.XMLConstants; 
import javax.xml.namespace.NamespaceContext; 
import javax.xml.parsers.DocumentBuilderFactory; 
import javax.xml.xpath.XPath; 
import javax.xml.xpath.XPathConstants; 
import javax.xml.xpath.XPathFactory; 

import org.junit.Test; 
import org.w3c.dom.Document; 
import org.xml.sax.InputSource; 

public class XPathBugTest { 

    private String xmlDec = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>"; 
    private String xml = xmlDec + 
     "<test>" + 
     " <child1>" + 
     " <grandchild1/>" + 
     " </child1>" + 
     " <child2/>" + 
     "</test>"; 
    private String xmlNs = xmlDec + 
     "<ns1:test xmlns:ns1=\"http://www.wfmc.org/2002/XPDL1.0\">" + 
     " <ns1:child1>" + 
     " <ns1:grandchild1/>" + 
     " </ns1:child1>" + 
     " <ns1:child2/>" + 
     "</ns1:test>"; 

    final XPathFactory xpathFactory = XPathFactory.newInstance(); 
    final XPath xpath = xpathFactory.newXPath(); 

    @Test 
    public void testNoNS() throws Exception { 
     System.out.println("\ntestNoNS()"); 
     final Document doc = getDocument(xml); 

     isFound("test", xpath.evaluate("test", doc, XPathConstants.NODE)); 
     isFound("/test", xpath.evaluate("/test", doc, XPathConstants.NODE)); 
     isFound("//test", xpath.evaluate("//test", doc, XPathConstants.NODE)); 
     isFound("//test/*", xpath.evaluate("//test/*", doc, XPathConstants.NODE)); 
     isFound("//test/child1", xpath.evaluate("//test/child1", doc, XPathConstants.NODE)); 
     isFound("//test/child1/grandchild1", xpath.evaluate("//test/child1/grandchild1", doc, XPathConstants.NODE)); 
     isFound("//test/child2", xpath.evaluate("//test/child2", doc, XPathConstants.NODE)); 
     isFound("//child1", xpath.evaluate("//child1", doc, XPathConstants.NODE)); 
     isFound("//grandchild1", xpath.evaluate("//grandchild1", doc, XPathConstants.NODE)); 
     isFound("//child1/grandchild1", xpath.evaluate("//child1/grandchild1", doc, XPathConstants.NODE)); 
     isFound("//child2", xpath.evaluate("//child2", doc, XPathConstants.NODE)); 
    } 

    @Test 
    public void testWithNS() throws Exception { 
     System.out.println("\ntestWithNS()"); 
     final Document doc = getDocument(xmlNs); 

     isFound("test", xpath.evaluate("test", doc, XPathConstants.NODE)); 
     isFound("/test", xpath.evaluate("/test", doc, XPathConstants.NODE)); 
     isFound("//test", xpath.evaluate("//test", doc, XPathConstants.NODE)); 
     isFound("//test/*", xpath.evaluate("//test/*", doc, XPathConstants.NODE)); 
     isFound("//test/child1", xpath.evaluate("//test/child1", doc, XPathConstants.NODE)); 
     isFound("//test/child1/grandchild1", xpath.evaluate("//test/child1/grandchild1", doc, XPathConstants.NODE)); 
     isFound("//test/child2", xpath.evaluate("//test/child2", doc, XPathConstants.NODE)); 
     isFound("//child1", xpath.evaluate("//child1", doc, XPathConstants.NODE)); 
     isFound("//grandchild1", xpath.evaluate("//grandchild1", doc, XPathConstants.NODE)); 
     isFound("//child1/grandchild1", xpath.evaluate("//child1/grandchild1", doc, XPathConstants.NODE)); 
     isFound("//child2", xpath.evaluate("//child2", doc, XPathConstants.NODE)); 
    } 

    @Test 
    public void testWithNSContext() throws Exception { 
     System.out.println("\ntestWithNSContext()"); 
     final Document doc = getDocumentNS(xmlNs); 

     xpath.setNamespaceContext(new MyNamespaceContext()); 

     isFound("ns1:test", xpath.evaluate("ns1:test", doc, XPathConstants.NODE)); 
     isFound("/ns1:test", xpath.evaluate("/ns1:test", doc, XPathConstants.NODE)); 
     isFound("//ns1:test", xpath.evaluate("//ns1:test", doc, XPathConstants.NODE)); 
     isFound("//ns1:test/*", xpath.evaluate("//ns1:test/*", doc, XPathConstants.NODE)); 
     isFound("//ns1:test/ns1:child1", xpath.evaluate("//ns1:test/ns1:child1", doc, XPathConstants.NODE)); 
     isFound("//ns1:test/ns1:child1/ns1:grandchild1", xpath.evaluate("//ns1:test/ns1:child1/ns1:grandchild1", doc, XPathConstants.NODE)); 
     isFound("//ns1:test/ns1:child2", xpath.evaluate("//ns1:test/ns1:child2", doc, XPathConstants.NODE)); 
     isFound("//ns1:child1", xpath.evaluate("//ns1:child1", doc, XPathConstants.NODE)); 
     isFound("//ns1:grandchild1", xpath.evaluate("//ns1:grandchild1", doc, XPathConstants.NODE)); 
     isFound("//ns1:child1/ns1:grandchild1", xpath.evaluate("//ns1:child1/ns1:grandchild1", doc, XPathConstants.NODE)); 
     isFound("//ns1:child2", xpath.evaluate("//ns1:child2", doc, XPathConstants.NODE)); 
    } 

    private void isFound(String xpath, Object object) { 
     System.out.println(xpath + " = " + (object == null ? "*** NOT FOUND ***" : "found")); 
    } 

    private Document getDocument(final String xml) throws Exception { 
     final DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); 
     return factory.newDocumentBuilder().parse(new InputSource(new StringReader(xml)));   
    } 

    private Document getDocumentNS(final String xml) throws Exception { 
     final DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); 
     factory.setNamespaceAware(true); 
     return factory.newDocumentBuilder().parse(new InputSource(new StringReader(xml))); 
    } 

    public class MyNamespaceContext implements NamespaceContext { 
     @Override 
     public String getNamespaceURI(String prefix) { 
      if ("ns1".equals(prefix)) { 
       return "http://www.wfmc.org/2002/XPDL1.0"; 
      } 
      return XMLConstants.NULL_NS_URI; 
     } 
     @Override 
     public String getPrefix(String uri) { 
      throw new UnsupportedOperationException(); 
     } 
     @Override 
     public Iterator getPrefixes(String uri) { 
      throw new UnsupportedOperationException(); 
     } 
    } 
} 

更新サクソンにtestWithNS()リターン*** NOT FOUND ***ではなく、デフォルトのXalanの実装と同様に「// がelementName」のようなものだけですべての行を使用して
final XPathFactory xpathFactory = new net.sf.saxon.xpath.XPathFactoryImpl(); 

xmlを解析するためにネームスペースを認識しないドキュメントビルダーファクトリを使用していることを考えれば、なぜこれらのxpathは機能しないのですか?

+3

XPath実装のバグのようです。 – obecker

+1

私はそれを疑問に思っていましたが、それは誰かにとって明らかなことかもしれません。私はサクソンと上記を試し、何が起こるかを報告します。 –

答えて

1

あなたが名前空間を無視したい場合は、あなたがlocal-name XPath関数を使用することができます。

のどれもしない、なぜ私は、XMLを解析するための非名前空間認識ドキュメントビルダーファクトリを使用していることを考えると
//*[local-name()='grandchild1'] 
+0

ありがとうございます。私はこのような方法があることを知っていますが、私の質問は**なぜ**私のXPathで動作しますが他のものではないのですか? –

1

これらのxpathは機能し、一部はXalanで動作しますか?

XPath言語は、ネームスペース形式のXMLドキュメントとフラグメントでのみ定義されます。ネームスペースをサポートせずに解析した場合、すべてのベットがオフになっているため、ネームスペースを認識できないパーサーによって作成されたDOMでXPath式が正常に動作するという保証はありません(問題のドキュメントでは名前空間が使用されていなくても) 。

私は、NSに対応していないドキュメントを提供するときに、Javaの組み込みXSLTプロセッサと大きく矛盾した動作を経験したことが分かりました。

+0

興味深い。あなたは情報源を挙げることができますか? (XPath言語はXPath言語でしか定義されていません...) – LarsH

+1

@LarsH "XPathで操作されるXML文書は、XML名前空間の推奨事項[XML Names]に準拠している必要があります。 ([XPath仕様、セクション5「データモデル」](http://www.w3.org/TR/xpath/#data-model)) –

関連する問題