a
    ):M]an  ã                   @   s¼   d Z ddlZddlZddlmZmZmZ ejd dk r@eZ	e
ZneZ	eZddd„ZG dd„ deeƒZG d	d
„ d
eƒZe d¡jZe d¡jZe d¡jZG dd„ deƒZG dd„ deƒZdS )a  
    cssselect.xpath
    ===============

    Translation of parsed CSS selectors to XPath expressions.


    :copyright: (c) 2007-2012 Ian Bicking and contributors.
                See AUTHORS for more details.
    :license: BSD, see LICENSE for more details.

é    N)ÚparseÚparse_seriesÚSelectorErroré   c                 C   s   |  dd¡ d¡}t| ||ƒS )NÚasciiÚreplace)ÚencodeÚdecodeÚgetattr)ÚobjÚnameÚdefault© r   ú.lib/python3.9/site-packages/cssselect/xpath.pyÚ_unicode_safe_getattr   s    r   c                   @   s   e Zd ZdZdS )ÚExpressionErrorz3Unknown or unsupported selector (eg. pseudo-class).N)Ú__name__Ú
__module__Ú__qualname__Ú__doc__r   r   r   r   r   #   s   r   c                   @   sF   e Zd Zddd„Zdd„ Zdd	„ Zd
d„ Zdd„ Zdd„ Zdd„ Z	dS )Ú	XPathExprÚ Ú*Fc                 C   s   || _ || _|| _d S ©N)ÚpathÚelementÚ	condition)Úselfr   r   r   Zstar_prefixr   r   r   Ú__init__+   s    zXPathExpr.__init__c                 C   s,   t | jƒt | jƒ }| jr(|d| j 7 }|S )Nz[%s]©Ú_unicoder   r   r   )r   r   r   r   r   Ú__str__0   s    zXPathExpr.__str__c                 C   s   d| j j| f S )Nz%s[%s])Ú	__class__r   ©r   r   r   r   Ú__repr__6   s    zXPathExpr.__repr__c                 C   s"   | j rd| j |f | _ n|| _ | S )Nz%s and (%s))r   )r   r   r   r   r   Úadd_condition9   s    zXPathExpr.add_conditionc                 C   s.   | j dkrd S |  dt | j ¡ ¡ d| _ d S )Nr   zname() = %s)r   r%   ÚGenericTranslatorÚxpath_literalr#   r   r   r   Úadd_name_test@   s    
ÿzXPathExpr.add_name_testc                 C   s   |  j d7  _ dS )ze
        Append '*/' to the path to keep the context constrained
        to a single parent.
        ú*/N)r   r#   r   r   r   Úadd_star_prefixH   s    zXPathExpr.add_star_prefixc                 C   s:   t | ƒ| }|jdkr ||j7 }|| _|j| _|j| _| S )Nr)   r   )r   ZcombinerÚotherr   r   r   r   ÚjoinO   s    

zXPathExpr.joinN)r   r   r   F)
r   r   r   r   r!   r$   r%   r(   r*   r,   r   r   r   r   r   )   s   
r   z('+)z^[a-zA-Z_][a-zA-Z0-9_.-]*$z^[^ \t\r\n\f]+$c                	   @   sÂ  e Zd ZdZdddddœZddd	d
dddddœZdZdZdZdZ	dZ
eZdhdd„Zdidd„Zdd„ Zedd„ ƒZdd„ Zdd„ Zd d!„ Zd"d#„ Zd$d%„ Zd&d'„ Zd(d)„ Zd*d+„ Zd,d-„ Zd.d/„ Zd0d1„ Zd2d3„ Zd4d5„ Zdjd7d8„Zd9d:„ Z d;d<„ Z!d=d>„ Z"d?d@„ Z#dAdB„ Z$dCdD„ Z%dEdF„ Z&dGdH„ Z'dIdJ„ Z(dKdL„ Z)dMdN„ Z*dOdP„ Z+dQdR„ Z,dSdT„ Z-dUdV„ Z.e.Z/e.Z0e.Z1e.Z2e.Z3e.Z4e.Z5e.Z6e.Z7dWdX„ Z8dYdZ„ Z9d[d\„ Z:d]d^„ Z;d_d`„ Z<dadb„ Z=dcdd„ Z>dedf„ Z?dgS )kr&   z¤
    Translator for "generic" XML documents.

    Everything is case-sensitive, no assumption is made on the meaning
    of element names and attribute names.

    Z
descendantÚchildZdirect_adjacentZindirect_adjacent)ú ú>ú+ú~ÚexistsZequalsZincludesZ	dashmatchZprefixmatchZsuffixmatchZsubstringmatchZ	different)r2   ú=z~=z|=z^=z$=z*=z!=Úidzxml:langFúdescendant-or-self::c                    s   d  ‡ ‡fdd„t|ƒD ƒ¡S )uµ  Translate a *group of selectors* to XPath.

        Pseudo-elements are not supported here since XPath only knows
        about "real" elements.

        :param css:
            A *group of selectors* as an Unicode string.
        :param prefix:
            This string is prepended to the XPath expression for each selector.
            The default makes selectors scoped to the context nodeâ€™s subtree.
        :raises:
            :class:`SelectorSyntaxError` on invalid selectors,
            :class:`ExpressionError` on unknown/unsupported selectors,
            including pseudo-elements.
        :returns:
            The equivalent XPath 1.0 expression as an Unicode string.

        z | c                 3   s   | ]}ˆj |ˆ d dV  qdS )T)Útranslate_pseudo_elementsN)Úselector_to_xpath)Ú.0Úselector©Úprefixr   r   r   Ú	<genexpr>¾   s   þÿz1GenericTranslator.css_to_xpath.<locals>.<genexpr>)r,   r   )r   Zcssr;   r   r:   r   Úcss_to_xpath«   s    þzGenericTranslator.css_to_xpathc                 C   s`   t |ddƒ}|std|f ƒ‚|  |¡}t|| jƒs8J ‚|rP|jrP|  ||j¡}|pVdt|ƒ S )u4  Translate a parsed selector to XPath.


        :param selector:
            A parsed :class:`Selector` object.
        :param prefix:
            This string is prepended to the resulting XPath expression.
            The default makes selectors scoped to the context nodeâ€™s subtree.
        :param translate_pseudo_elements:
            Unless this is set to ``True`` (as :meth:`css_to_xpath` does),
            the :attr:`~Selector.pseudo_element` attribute of the selector
            is ignored.
            It is the caller's responsibility to reject selectors
            with pseudo-elements, or to account for them somehow.
        :raises:
            :class:`ExpressionError` on unknown/unsupported selectors.
        :returns:
            The equivalent XPath 1.0 expression as an Unicode string.

        Zparsed_treeNz"Expected a parsed selector, got %rr   )r
   Ú	TypeErrorÚxpathÚ
isinstanceÚxpathexpr_clsÚpseudo_elementÚxpath_pseudo_elementr    )r   r9   r;   r6   Ztreer?   r   r   r   r7   Â   s    

z#GenericTranslator.selector_to_xpathc                 C   s   t dƒ‚dS )zTranslate a pseudo-element.

        Defaults to not supporting pseudo-elements at all,
        but can be overridden by sub-classes.

        z"Pseudo-elements are not supported.N)r   )r   r?   rB   r   r   r   rC   á   s    z&GenericTranslator.xpath_pseudo_elementc                 C   sL   t | ƒ} d| vrd|  } n.d| vr,d|  } ndd dd„ t| ƒD ƒ¡ } | S )	Nú'ú'%s'ú"ú"%s"z
concat(%s)ú,c                 S   s$   g | ]}|rd |v rdpd| ‘qS )rD   rG   rE   r   )r8   Úpartr   r   r   Ú
<listcomp>ò   s   ÿz3GenericTranslator.xpath_literal.<locals>.<listcomp>)r    r,   Úsplit_at_single_quotes)Úsr   r   r   r'   ê   s    

þ
zGenericTranslator.xpath_literalc                 C   s:   t |ƒj}t| d| ¡  dƒ}|du r2td| ƒ‚||ƒS )z%Translate any parsed selector object.zxpath_%sNz%s is not supported.)Útyper   r
   Úlowerr   )r   Zparsed_selectorÚ	type_nameÚmethodr   r   r   r?   ø   s
    
zGenericTranslator.xpathc                 C   s4   | j |j }t| d| ƒ}||  |j¡|  |j¡ƒS )zTranslate a combined selector.zxpath_%s_combinator)Úcombinator_mappingÚ
combinatorr
   r?   r9   Úsubselector)r   ZcombinedrR   rP   r   r   r   Úxpath_combinedselector  s
    
ÿz(GenericTranslator.xpath_combinedselectorc                 C   sD   |   |j¡}|   |j¡}| ¡  |jr6| d|j ¡S | d¡S d S )Nznot(%s)Ú0)r?   r9   rS   r(   r   r%   )r   Znegationr?   Z	sub_xpathr   r   r   Úxpath_negation
  s    z GenericTranslator.xpath_negationc                 C   sB   d|j  dd¡ }t| |dƒ}|s0td|j  ƒ‚||  |j¡|ƒS )z$Translate a functional pseudo-class.zxpath_%s_functionú-Ú_Nz!The pseudo-class :%s() is unknown)r   r   r   r   r?   r9   )r   ÚfunctionrP   r   r   r   Úxpath_function  s    ÿz GenericTranslator.xpath_functionc                 C   s@   d|j  dd¡ }t| |dƒ}|s0td|j  ƒ‚||  |j¡ƒS )zTranslate a pseudo-class.zxpath_%s_pseudorW   rX   NzThe pseudo-class :%s is unknown)Úidentr   r   r   r?   r9   )r   ZpseudorP   r   r   r   Úxpath_pseudo  s    ÿzGenericTranslator.xpath_pseudoc                 C   s¸   | j |j }t| d| ƒ}| jr,|j ¡ }n|j}t|ƒ}|jr\d|j|f }|oZt|jƒ}|rjd| }nd|  |¡ }|j	du rˆd}n| j
rœ|j	j	 ¡ }n|j	j	}||  |j¡||ƒS )z Translate an attribute selector.zxpath_attrib_%sú%s:%sú@zattribute::*[name() = %s]N)Úattribute_operator_mappingÚoperatorr
   Úlower_case_attribute_namesÚattribrN   Úis_safe_nameÚ	namespacer'   ÚvalueÚlower_case_attribute_valuesr?   r9   )r   r9   r`   rP   r   Úsaferb   re   r   r   r   Úxpath_attrib'  s$    

zGenericTranslator.xpath_attribc                 C   s   |   |j¡}|  |d|j¡S )zTranslate a class selector.z@class)r?   r9   Úxpath_attrib_includesÚ
class_name)r   Zclass_selectorr?   r   r   r   Úxpath_class?  s    ÿzGenericTranslator.xpath_classc                 C   s   |   |j¡}|  |d|j¡S )zTranslate an ID selector.z@id)r?   r9   Úxpath_attrib_equalsr4   )r   Zid_selectorr?   r   r   r   Ú
xpath_hashF  s    zGenericTranslator.xpath_hashc                 C   sh   |j }|sd}d}nt|ƒ}| jr*| ¡ }|jrLd|j|f }|oJt|jƒ}| j|d}|sd| ¡  |S )z'Translate a type or universal selector.r   Tr]   )r   )r   rc   Úlower_case_element_namesrN   rd   rA   r(   )r   r9   r   rg   r?   r   r   r   Úxpath_elementK  s    zGenericTranslator.xpath_elementc                 C   s   |  d|¡S )z;right is a child, grand-child or further descendant of leftz/descendant-or-self::*/©r,   ©r   ÚleftÚrightr   r   r   Úxpath_descendant_combinatorb  s    z-GenericTranslator.xpath_descendant_combinatorc                 C   s   |  d|¡S )z#right is an immediate child of leftú/rp   rq   r   r   r   Úxpath_child_combinatorf  s    z(GenericTranslator.xpath_child_combinatorc                 C   s   |  d|¡}| ¡  | d¡S )z)right is a sibling immediately after leftú/following-sibling::zposition() = 1)r,   r(   r%   )r   rr   rs   r?   r   r   r   Ú xpath_direct_adjacent_combinatorj  s    z2GenericTranslator.xpath_direct_adjacent_combinatorc                 C   s   |  d|¡S )z1right is a sibling after left, immediately or notrw   rp   rq   r   r   r   Ú"xpath_indirect_adjacent_combinatorp  s    z4GenericTranslator.xpath_indirect_adjacent_combinatorTc                 C   sL  zt |jƒ\}}W n  ty2   td|j ƒ‚Y n0 |d }|dkrP|dkrP|S |dk rj|dk rj| d¡S |rtd}n
d|j }|sŒd| }	nd| }	|dkr®| d	|	|f ¡S g }
|dkrÖ|dkrè|
 d
|	|f ¡ n|
 d|	|f ¡ t|ƒdkr8|	}| t|ƒ }|dkr&d| }d||f }|
 d||f ¡ | d |
¡¡ |S )NzInvalid series: '%r'é   r   rU   r   z%szcount(preceding-sibling::%s)zcount(following-sibling::%s)ú%s = %sz%s >= %sz%s <= %sz+%sz(%s %s)z%s mod %s = 0z and )	r   Ú	argumentsÚ
ValueErrorr   r%   r   ÚappendÚabsr,   )r   r?   rY   Úlastr(   ÚaÚbZb_min_1ZnodetestZsiblings_countÚexprrr   Zb_negr   r   r   Úxpath_nth_child_functionw  s>    +



z*GenericTranslator.xpath_nth_child_functionc                 C   s   | j ||ddS )NT)r€   )r„   ©r   r?   rY   r   r   r   Úxpath_nth_last_child_function÷  s    z/GenericTranslator.xpath_nth_last_child_functionc                 C   s"   |j dkrtdƒ‚| j||ddS )Nr   ú"*:nth-of-type() is not implementedF)r(   ©r   r   r„   r…   r   r   r   Úxpath_nth_of_type_functionú  s    
ÿÿz,GenericTranslator.xpath_nth_of_type_functionc                 C   s$   |j dkrtdƒ‚| j||dddS )Nr   r‡   TF)r€   r(   rˆ   r…   r   r   r   Úxpath_nth_last_of_type_function  s    
ÿ
ÿz1GenericTranslator.xpath_nth_last_of_type_functionc                 C   sB   |  ¡ dgdgfvr"td|j ƒ‚|jd j}| d|  |¡ ¡S )NÚSTRINGÚIDENTz9Expected a single string or ident for :contains(), got %rr   zcontains(., %s)©Úargument_typesr   r|   re   r%   r'   ©r   r?   rY   re   r   r   r   Úxpath_contains_function  s    ÿÿÿz)GenericTranslator.xpath_contains_functionc                 C   sB   |  ¡ dgdgfvr"td|j ƒ‚|jd j}| d|  |¡ ¡S )Nr‹   rŒ   ú5Expected a single string or ident for :lang(), got %rr   zlang(%s)r   r   r   r   r   Úxpath_lang_function  s    ÿÿÿz%GenericTranslator.xpath_lang_functionc                 C   s
   |  d¡S )Nznot(parent::*)©r%   ©r   r?   r   r   r   Úxpath_root_pseudo  s    z#GenericTranslator.xpath_root_pseudoc                 C   s
   |  d¡S )NÚ1r“   r”   r   r   r   Úxpath_scope_pseudo'  s    z$GenericTranslator.xpath_scope_pseudoc                 C   s
   |  d¡S )Nzcount(preceding-sibling::*) = 0r“   r”   r   r   r   Úxpath_first_child_pseudo*  s    z*GenericTranslator.xpath_first_child_pseudoc                 C   s
   |  d¡S )Nzcount(following-sibling::*) = 0r“   r”   r   r   r   Úxpath_last_child_pseudo-  s    z)GenericTranslator.xpath_last_child_pseudoc                 C   s"   |j dkrtdƒ‚| d|j  ¡S )Nr   z"*:first-of-type is not implementedz count(preceding-sibling::%s) = 0©r   r   r%   r”   r   r   r   Úxpath_first_of_type_pseudo0  s
    
ÿz,GenericTranslator.xpath_first_of_type_pseudoc                 C   s"   |j dkrtdƒ‚| d|j  ¡S )Nr   z!*:last-of-type is not implementedz count(following-sibling::%s) = 0rš   r”   r   r   r   Úxpath_last_of_type_pseudo6  s
    
ÿz+GenericTranslator.xpath_last_of_type_pseudoc                 C   s
   |  d¡S )Nzcount(parent::*/child::*) = 1r“   r”   r   r   r   Úxpath_only_child_pseudo<  s    z)GenericTranslator.xpath_only_child_pseudoc                 C   s"   |j dkrtdƒ‚| d|j  ¡S )Nr   z!*:only-of-type is not implementedzcount(parent::*/child::%s) = 1rš   r”   r   r   r   Úxpath_only_of_type_pseudo?  s
    
ÿz+GenericTranslator.xpath_only_of_type_pseudoc                 C   s
   |  d¡S )Nznot(*) and not(string-length())r“   r”   r   r   r   Úxpath_empty_pseudoE  s    z$GenericTranslator.xpath_empty_pseudoc                 C   s
   |  d¡S )z:Common implementation for pseudo-classes that never match.rU   r“   r”   r   r   r   Úpseudo_never_matchesH  s    z&GenericTranslator.pseudo_never_matchesc                 C   s   |rJ ‚|  |¡ |S r   r“   ©r   r?   r   re   r   r   r   Úxpath_attrib_existsX  s    
z%GenericTranslator.xpath_attrib_existsc                 C   s   |  d||  |¡f ¡ |S )Nr{   ©r%   r'   r¡   r   r   r   rl   ]  s    z%GenericTranslator.xpath_attrib_equalsc                 C   s<   |r |  d|||  |¡f ¡ n|  d||  |¡f ¡ |S )Nznot(%s) or %s != %sz%s != %sr£   r¡   r   r   r   Úxpath_attrib_differenta  s    ÿÿz(GenericTranslator.xpath_attrib_differentc              	   C   s:   t |ƒr,| d|||  d| d ¡f ¡ n
| d¡ |S )Nz:%s and contains(concat(' ', normalize-space(%s), ' '), %s)r.   rU   )Úis_non_whitespacer%   r'   r¡   r   r   r   ri   k  s    ÿÿ
z'GenericTranslator.xpath_attrib_includesc                 C   s,   |  d|||  |¡||  |d ¡f ¡ |S )Nz'%s and (%s = %s or starts-with(%s, %s))rW   r£   r¡   r   r   r   Úxpath_attrib_dashmatcht  s    
ýz(GenericTranslator.xpath_attrib_dashmatchc                 C   s.   |r |  d|||  |¡f ¡ n
|  d¡ |S )Nz%s and starts-with(%s, %s)rU   r£   r¡   r   r   r   Úxpath_attrib_prefixmatch|  s    ÿ

z*GenericTranslator.xpath_attrib_prefixmatchc              
   C   s:   |r,|  d|||t|ƒd |  |¡f ¡ n
|  d¡ |S )Nz/%s and substring(%s, string-length(%s)-%s) = %srz   rU   )r%   Úlenr'   r¡   r   r   r   Úxpath_attrib_suffixmatch„  s    ÿÿ
z*GenericTranslator.xpath_attrib_suffixmatchc                 C   s.   |r |  d|||  |¡f ¡ n
|  d¡ |S )Nz%s and contains(%s, %s)rU   r£   r¡   r   r   r   Úxpath_attrib_substringmatchŽ  s    ÿ

z-GenericTranslator.xpath_attrib_substringmatchN)r5   )r5   F)FT)@r   r   r   r   rQ   r_   Zid_attributeÚlang_attributern   ra   rf   r   rA   r=   r7   rC   Ústaticmethodr'   r?   rT   rV   rZ   r\   rh   rk   rm   ro   rt   rv   rx   ry   r„   r†   r‰   rŠ   r   r’   r•   r—   r˜   r™   r›   rœ   r   rž   rŸ   r    Úxpath_link_pseudoZxpath_visited_pseudoZxpath_hover_pseudoZxpath_active_pseudoZxpath_focus_pseudoZxpath_target_pseudoÚxpath_enabled_pseudoÚxpath_disabled_pseudoÚxpath_checked_pseudor¢   rl   r¤   ri   r¦   r§   r©   rª   r   r   r   r   r&   g   sš   üø
  ÿ
	
		  ÿ
 
	
r&   c                   @   sF   e Zd ZdZdZddd„Zdd„ Zdd	„ Zd
d„ Zdd„ Z	dd„ Z
dS )ÚHTMLTranslatoraê  
    Translator for (X)HTML documents.

    Has a more useful implementation of some pseudo-classes based on
    HTML-specific element names and attribute names, as described in
    the `HTML5 specification`_. It assumes no-quirks mode.
    The API is the same as :class:`GenericTranslator`.

    .. _HTML5 specification: http://www.w3.org/TR/html5/links.html#selectors

    :param xhtml:
        If false (the default), element names and attribute names
        are case-insensitive.

    ÚlangFc                 C   s   || _ |sd| _d| _d S )NT)Úxhtmlrn   ra   )r   r³   r   r   r   r   «  s    zHTMLTranslator.__init__c                 C   s
   |  d¡S )NzŠ(@selected and name(.) = 'option') or (@checked and (name(.) = 'input' or name(.) = 'command')and (@type = 'checkbox' or @type = 'radio'))r“   r”   r   r   r   r°   ²  s    ÿz#HTMLTranslator.xpath_checked_pseudoc                 C   sP   |  ¡ dgdgfvr"td|j ƒ‚|jd j}| d| j|  | ¡ d ¡f ¡S )Nr‹   rŒ   r‘   r   z‡ancestor-or-self::*[@lang][1][starts-with(concat(translate(@%s, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'), '-'), %s)]rW   )rŽ   r   r|   re   r%   r«   r'   rN   r   r   r   r   r’   º  s    ÿÿûÿz"HTMLTranslator.xpath_lang_functionc                 C   s
   |  d¡S )NzA@href and (name(.) = 'a' or name(.) = 'link' or name(.) = 'area')r“   r”   r   r   r   r­   È  s    z HTMLTranslator.xpath_link_pseudoc                 C   s
   |  d¡S )Na¥  
        (
            @disabled and
            (
                (name(.) = 'input' and @type != 'hidden') or
                name(.) = 'button' or
                name(.) = 'select' or
                name(.) = 'textarea' or
                name(.) = 'command' or
                name(.) = 'fieldset' or
                name(.) = 'optgroup' or
                name(.) = 'option'
            )
        ) or (
            (
                (name(.) = 'input' and @type != 'hidden') or
                name(.) = 'button' or
                name(.) = 'select' or
                name(.) = 'textarea'
            )
            and ancestor::fieldset[@disabled]
        )
        r“   r”   r   r   r   r¯   Ï  s    z$HTMLTranslator.xpath_disabled_pseudoc                 C   s
   |  d¡S )Na'  
        (
            @href and (
                name(.) = 'a' or
                name(.) = 'link' or
                name(.) = 'area'
            )
        ) or (
            (
                name(.) = 'command' or
                name(.) = 'fieldset' or
                name(.) = 'optgroup'
            )
            and not(@disabled)
        ) or (
            (
                (name(.) = 'input' and @type != 'hidden') or
                name(.) = 'button' or
                name(.) = 'select' or
                name(.) = 'textarea' or
                name(.) = 'keygen'
            )
            and not (@disabled or ancestor::fieldset[@disabled])
        ) or (
            name(.) = 'option' and not(
                @disabled or ancestor::optgroup[@disabled]
            )
        )
        r“   r”   r   r   r   r®   ë  s    z#HTMLTranslator.xpath_enabled_pseudoN)F)r   r   r   r   r«   r   r°   r’   r­   r¯   r®   r   r   r   r   r±   ˜  s   
r±   )N)r   ÚsysÚreZcssselect.parserr   r   r   Úversion_infoZ
basestringZ_basestringZunicoder    Ústrr   ÚRuntimeErrorr   Úobjectr   ÚcompileÚsplitrK   Úmatchrc   r¥   r&   r±   r   r   r   r   Ú<module>   s(   
1    5