Skip to content

Commit

Permalink
add suppport for [of S]? part in nth-child's arguments
Browse files Browse the repository at this point in the history
  • Loading branch information
annbgn committed Jul 13, 2021
1 parent ffb931c commit 5ac2aa8
Show file tree
Hide file tree
Showing 3 changed files with 22 additions and 5 deletions.
12 changes: 9 additions & 3 deletions cssselect/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -614,12 +614,13 @@ def parse_series(tokens):
Parses the arguments for :nth-child() and friends.
:raises: A list of tokens
:returns: :``(a, b)``
:returns: :``(a, b, c?)``
"""
for token in tokens:
if token.type == 'STRING':
raise ValueError('String tokens not allowed in series.')

s = ''.join(token.value for token in tokens).strip()
if s == 'odd':
return 2, 1
Expand All @@ -630,7 +631,8 @@ def parse_series(tokens):
if 'n' not in s:
# Just b
return 0, int(s)
a, b = s.split('n', 1)
s, *subselector = s.split("of")
a, b = s.split("n", 1)
if not a:
a = 1
elif a == '-' or a == '+':
Expand All @@ -641,7 +643,11 @@ def parse_series(tokens):
b = 0
else:
b = int(b)
return a, b
if not subselector:
c = 0
else:
c = subselector[0]
return a, b, c


#### Token objects
Expand Down
6 changes: 4 additions & 2 deletions cssselect/xpath.py
Original file line number Diff line number Diff line change
Expand Up @@ -375,7 +375,7 @@ def xpath_indirect_adjacent_combinator(self, left, right):
def xpath_nth_child_function(self, xpath, function, last=False,
add_name_test=True):
try:
a, b = parse_series(function.arguments)
a, b, c = parse_series(function.arguments)
except ValueError:
raise ExpressionError("Invalid series: '%r'" % function.arguments)

Expand Down Expand Up @@ -439,7 +439,9 @@ def xpath_nth_child_function(self, xpath, function, last=False,
# `add_name_test` boolean is inverted and somewhat counter-intuitive:
#
# nth_of_type() calls nth_child(add_name_test=False)
if add_name_test:
if c:
nodetest = self.xpath(parse(c)[0].parsed_tree).element
elif add_name_test:
nodetest = '*'
else:
nodetest = '%s' % xpath.element
Expand Down
9 changes: 9 additions & 0 deletions tests/test_cssselect.py
Original file line number Diff line number Diff line change
Expand Up @@ -406,6 +406,15 @@ def xpath(css):
"@hreflang = 'en' or starts-with(@hreflang, 'en-'))]")

# --- nth-* and nth-last-* -------------------------------------
assert (
xpath("e:nth-child(2n+1 of S)")
== "e[count(preceding-sibling::S) mod 2 = 0]"
)
assert (
xpath("e:nth-of-type(2n+1 of S)")
== "e[count(preceding-sibling::S) mod 2 = 0]"
)
# assert xpath('e:nth-child(2n+1 of li.important)') == "e[count(preceding-sibling::e[@class and contains(concat(' ', normalize-space(@class), ' '), ' important ')]) mod 2 = 0"
assert xpath('e:nth-child(1)') == (
"e[count(preceding-sibling::*) = 0]")

Expand Down

0 comments on commit 5ac2aa8

Please sign in to comment.