2010-10-13 11 views
15

मैं एक XPath क्वेरी बनाना चाहता हूं जो "div" या "table" तत्व लौटाएगा, जब तक कि इसमें "abc" टेक्स्ट वाला वंशज होगा। एक चेतावनी यह है कि इसमें कोई div या table descendants नहीं हो सकता है।वंश और वंशज पाठ के साथ XPath क्वेरी

<div> 
    <table> 
    <form> 
     <div> 
     <span> 
      <p>abcdefg</p> 
     </span> 
     </div> 
     <table> 
     <span> 
      <p>123456</p> 
     </span> 
     </table> 
    </form> 
    </table> 
</div> 

तो इस प्रश्न का केवल सही परिणाम होगा:

/div/table/form/div 

मेरे सबसे अच्छे प्रयास इस तरह दिखता है:

//div[contains(//text(), "abc") and not(descendant::div or descendant::table)] | //table[contains(//text(), "abc") and not(descendant::div or descendant::table)] 

लेकिन सही परिणाम वापस नहीं करता है।

आपकी मदद के लिए धन्यवाद।

+0

अच्छा सवाल, +1। शायद सबसे छोटा समाधान क्या है इसके लिए मेरा जवाब देखें। :) –

उत्तर

32

कुछ अलग: :)

//text()[contains(.,'abc')]/ancestor::*[self::div or self::table][1] 

अन्य समाधान की तुलना में बहुत कम है लगता है, है ना? :)

सरल अंग्रेजी इसमें अनूदित: कि स्ट्रिंग "abc" अपनी पहली पूर्वज है कि या तो एक div या एक table है का चयन दस्तावेज़ में किसी भी पाठ नोड के लिए।

यह और अधिक कुशल है, केवल एक ही दस्तावेज़ पेड़ (और किसी भी अन्य नहीं) का पूरा स्कैन के रूप में की आवश्यकता है, और ancestor::* ट्रेवर्सल एक descendent:: (पेड़) स्कैन की तुलना में बहुत सस्ता है।

सत्यापित करने के लिए कि इस समाधान "वास्तव में काम करता है":

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
<xsl:output omit-xml-declaration="yes" indent="yes"/> 
<xsl:strip-space elements="*"/> 

<xsl:template match="/"> 
    <xsl:copy-of select= 
    "//text()[contains(.,'abc')]/ancestor::*[self::div or self::table][1] "/> 
</xsl:template> 
</xsl:stylesheet> 

जब इस बदलाव प्रदान की XML दस्तावेज़ पर किया जाता है:

<div> 
    <table> 
    <form> 
     <div> 
     <span> 
      <p>abcdefg</p> 
     </span> 
     </div> 
     <table> 
     <span> 
      <p>123456</p> 
     </span> 
     </table> 
    </form> 
    </table> 
</div> 

चाहता था, सही परिणाम है उत्पादित:

<div> 
    <span> 
     <p>abcdefg</p> 
    </span> 
</div> 

नोट: एक्सएसएलटी का उपयोग करना आवश्यक नहीं है - किसी भी XPath 1.0 होस्ट - जैसे कि डोम, एक ही परिणाम प्राप्त करना होगा।

+1

आपकी प्रतिक्रिया के लिए धन्यवाद और +1 के लिए धन्यवाद। मैं इस जवाब की कॉम्पैक्टनेस पसंद करता हूं, हालांकि मैं इसे अपने परीक्षणों में काम करने में असमर्थ हूं। इस प्रश्न के अन्य दो जवाब मेरे लिए काम करते हैं। क्या यह संभव है कि आपकी प्रतिक्रिया में एक टाइपो है? मैं इसे सब समझने का दावा नहीं कर सकता।[1] क्या करता है? फिर, यदि आपके पास कोई अंतर्दृष्टि है कि यह उत्तर मेरे लिए क्यों काम नहीं करता है और अन्य लोग करते हैं, तो मैं इसकी सराहना करता हूं। मैं आपके समय के लिए +1 करूंगा लेकिन मैं इस साइट पर नया हूं और अभी तक क्षमता नहीं है। धन्यवाद। – juan234

+0

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

+0

मुझे आश्वस्त है :) – juan234

1

आप की कोशिश कर सकते:

//div[ 
    descendant::text()[contains(., "abc")] 
    and not(descendant::div or descendant::table) 
] | 
//table[ 
    descendant::text()[contains(., "abc")] 
    and not(descendant::div or descendant::table) 
] 

कि मदद करता है?

1
//*[self::div|self::table] 
    [descendant::text()[contains(.,"abc")]] 
    [not(descendant::div|descendant::table)] 

contains(//text(), "abc") के साथ समस्या यह है कि फ़ंक्शंस नोड सेट पहले नोड को लेते हैं।

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