Is there a more concise way to implement css' An + B micro-syntax as xpath predicates?

I am creating a CSS selector for the xpath 1 converter, and one detail I have tried hard with is finding a short An+Bsyntax substitute .

Since I implement it for xpath 1 and so that it is as general as possible, there are a few limitations that my generated predicates should adhere to:

  • I (I suppose that I) cannot use position(), as it depends on possibly predicates predicates.

  • All *-of-typepseudo-class equivalents will be generated by external functions in the host language, because I believe that there is no way to construct predicates based on the name of the previous context - node in xpath 1.

    For example, hard coding li:first-of-typelike

    //li[count(preceding-sibling::li) = 0]
    

    in order. But dynamic coding *:first-of-typeis kind of like

    //*[count(preceding-sibling::*[name()=name(.)]) = 0]
    <!-- this is probably silly anyway -->
    

    not possible in xpath 1, I believe.

So, here is the template predicate that I came up with nth-of-type(An+B)so that the host language fills in the missing values:

<!-- 
  $A  represents the step (A) I will insert
  $Am represents "mod $A" I will insert if $A != 0
  $B  represents the offset (B) I will insert
  $E  represents the element name I will insert
  $O  represents the operator I will insert: <= if $A is negative, else >=
-->
[count(preceding-sibling::$E) + 1 - $B $O 0 and
 (count(preceding-sibling::$E) + 1 - $B) $Am = 0]

li:nth-of-type(2n+3) will be this way:

<!-- 
  $A  (step) = 2
  $Am (mod step) = mod $A = mod 2
  $B  (offset) = 3
  $E  (element name) = li
  $O  (comparison operator) = >=
-->
[count(preceding-sibling::li) + 1 - 3 >= 0 and
 (count(preceding-sibling::li) + 1 - 3) mod 2 = 0]

li:nth-of-type(-2n+3) will be this way:

<!-- 
  $A  (step) = -2
  $Am (mod step) = mod $A = mod -2
  $B  (offset) = 3
  $E  (element name) = li
  $O  (comparison operator) = <=
-->
[count(preceding-sibling::li) + 1 - 3 <= 0 and
 (count(preceding-sibling::li) + 1 - 3) mod -2 = 0]

li:nth-of-type(3) will be this way:

<!-- 
  $A  (step) = 0
  $Am (mod step) = absent
  $B  (offset) = 3
  $E  (element name) = li
  $O  (comparison operator) = >=

  first line seems redundant now
-->
[count(preceding-sibling::li) + 1 - 3 >= 0 and
 (count(preceding-sibling::li) + 1 - 3) = 0]

... etc..

As you can see, all this is a little cumbersome. I would prefer to create a nice compact single-line predicate without seemingly redundant bits and with the least need for variable substitutions (in particular, the comparison operator and the calculation of a step-by-step mode).

Is there a more concise way to enable the functionality An+B(step and offset) that I showed above?

+6

All Articles