2009-02-28 10 views
14

का उपयोग करके पैरेंट नोड्स का पालन करें I XPath के साथ कुछ HTML को पार्स करने का प्रयास कर रहा हूं। नीचे सरलीकृत एक्सएमएल उदाहरण के बाद, मैं स्ट्रिंग 'टेक्स्ट 1' से मेल खाना चाहता हूं, फिर प्रासंगिक content नोड की सामग्री को पकड़ें।टेक्स्ट नोड से मिलान कैसे करें, फिर XPath

<doc> 
    <block> 
     <title>Text 1</title> 
     <content>Stuff I want</content> 
    </block> 

    <block> 
     <title>Text 2</title> 
     <content>Stuff I don't want</content> 
    </block> 
</doc> 

मेरे अजगर कोड फेंकता एक wobbly:

>>> from lxml import etree 
>>> 
>>> tree = etree.XML("<doc><block><title>Text 1</title><content>Stuff 
I want</content></block><block><title>Text 2</title><content>Stuff I d 
on't want</content></block></doc>") 
>>> 
>>> # get all titles 
... tree.xpath('//title/text()') 
['Text 1', 'Text 2'] 
>>> 
>>> # match 'Text 1' 
... tree.xpath('//title/text()="Text 1"') 
True 
>>> 
>>> # Follow parent from selected nodes 
... tree.xpath('//title/text()/../..//text()') 
['Text 1', 'Stuff I want', 'Text 2', "Stuff I don't want"] 
>>> 
>>> # Follow parent from selected node 
... tree.xpath('//title/text()="Text 1"/../..//text()') 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "lxml.etree.pyx", line 1330, in lxml.etree._Element.xpath (src/ 
lxml/lxml.etree.c:14542) 
    File "xpath.pxi", line 287, in lxml.etree.XPathElementEvaluator.__ca 
ll__ (src/lxml/lxml.etree.c:90093) 
    File "xpath.pxi", line 209, in lxml.etree._XPathEvaluatorBase._handl 
e_result (src/lxml/lxml.etree.c:89446) 
    File "xpath.pxi", line 194, in lxml.etree._XPathEvaluatorBase._raise 
_eval_error (src/lxml/lxml.etree.c:89281) 
lxml.etree.XPathEvalError: Invalid type 

XPath में यह संभव है? क्या मुझे यह व्यक्त करने की ज़रूरत है कि मैं अलग-अलग तरीके से क्या करना चाहता हूं?

उत्तर

22

क्या आप चाहते हैं?

//title[text()='Text 1']/../content/text() 
+0

ओह, सरल सच है! किंडा समझ में आता है कि मैं अब टेक्स्ट() विशेषता का चयन कर रहा हूं। – Mat

+2

प्रासंगिक सामग्री नोड – Dror

+0

@ डोरर प्राप्त करने के लिए आप // ब्लॉक [शीर्षक = 'टेक्स्ट 1']/सामग्री का भी उपयोग कर सकते हैं: अब यह जानना उपयोगी है। – Mat

16

उपयोग:

string(/*/*/title[. = 'Text 1']/following-sibling::content) 

यह कम से कम दो सुधार जोहन्नेस वेइस की वर्तमान में स्वीकार समाधान की तुलना में प्रतिनिधित्व करता है:

  1. बहुत महंगा संक्षिप्त नाम " // " (आमतौर पर कौन होता है ले एक्सएमएल दस्तावेज़ स्कैन किए जाने के लिए) से बचा है क्योंकि जब भी XML दस्तावेज़ की संरचना अग्रिम में जानी जाती है।

  2. वहाँ वापस कोई वापसी माता पिता (स्थान कदम "/ .." से बचा जाता है)

+0

उचित सुधार, मेरा वास्तविक दस्तावेज़ HTML है और 'शीर्षक' भाग लगभग पांच स्तरों को गहराई से घिरा हुआ है, इसलिए मुझे 'सामग्री' क्षेत्र में जाने के लिए लगभग पांच माता-पिता वापस जाना होगा। मैं दिमाग में पहला बिंदु सहन करूंगा, हालांकि यह एक गंदे हैक के लिए थोड़ा अंतर करेगा। – Mat

+2

'/ */* /' क्या करता है? मैं इसे काफी बड़े दस्तावेज़ पर आज़मा रहा हूं और यह '//' जितना धीमा लगता है। – dentarg

+2

@ डेंटार्ग: '/ */*' दस्तावेज़ के शीर्ष तत्व के बच्चे हैं जो सभी तत्वों का चयन करता है। यह '// someName' से तेज़ तरीका है जो पूर्ण दस्तावेज़ को पार करता है और 'कुछ नाम" नामक प्रत्येक तत्व का चयन करता है। इस जवाब में हम एक और अधिक कुशल अभिव्यक्ति का उपयोग कर सकते हैं: 'स्ट्रिंग (/ */*/शीर्षक [। =' टेक्स्ट 1 '] [1]/निम्नलिखित-भाई :: सामग्री)' उत्तर में अभिव्यक्ति नहीं होनी चाहिए कम कुशल, एक अनुकूल ऑप्टिमाइज़िंग XPath प्रोसेसर दिया गया - क्योंकि जब भी 'स्ट्रिंग() 'फ़ंक्शन एक तर्क प्रदान किया जाता है जो नोड-सेट होता है, तो यह केवल इस नोड-सेट के पहले नोड के स्ट्रिंग मान का उत्पादन करता है। –

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