3

I'm currently working with Open Street Maps data and I'm trying to select the preceding and following sibling of a specific node.

My queries currently look like this :

/osm/way/nd[@ref=203936110]/following-sibling::nd[1]
/osm/way/nd[@ref=203936110]/preceding-sibling::nd[1]

These queries work as expected but I'd like to merge them into a single query. I did found some examples mentioning that this is possible but for some reason I haven't been able to find the right syntax to make it work.

This query, for example, is invalid :

/osm/way/nd[@ref=203936110]/(following-sibling::nd[1] or preceding-sibling::nd[1])
Community
  • 1
  • 1
louisroy
  • 87
  • 1
  • 9

1 Answers1

3

If you are using lxml (which currently only supports XPath version 1.0), you have to spell out each XPath entirely, and join them with |:

'''/osm/way/nd[@ref=203936110]/following-sibling::nd[1] 
   | /osm/way/nd[@ref=203936110]/preceding-sibling::nd[1]'''

For example,

import lxml.etree as ET
content = '''\
<record>
    <nd>First</nd>
    <nd>Second</nd>
    <nd ref="203936110"></nd>
    <nd>Third</nd>
    <nd>Fourth</nd>    
</record>'''
root = ET.fromstring(content)

for elt in root.xpath('''
    //nd[@ref="203936110"]/following-sibling::nd[1]
    |
    //nd[@ref="203936110"]/preceding-sibling::nd[1]'''):

    print(elt.text)

yields

Second
Third
unutbu
  • 842,883
  • 184
  • 1,785
  • 1,677
  • You could also "or" them in a predicate: '//nd[following-sibling::nd[1][@ref="203936110"] or preceding-sibling::nd[1][@ref="203936110"]]' But I think unioning the nodesets is probably a better approach. – brjaga Dec 03 '13 at 20:40
  • @brjaga: That would match `nd`s that *have* a following-sibling or preceding-sibling -- not the siblings themselves. – unutbu Dec 03 '13 at 22:48
  • The nodes we're looking for are `nd`s (`following-sibling::nd[1]`). The node found by `//nd[@ref="blah"]/following-sibling::nd[1]` is the same one found by `//nd[preceding-sibling::nd[1][@ref="blah"]]` (you can check it with the example above). In general, I do think the unioning option is more elegant, but I've run into certain situations where I can only get an axis to work inside a predicate. – brjaga Dec 04 '13 at 18:21
  • @brjaga: Oops, I mispoke -- you are correct. That's an interesting alternative. – unutbu Dec 04 '13 at 19:33