3

Given the following tricky XML:

<Type>
    <ID></ID>
    <Name></Name>
    <Child>
        <Type>
            <ID></ID>
            <Name></Name>
            <Child>
                <Type>
                    <ID></ID>
                    <Name></Name>
                    <Child>
                        <Type>
                            <ID></ID>
                            <Name></Name>
                            <Child>
                                <Type>
                                    <ID></ID>
                                    <Name>FIND ME</Name>
                                </Type>
                            </Child>
                        </Type>
                    </Child>
                </Type>
            </Child>
        </Type>
    </Child>
</Type>

Is it possible to obtains the deepest Type's Name field? I've tried constructions like that:

//*not(*)

but with no results..

Kirill Polishchuk
  • 54,804
  • 11
  • 122
  • 125
Vladimir Kishlaly
  • 1,872
  • 1
  • 16
  • 26
  • You might want to look at this question : http://stackoverflow.com/questions/11135620/how-to-get-the-most-deeply-nested-element-nodes-using-xpath-implementation-wit – koopajah Dec 06 '12 at 21:32
  • 1
    possible duplicate of [How do you find the deepest node (steps) - Xpath - php - xml -](http://stackoverflow.com/questions/9890097/how-do-you-find-the-deepest-node-steps-xpath-php-xml) – Marc B Dec 06 '12 at 21:33
  • yes, it was the same as post in your link. thanks! – Vladimir Kishlaly Dec 06 '12 at 21:45

2 Answers2

4

I. This short and simple XPath 1.0 expression:

//*[not(../*/*)]

when evaluated against the provided XML document:

<Type>
    <ID></ID>
    <Name></Name>
    <Child>
        <Type>
            <ID></ID>
            <Name></Name>
            <Child>
                <Type>
                    <ID></ID>
                    <Name></Name>
                    <Child>
                        <Type>
                            <ID></ID>
                            <Name></Name>
                            <Child>
                                <Type>
                                    <ID></ID>
                                    <Name>FIND ME</Name>
                                </Type>
                            </Child>
                        </Type>
                    </Child>
                </Type>
            </Child>
        </Type>
    </Child>
</Type>

selects these two elements:

<ID/>
<Name>FIND ME</Name>

Therefore, in your case one XPath expression that produces the wanted result is:

//*[not(../*/*)]/Name

II. Generic XPath 1.0 expression that selects the elements with maximum depth when it is known that the maximum depth isn't greater than a given number:

   //*[count(ancestor::*) >= 9]
   |
    //*[not(//*[count(ancestor::*) >= 9])]
                    [count(ancestor::*) = 8]
   |
    //*[not(//*[count(ancestor::*) >= 8])]
                    [count(ancestor::*) = 7]
   |
    //*[not(//*[count(ancestor::*) >= 7])]
                    [count(ancestor::*) = 6]
   |
    //*[not(//*[count(ancestor::*) >= 6])]
                    [count(ancestor::*) = 5]
   |
    //*[not(//*[count(ancestor::*) >= 5])]
                    [count(ancestor::*) = 4]
   |
    //*[not(//*[count(ancestor::*) >= 4])]
                    [count(ancestor::*) = 3]
   |
    //*[not(//*[count(ancestor::*) >= 3])]
                    [count(ancestor::*) = 2]
   |
    //*[not(//*[count(ancestor::*) >= 2])]
                    [count(ancestor::*) = 1]

   |
    /*[not(//*[count(ancestor::*) >= 1])]

While this seems a very long and unwieldy, an XML document typically is not more than 4-5 level deep and such expression is actually practical.


III. Generic XPath 2.0 solution:

//*[not(*) and count(ancestor::*) = max(//*/count(ancestor::*))]
Dimitre Novatchev
  • 240,661
  • 26
  • 293
  • 431
2

Try this XPath:

//Type[not(descendant::Type)]/Name
Mads Hansen
  • 63,927
  • 12
  • 112
  • 147
Kirill Polishchuk
  • 54,804
  • 11
  • 122
  • 125
  • 1
    This one worked like a charm for me. I was looking for a way to create correct XPath for automation testing to select elements that consisted of multiple spans by text content and this simple solution worked. Thank you! – Maciej Sawicki Nov 24 '22 at 16:41