2
votes

My current XPath returns ancestor-or-self nodes matching criteria.

//*[contains(., '"& v_search &"')]/ancestor-or-self::*/*[local-name()='name' and @locale='en']

Now I want to implement addition feature to return following-sibling from the matching nodes. I have changed my XPath as below. But it doesn't return ancestor-or-self plus sibling in result.

//*[contains(., '"& v_search &"')]/ancestor-or-self::*/following-sibling::*/*[local-name()='name' and @locale='en']

here v_search is a variable that can be replaced by any string for testing. My xml is like :-

<root xmlns="https://jlkjsdlfjl/">
    <name>Accounts</name>
    <property name="included" type="hidden">true</property>
    <locales>
        <locale>en</locale>
        <locale>de</locale>
    </locales>
    <defaultLocale>en</defaultLocale>
    <searchspace>
        <name locale="en">Accounts</name>
        <name locale="de">Accounts</name>
        <lastChanged>2014-03-05T18:47:30</lastChanged>
        <lastChangedBy>userx</lastChangedBy>
        <property name="included" type="hidden">true</property>
        <searchspace>
            <name locale="en">Database L</name>
            <name locale="zw">Database L</name>
            <searchSubject status="valid">
                <name locale="en">SName1</name>
                <name locale="zw">qskxyz</name>
                <searchItem>
                    <name locale="en">IName1</name>
                    <name locale="zw">qixyz</name>
                    <hello>v_search</hello>
                </searchItem>
                 <searchItem>
                    <name locale="en">IName2</name>
                    <name locale="zw">abc</name>
                    v_search
                </searchItem>
                 <searchItem>
                    <name locale="en">IName3</name>
                    <name locale="zw">def</name>
                    <hello>something else</hello>
                </searchItem>
            </searchSubject>
        </searchspace>
    </searchspace>
    <searchspace>
        <name locale="en">Names</name>
        <lastChanged>2016-01-12T12:42:46</lastChanged>
        <searchspace>
            <name locale="en">Database Layer</name>
            <name locale="zw">Database Layer</name>
            <searchSubject status="valid">
                <name locale="en">SName2</name>
                <searchItem>
                    <name locale="en">IName4</name>
                    <hello>...Hi there..</hello>
                </searchItem>
            </searchSubject>
        </searchspace>
    </searchspace>
</root>

v_search is sample keyword, I want to return sibling of lowest matching nodes. i.e. sibling of self from ancestor-or-self.

1
Currently, it isn't clear following-sibling of which element that you mean; following-sibling of matching element or following-sibling of ancestor of matching element? - har07
Maybe it will help if you provide sample keyword and elements you expect to be selected given that keyword and the above XML.. - har07
I have added last line with edit - Kailash Singh
Alright, that sounds clearer. But now my confusion is, that the matching element (<hello>v_search</hello>) in the given scenario doesn't have any following-sibling. So, what element(s) do you actually mean by following-sibling of the v_search element here? - har07
IName2 has matching value v_search and it also has a sibling following it IName3. So the result should be ancestor-or-self of IName2 and sibling of IName2 that is IName3. - Kailash Singh

1 Answers

1
votes

The easiest way might be to introduce 2nd expression that will return 'following-sibling' of the matched element. You can combine the 2nd expression with the existing one using union (|) operator as follow (wrapped for readability) :

//*[contains(., 'v_search')]
 /ancestor-or-self::*
 /*[local-name()='name' and @locale='en']
    |
//*[text()[contains(.,'v_search')]]
 /following-sibling::*
 /*[local-name()='name' and @locale='en']

Brief test : http://www.xpathtester.com/xpath/294a1ef49d30eb6abecf2f024cfcd318