XPath में HtmlUnit के साथ डिफ़ॉल्ट नामस्थान चुनें




groovy namespaces (2)

मैं एचटीएमएलयूनिट के साथ फीडबर्नर फ़ीड को पार्स करना चाहता हूं। फीड यह है: http://feeds.feedburner.com/alcoanewsreleases

इस फीड से मैं सभी मद नोड्स पढ़ना चाहता हूं, इसलिए सामान्य तौर पर एक //item 1000 //item सीधा करने चाहिए I दुर्भाग्य से इस मामले में यह काम नहीं करता है।

ग्रोवी कोड स्निपेट:

def page = webClient.getPage("http://feeds.feedburner.com/alcoanewsreleases")
def elements = page.getByXPath("//item")

एक्सएमएल फ़ीड का नमूना:

<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss1full.xsl"?>
<?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?>

<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns="http://purl.org/rss/1.0/" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0">

[...SNIP...]

<item rdf:about="http://www.alcoa.com/global/en/news/news_detail.asp?newsYear=2011&amp;pageID=20110518006002en">
    <title>Chris L. Ayers Named President, Alcoa Global Primary Products</title>
    <dc:date>2011-05-18</dc:date
    <link>http://feedproxy.google.com/~r/alcoanewsreleases/~3/PawvdhpJrkc/news_detail.asp</link>
    <description>NEW YORK--(BUSINESS WIRE)--Alcoa (NYSE:AA) announced today that Chris L. Ayers has been named President of Alcoa’s Global Primary Products (GPP) business, effective May 18, 2011. Ayers, previously Chief Operating Officer of GPP, succeeds John Thuestad, who will be handling special projects for the Company. Ayers joined Alcoa in February 2010 as Chief Operating Officer of Alcoa Cast, Forged and Extruded Products, a new position. He was elected a Vice President of Alcoa in April 2010 and Executive</description>
    <feedburner:origLink xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0">http://www.alcoa.com/global/en/news/news_detail.asp?newsYear=2010&amp;pageID=20100104006194en</feedburner:origLink>
</item>

[...SNIP...]

</rdf:RDF>

मुझे यह संदेह है कि नामस्थान के साथ कोई समस्या हो, क्योंकि इस दस्तावेज़ में 4 नामस्थान हैं I नामस्थान हैं

  • (यह डिफ़ॉल्ट है) xmlns = "http://purl.org/rss/1.0/"
  • xmlns: rdf = "http://www.w3.org/1999/02/22-rdf-syntax-ns#"
  • xmlns: डीसी = "http://purl.org/dc/elements/1.1/"
  • xmlns: feedburner = "http://rssnamespace.org/feedburner/ext/1.0"

मैंने इस के साथ नोकोगीरी का उपयोग करने की कोशिश की है (एक अन्य एक्सएमएल पार्सर जिसे मैं रूबी स्क्रिप्ट के लिए उपयोग करता हूं)। नोकोगीरी के साथ मैं सिर्फ हमें XPath //xmlns:item जो काम करता है और फ़ीड से सभी नोड्स लौटाता है।

मैंने उसी XPath को HtmlUnit के साथ की कोशिश की है लेकिन यह काम नहीं करता है

इसलिए मुझे लगता है कि मैं अपना प्रश्न इस रूप में कर सकता हूं: मैं डिफ़ॉल्ट नाम स्थान से HtmlUnit के साथ एक नोड कैसे चुन सकता हूं?

कोई विचार?


यह काफी परिचित लगता है कि मुझे पूरा यकीन है कि मैंने नामस्थान और XPath को सफलतापूर्वक HtmlUnit के साथ अतीत में उपयोग किया है, लेकिन निश्चित रूप से मुझे कोड नहीं मिल सकता है। मुझे संदेह है कि यह केवल HTML पृष्ठों के साथ ही होगा: आपके उदाहरण में page संदर्भ एक XmlPage जिसमें XmlPage के लिए विशिष्ट कई विधियां हैं, जिनमें से सभी प्रयोग किए जाने पर "अभी तक कार्यान्वित नहीं" अपवाद फेंक देते हैं। :-(

HtmlUnit का वर्तमान संस्करण (2.8) लगभग एक वर्ष का है, इसलिए हो सकता है कि इस बीच में XML नामस्थानों का समर्थन करने के लिए कुछ काम किया गया है। "HtmlUnit उपयोगकर्ता" मेलिंग सूची का पता लगाने का स्थान होगा।

इस बीच, हमेशा एक वैकल्पिक हल होता है:

final XmlPage page = webClient.getPage("http://feeds.feedburner.com/alcoanewsreleases");

// no good
List elements = page.getByXPath("//item");
System.out.println( elements.size() ) ;

// ugly, but it works
DomElement de = (DomElement)page.getFirstByXPath( "//rdf:RDF" );
List<DomNode> items = new ArrayList<DomNode>() ;
for( DomNode dn : de.getChildNodes() )
{
    String name = dn.getLocalName() ;
    if( ( name != null ) && ( name.equals( "item" ) ) )
        items.add( dn ) ;
}
System.out.println( "found " + items.size() ) ;

ओह लड़का जावा स्काला में काम करने के बाद दर्दनाक है ... ;-)


इस फीड से मैं सभी मद नोड्स पढ़ना चाहता हूं, इसलिए सामान्य तौर पर एक //item 1000 //item सीधा करने चाहिए I दुर्भाग्य से इस मामले में यह काम नहीं करता है।

XPath में, इसका अर्थ है "उन सभी तत्वों का चयन करें जिनके स्थानीय नाम item हैं जो कोई नाम स्थान में नहीं हैं "। आरएसएस में, item तत्वों को एक नेमस्पेस में होना चाहिए। इसलिए उपरोक्त किसी भी अनुरूप XML पार्सर और XPath इंजन के साथ काम नहीं करना चाहिए।

भ्रामक यह है कि एक्सएमएल में, <item> अर्थ है "एक तत्व नाम दिया गया है जो डिफ़ॉल्ट नेमस्पेस में है, अर्थात जो दस्तावेज़ में इस स्थान पर कुछ भी डिफ़ॉल्ट नाम स्थान है;" जबकि XPath में, "आइटम" का अर्थ किसी भी नाम स्थान में नहीं है। (या, आप कह सकते हैं, इसका मतलब डिफ़ॉल्ट नेमस्पेस में एक तत्व है, लेकिन जब तक आपके पास XPath को डिफ़ॉल्ट नाम स्थान नहीं बताया जाता है, तो डिफ़ॉल्ट नेमस्पेस नामस्थान नहीं है। आमतौर पर (हमेशा?) XPath 1.0 में कोई रास्ता नहीं है XPath अभिव्यक्ति के लिए डिफ़ॉल्ट नेमस्पेस घोषित करने के लिए।)

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

नोकोगीरी के साथ मैं सिर्फ हमें XPath //xmlns:item जो काम करता है और फ़ीड से सभी नोड्स लौटाता है।

जो भी हो, यह नहीं है XPath। हो सकता है कि यह एक नोकोगीरी विस्तार है (एक बहुत सुविधाजनक है, लेकिन इसकी वाक्य-रचना वास्तव में प्रति-सहज ज्ञान युक्त है)

इसलिए मुझे लगता है कि मैं अपना प्रश्न इस रूप में कर सकता हूं: मैं डिफ़ॉल्ट नाम स्थान से HtmlUnit के साथ एक नोड कैसे चुन सकता हूं?

चलो यह रूप में वाक्यांश: मैं HtmlUnit के साथ आरएसएस आइटम तत्वों का चयन कैसे कर सकता हूँ? मुझे यह वाक्यांश इस तरह से है क्योंकि आरएसएस युक्ति (वास्तव में किसी भी XML शब्दावली के सामान्य अनुरूप) को इसकी आवश्यकता नहीं है कि इसके तत्व डिफ़ॉल्ट नेमस्पेस में होंगे। यह आपके द्वारा प्राप्त किए गए नमूने में सच होना होता है, लेकिन सेवा प्रदाता उस कल को बदल सकता है और अभी भी आरएसएस के अनुरूप हो सकता है। कल, सेवा प्रदाता उस नेमस्पेस के लिए "आरएसएस" नाम स्थान उपसर्ग का उपयोग कर सकता है; या किसी भी अन्य मनमानी उपसर्ग आरएसएस क्या निर्दिष्ट करता है कि इसके नामों का नाम क्या होगा: नाम स्थान जिसका यूआरआइ http://purl.org/rss/1.0/

यह पूछने जैसा है, "मैं जावास्क्रिप्ट, सी, जावा आदि में एक फ़ंक्शन कैसे लिख सकता हूं जो कि मुझे वैरिएबल के मान बता सकता a ?" आम तौर पर एक फ़ंक्शन को पता नहीं है कि कॉलर में क्या चर नाम का उपयोग किया गया था। यह सब जानते हैं कि इसके तर्कों के मूल्य हैं। यदि आप sqrt(4) , तो आपको a = 4; sqrt(a) साथ a = 4; sqrt(a) ही उत्तर मिलेगा a = 4; sqrt(a) a = 4; sqrt(a) या rumpelstiltzkin = 4; sqrt(rumpelstiltzkin) rumpelstiltzkin = 4; sqrt(rumpelstiltzkin) स्पष्ट रूप से, चर तर्क के नाम का फ़ंक्शन कॉल के परिणाम पर कोई प्रत्यक्ष प्रभाव नहीं होता है। यह सिर्फ एक वैरिएबल का नाम होना चाहिए जो सही मूल्य रखती है। यदि एक कंपाइलर शिकायत करता है क्योंकि आपने b = 4; return sqrt(b) लिखा है b = 4; return sqrt(b) b = 4; return sqrt(b) a का उपयोग करने के बजाय, आपको लगता था कि संकलक पागल था। जब तक आप वैध आइडेंटिफ़ायर का उपयोग करते हैं तब तक यह चर नामों के बारे में ध्यान नहीं रखता है।

उसी तरह, जब आरएसएस का प्रसंस्करण किया जाता है, तब तक हमें ध्यान नहीं दिया जाता है कि नेमसैस उपसर्ग का उपयोग किस प्रकार किया जाता है, जब तक यह एक उपसर्ग है जो सही नेमस्पेस को पहचानता है। यह कोई उपसर्ग नहीं हो सकता (जो कि डिफ़ॉल्ट नेमस्पेस को पहचानती है)।

XPath 2.0 में, आप नाम स्थान पर वाइल्डकार्ड कर सकते हैं। यह बहुत आसान है यदि आप जानते हैं कि आप निंदा के लिए नामस्थान की जरूरत नहीं जा रहे हैं। उस मामले में आप //*:item चयन कर सकते हैं। हालांकि, मुझे नहीं लगता कि HTMLUnit XPath 2.0 का समर्थन करता है। XPath 2.0 परिवेश जैसे XSLT 2.0 में, आप XPath अभिव्यक्ति के लिए एक डिफ़ॉल्ट नेमस्पेस निर्दिष्ट कर सकते हैं, लेकिन वह HTMLUnit में आपकी सहायता नहीं करेगा।

तो आपके पास कुछ विकल्प हैं:

  • एक XPath अभिव्यक्ति का उपयोग करें जो //*[local-name = 'item'] को अनदेखा करता है, जैसे //*[local-name = 'item']

या

  • मजबूत तरीका: http://purl.org/rss/1.0/ लिए एक नेमस्पेस उपसर्ग पंजीकृत http://purl.org/rss/1.0/ और अपने XPath अभिव्यक्ति में इसका उपयोग करें: //rss:item प्रश्न तब बन जाता है, आप HTMLUnit में एक नेमस्पेस उपसर्ग कैसे पंजीकृत करते हैं और इसे XPath प्रोसेसर में पास करते हैं? मैंने डॉक्स में एक त्वरित नज़र लिया और ऐसा करने के लिए कोई सुविधा नहीं मिली।

चेतावनी: मुझे यह कहना चाहिए कि उपरोक्त XPath प्रोसेसर के अनुरूप है। मुझे नहीं पता है कि XPath प्रोसेसर HTMLUnit का उपयोग कैसे करता है। वहाँ कुछ XPath प्रोसेसर वहाँ चश्मा की अनदेखी कर रहे हैं और दुनिया को हर किसी के लिए और अधिक भ्रमित कर रहे हैं।

मैंने देखा कि किसी ने HTMLUnit में डिफ़ॉल्ट नाम स्थान में तत्वों के लिए निम्न सिंटैक्स का उपयोग किया है:

//:item

लेकिन मैं यह नहीं सुझाऊंगा कि तीन कारणों से:

  1. यह मान्य XPath नहीं है, इसलिए आप इसे अन्य कार्यक्रमों के साथ काम करने की उम्मीद नहीं कर सकते।

  2. यह केवल आरएसएस फ़ीड पर काम करेगा जो आरएसएस नाम स्थान को डिफ़ॉल्ट नेमस्पेस घोषित करते हैं। आरएसएस फीड्स जो एक नेमस्पेस उपसर्ग का उपयोग करते हैं, ऊपर से असफल होने का कारण होगा।

  3. यह आपको सीखने से वापस पकड़ देगा कि XML नामस्थान वास्तव में कैसे काम करते हैं, और यह उपकरण के यथास्थिति को संरक्षित करने में मदद करेगा जो पर्याप्त रूप से नामस्थानों का समर्थन नहीं करते हैं

HTMLUnit प्राथमिक रूप से HTML के लिए डिज़ाइन किया गया है, इसलिए एक्सएमएल का अपूर्ण प्रबंधन समझ में आता है। लेकिन XPath को समर्थन देने का दावा करते हुए और फिर नामपटल उपसर्गों को घोषित करने के तरीके प्रदान नहीं करना एक बग है HTMLUnit XPath पैकेज का उपयोग करता है जो कि Xalan-J का हिस्सा लगता है उस पैकेज में XPath को नामस्थान मैपिंग प्रदान करने के तरीके हैं , लेकिन मुझे नहीं पता कि क्या HTMLUnit उस कार्यक्षमता को उजागर करता है