@@ -12,6 +12,7 @@ Table of contents
12
12
* [ Method parse(...)] ( #method-parse )
13
13
* [ Print result modes] ( #print-result-modes )
14
14
* [ HTML support] ( #html-support )
15
+ * [ Relative expressions] ( #relative-expressions )
15
16
* [ Unqualified vs. Qualified] ( #unqualified-vs-qualified )
16
17
* [ Initial Xpath Examples] ( #initial-xpath-examples )
17
18
* [ Performance] ( #performance )
@@ -215,6 +216,68 @@ or on command line
215
216
pyxml2xpath tests/resources/html5-small.html.xml 'all' '//*[@id="math"]'
216
217
```
217
218
219
+ ## Relative expressions
220
+ Build relative expressions when passing ` xpath_base ` kword argument. The xpath of the parent should be removed so ` base_xpath ` should be like:
221
+
222
+ ` xpath_base = '//*[@id="math"]/parent::* | //*[@id="math"]/descendant-or-self::*' `
223
+
224
+ Example:
225
+
226
+ ``` python
227
+ from lxml import html
228
+ from xml2xpath import xml2xpath
229
+
230
+ filepath = ' tests/resources/html5-small.html.xml'
231
+ hdoc = html.parse(filepath)
232
+
233
+ needle = ' math'
234
+ xpath_base = f ' //*[@id=" { needle} "]/parent::* | //*[@id=" { needle} "]/descendant-or-self::* '
235
+ xmap = xml2xpath.parse(None , itree = hdoc, xpath_base = xpath_base)[2 ]
236
+
237
+ rel_xpath = []
238
+ xiter = iter (xmap)
239
+ # parent xpath
240
+ x0 = next (xiter)
241
+ # base element xpath
242
+ x1 = next (xiter)
243
+ # get base element attributes and build a predicate with first
244
+ x1a = ' '
245
+ if len (xmap[x1][2 ]) > 0 :
246
+ x1a = f ' [@ { xmap[x1][2 ][0 ]} =" { needle} "] '
247
+ # base element relative xpath (/html/body/math -> //math)
248
+ x1f = x1.replace(x0, ' /' )
249
+ # remove numeric indexes if any (div[1] -> div)
250
+ x1f = x1f.split(' [' , 1 )[0 ]
251
+ # add first attribute as predicate
252
+ x1f += x1a
253
+ rel_xpath.append(x1f)
254
+
255
+ # children relative xpath
256
+ for xs in list (xmap.keys())[2 :]:
257
+ rel_xpath.append(xs.replace(x1, x1f))
258
+
259
+ for x in rel_xpath:
260
+ print (x)
261
+ ```
262
+
263
+ Output
264
+
265
+ ``` None
266
+ //math[@id='math']
267
+ //math[@id='math']/mrow
268
+ //math[@id='math']/mrow/mi
269
+ //math[@id='math']/mrow/mo
270
+ //math[@id='math']/mrow/mfrac
271
+ //math[@id='math']/mrow/mfrac/mn
272
+ //math[@id='math']/mrow/mfrac/msqrt
273
+ //math[@id='math']/mrow/mfrac/msqrt/mrow
274
+ //math[@id='math']/mrow/mfrac/msqrt/mrow/msup
275
+ //math[@id='math']/mrow/mfrac/msqrt/mrow/msup/mi
276
+ //math[@id='math']/mrow/mfrac/msqrt/mrow/msup/mn
277
+ //math[@id='math']/mrow/mfrac/msqrt/mrow/mo
278
+ //math[@id='math']/mrow/mfrac/msqrt/mrow/mn
279
+ ```
280
+
218
281
## Unqualified vs. Qualified
219
282
Symbolic element tree of ` tests/resources/wiki.xml ` showing position of unqualified elements.
220
283
0 commit comments