2013-07-24 8 views
6

कि प्रपत्र '// elementName' वापसी अशक्त जब स्रोत एक्सएमएल एक namespace उपसर्ग में हैं किसी भी XPath नीचे दिए गए उदाहरण कोड में है (में testWithNS() देखना नीचे कोड)।क्यों केवल कुछ xPath अभिव्यक्ति नोड्स मिल रहा है जब एक्सएमएल एक नामस्थान उपसर्ग

जब स्रोत xml में नामस्थान उपसर्ग नहीं है तो सभी सूचीबद्ध XPath अभिव्यक्तियां नोड लौटाती हैं (testNoNS() देखें)।

मुझे पता है कि मैं नेमस्पेस कॉन्टेक्स्ट (testWithNSContext() में) स्थापित करके, एक्सएमएल को नेमस्पेस जागरूक दस्तावेज़ के रूप में पार्स करना और XPaths में नेमस्पेस उपसर्ग का उपयोग करके इसे हल कर सकता हूं। हालांकि मैं ऐसा नहीं करना चाहता क्योंकि मेरे वास्तविक कोड को नामस्थान उपसर्गों के साथ और बिना दोनों एक्सएमएल को संसाधित करने की आवश्यकता है।

मेरा प्रश्न क्यों यह केवल है:

  • // परीक्षण
  • // child1
  • // grandchild1
  • // child2

कि अशक्त लौटने के लिए, अभी तक 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 

कोड

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(); 
     } 
    } 
} 

सैक्सन परीक्षण

मैं अब सैक्सन इस

को XPahtFactory लाइन को बदलने का उपयोग कर एक ही कोड का परीक्षण किया है निम्नलिखित अद्यतन
final XPathFactory xpathFactory = new net.sf.saxon.xpath.XPathFactoryImpl(); 

डिफ़ॉल्ट Xalan कार्यान्वयन के साथ के रूप में सेक्सन '// elementName' की तरह testWithNS() बदले में सभी लाइनों *** NOT FOUND *** बजाय सिर्फ लोगों का उपयोग करना।

यह देखते हुए कि मैं एक्सएमएल को पार्स करने के लिए एक गैर नामस्थान जागरूक दस्तावेज़ निर्माता कारखाने का उपयोग कर रहा हूं, इनमें से कोई भी xpaths क्यों काम नहीं करता है, और केवल कुछ Xalan के साथ?

+3

XPath कार्यान्वयन में एक बग की तरह दिखता है। – obecker

+1

मैंने सोचा था कि सोचा था कि यह किसी के लिए कुछ स्पष्ट भी हो सकता है। मैं उपरोक्त सैक्सन के साथ कोशिश करूंगा और रिपोर्ट करता हूं कि क्या होता है। –

उत्तर

1

आप नामस्थान अनदेखा करना चाहते हैं, तो आप local-name XPath फ़ंक्शन का उपयोग कर सकते हैं:

//*[local-name()='grandchild1'] 
+0

धन्यवाद। मुझे पता है कि इस काम को करने के लिए इस तरह के तरीके हैं लेकिन मेरा सवाल है ** ** यह मेरे कुछ XPath के साथ क्यों काम करता है लेकिन दूसरों को नहीं? –

1

यह देखते हुए कि मैं xml पार्स करने के लिए एक गैर नाम स्थान के बारे में पता दस्तावेज़ बिल्डर कारखाने का उपयोग कर रहा है, क्यों से कोई भी नहीं ये xpaths काम करते हैं, और केवल कुछ Xalan के साथ?

XPath भाषा केवल नामस्थान-अच्छी तरह से गठित XML दस्तावेज़ों और टुकड़ों पर परिभाषित है। यदि आप नेमस्पेस समर्थन के बिना पार्स करते हैं तो सभी दांव बंद हैं, इस बात की कोई गारंटी नहीं है कि किसी भी XPath अभिव्यक्ति को गैर-नेमस्पेस-जागरूक पार्सर द्वारा बनाए गए डोम पर सही तरीके से काम करेगा (भले ही प्रश्न में दस्तावेज़ किसी भी नामस्थान का उपयोग न करे) ।

मुझे पता है कि मैंने जावा-अंतर्निहित एक्सएसएलटी प्रोसेसर से गैर-एनएस-जागरूक दस्तावेज देते समय जंगली असंगत व्यवहार देखा है।

+0

दिलचस्प। क्या आप आगे की जानकारी के लिए एक स्रोत उद्धृत कर सकते हैं? (esp "XPath भाषा केवल परिभाषित है ...") – LarsH

+1

@LarsH "एक्सपीएथ द्वारा संचालित एक्सएमएल दस्तावेज़ एक्सएमएल नेमस्पेस सिफारिश [एक्सएमएल नाम] के अनुरूप होना चाहिए।" ([XPath विनिर्देश, खंड 5 "डेटा मॉडल"] (http://www.w3.org/TR/xpath/#data-model)) –

संबंधित मुद्दे