3
(ha                 @   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jdjZejdjZej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   |j ddjd}t| ||S )Nasciireplace)encodedecodegetattr)objnamedefault r   6/tmp/pip-install-q3hcpn_q/cssselect/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 | jdtj| j   d| _ d S )Nr   zname() = %s)r   r"   GenericTranslatorxpath_literal)r   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.
        z*/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 )Nz*/)r   r   r   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dfddZdgd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dhd7d8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-e-Z.e-Z/e-Z0e-Z1e-Z2e-Z3e-Z4e-Z5e-Z6dUdV Z7dWdX Z8dYdZ Z9d[d\ Z:d]d^ Z;d_d` Z<dadb Z=dcdd Z>deS )ir#   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) >+~existsequalsZincludesZ	dashmatchZprefixmatchZsuffixmatchZsubstringmatchZ	different)r.   =z~=z|=z^=z$=z*=z!=idzxml:langFdescendant-or-self::c                s   dj  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   cssr7   r   )r7   r   r   css_to_xpath   s    zGenericTranslator.css_to_xpathc             C   s`   t |dd}|std|f | j|}t|| js8t|rP|jrP| j||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AssertionErrorpseudo_elementxpath_pseudo_elementr   )r   r6   r7   r3   treer<   r   r   r   r4      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<   r@   r   r   r   rA      s    z&GenericTranslator.xpath_pseudo_elementc             C   sL   t | } d| krd|  } n.d| kr,d|  } nddjdd t| D  } | S )	N'z'%s'"z"%s"z
concat(%s),c             S   s$   g | ]}|rd |krdpd| qS )rC   z"%s"z'%s'r   )r5   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|j  d}|dk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| j|jS )zTranslate a combined selector.zxpath_%s_combinator)combinator_mapping
combinatorr
   r<   r6   subselector)r   ZcombinedrO   rM   r   r   r   xpath_combinedselector  s    z(GenericTranslator.xpath_combinedselectorc             C   sD   | j |j}| j |j}|j  |jr6|jd|j S |jdS d S )Nznot(%s)0)r<   r6   rP   r%   r   r"   )r   Znegationr<   Z	sub_xpathr   r   r   xpath_negation
  s    z GenericTranslator.xpath_negationc             C   sB   d|j jdd }t| |d}|s0td|j  || 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<   r6   )r   functionrM   r   r   r   xpath_function  s    z GenericTranslator.xpath_functionc             C   s@   d|j jdd }t| |d}|s0td|j  || j|jS )zTranslate a pseudo-class.zxpath_%s_pseudorT   rU   NzThe pseudo-class :%s is unknown)identr   r   r   r<   r6   )r   ZpseudorM   r   r   r   xpath_pseudo  s    zGenericTranslator.xpath_pseudoc             C   s   | j |j }t| d| }| jr,|jj }n|j}t|}|jr\d|j|f }|oZt|j}|rjd| }nd| j| }| j	r|j
j }n|j
}|| j|j||S )z Translate an attribute selector.zxpath_attrib_%sz%s:%s@zattribute::*[name() = %s])attribute_operator_mappingoperatorr
   lower_case_attribute_namesattribrK   is_safe_name	namespacer$   lower_case_attribute_valuesvaluer<   r6   )r   r6   r\   rM   r   safer^   rb   r   r   r   xpath_attrib'  s     
zGenericTranslator.xpath_attribc             C   s   | j |j}| j|d|jS )zTranslate a class selector.z@class)r<   r6   xpath_attrib_includes
class_name)r   Zclass_selectorr<   r   r   r   xpath_class=  s    zGenericTranslator.xpath_classc             C   s   | j |j}| j|d|jS )zTranslate an ID selector.z@id)r<   r6   xpath_attrib_equalsr1   )r   Zid_selectorr<   r   r   r   
xpath_hashD  s    zGenericTranslator.xpath_hashc             C   sh   |j }|sd}d}nt|}| jr*|j }|jrLd|j|f }|oJt|j}| j|d}|sd|j  |S )z'Translate a type or universal selector.r   Tz%s:%s)r   )r   r_   lower_case_element_namesrK   r`   r>   r%   )r   r6   r   rc   r<   r   r   r   xpath_elementI  s    zGenericTranslator.xpath_elementc             C   s   |j 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_combinator`  s    z-GenericTranslator.xpath_descendant_combinatorc             C   s   |j d|S )z#right is an immediate child of left/)r(   )r   rl   rm   r   r   r   xpath_child_combinatord  s    z(GenericTranslator.xpath_child_combinatorc             C   s   |j d|}|j  |jdS )z)right is a sibling immediately after leftz/following-sibling::zposition() = 1)r(   r%   r"   )r   rl   rm   r<   r   r   r    xpath_direct_adjacent_combinatorh  s    z2GenericTranslator.xpath_direct_adjacent_combinatorc             C   s   |j d|S )z1right is a sibling after left, immediately or notz/following-sibling::)r(   )r   rl   rm   r   r   r   "xpath_indirect_adjacent_combinatorn  s    z4GenericTranslator.xpath_indirect_adjacent_combinatorTc       	      C   s  yt |j\}}W n" tk
r4   td|j Y nX |rB|j  |j  |dkrl|r^d| }|jd| S |r|| }| }|dkrt| }n
d|  }|dkrd||f g}ng }|dkr|jd|  n|dk r|r|jd	|  d
j	|}|r|j| |S )NzInvalid series: '%r'r   zlast() - %szposition() = %sz+%s   z(position() %s) mod %s = 0zposition() >= %szposition() < (last() %s)z and )
r   	arguments
ValueErrorr   r%   r&   r"   strappendr(   )	r   r<   rV   lastr%   abZb_negexprr   r   r   xpath_nth_child_functionu  s8    


z*GenericTranslator.xpath_nth_child_functionc             C   s   | j ||ddS )NT)rx   )r|   )r   r<   rV   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   z"*:nth-of-type() is not implementedF)r%   )r   r   r|   )r   r<   rV   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   z"*:nth-of-type() is not implementedTF)rx   r%   )r   r   r|   )r   r<   rV   r   r   r   xpath_nth_last_of_type_function  s
    

z1GenericTranslator.xpath_nth_last_of_type_functionc             C   sB   |j  dgdgfkr"td|j |jd j}|jd| j| S )NSTRINGIDENTz9Expected a single string or ident for :contains(), got %rr   zcontains(., %s))argument_typesr   rt   rb   r"   r$   )r   r<   rV   rb   r   r   r   xpath_contains_function  s    
z)GenericTranslator.xpath_contains_functionc             C   sB   |j  dgdgfkr"td|j |jd j}|jd| j| S )Nr   r   z5Expected a single string or ident for :lang(), got %rr   zlang(%s))r   r   rt   rb   r"   r$   )r   r<   rV   rb   r   r   r   xpath_lang_function  s    
z%GenericTranslator.xpath_lang_functionc             C   s
   |j dS )Nznot(parent::*))r"   )r   r<   r   r   r   xpath_root_pseudo  s    z#GenericTranslator.xpath_root_pseudoc             C   s   |j   |j  |jdS )Nzposition() = 1)r&   r%   r"   )r   r<   r   r   r   xpath_first_child_pseudo  s    z*GenericTranslator.xpath_first_child_pseudoc             C   s   |j   |j  |jdS )Nzposition() = last())r&   r%   r"   )r   r<   r   r   r   xpath_last_child_pseudo  s    z)GenericTranslator.xpath_last_child_pseudoc             C   s$   |j dkrtd|j  |jdS )Nr   z"*:first-of-type is not implementedzposition() = 1)r   r   r&   r"   )r   r<   r   r   r   xpath_first_of_type_pseudo  s
    
z,GenericTranslator.xpath_first_of_type_pseudoc             C   s$   |j dkrtd|j  |jdS )Nr   z!*:last-of-type is not implementedzposition() = last())r   r   r&   r"   )r   r<   r   r   r   xpath_last_of_type_pseudo  s
    
z+GenericTranslator.xpath_last_of_type_pseudoc             C   s   |j   |j  |jdS )Nz
last() = 1)r%   r&   r"   )r   r<   r   r   r   xpath_only_child_pseudo  s    z)GenericTranslator.xpath_only_child_pseudoc             C   s   |j dkrtd|jdS )Nr   z!*:only-of-type is not implementedz
last() = 1)r   r   r"   )r   r<   r   r   r   xpath_only_of_type_pseudo  s    
z+GenericTranslator.xpath_only_of_type_pseudoc             C   s
   |j dS )Nznot(*) and not(string-length()))r"   )r   r<   r   r   r   xpath_empty_pseudo  s    z$GenericTranslator.xpath_empty_pseudoc             C   s
   |j dS )z:Common implementation for pseudo-classes that never match.rR   )r"   )r   r<   r   r   r   pseudo_never_matches  s    z&GenericTranslator.pseudo_never_matchesc             C   s   | s
t |j| |S )N)r?   r"   )r   r<   r   rb   r   r   r   xpath_attrib_exists  s    

z%GenericTranslator.xpath_attrib_existsc             C   s   |j d|| j|f  |S )Nz%s = %s)r"   r$   )r   r<   r   rb   r   r   r   rh     s    z%GenericTranslator.xpath_attrib_equalsc             C   s<   |r |j d||| j|f  n|j d|| j|f  |S )Nznot(%s) or %s != %sz%s != %s)r"   r$   )r   r<   r   rb   r   r   r   xpath_attrib_different  s    z(GenericTranslator.xpath_attrib_differentc             C   s:   t |r,|jd||| jd| d f  n
|jd |S )Nz:%s and contains(concat(' ', normalize-space(%s), ' '), %s)r*   rR   )is_non_whitespacer"   r$   )r   r<   r   rb   r   r   r   re     s    
z'GenericTranslator.xpath_attrib_includesc          	   C   s,   |j d||| j||| j|d f  |S )Nz'%s and (%s = %s or starts-with(%s, %s))rT   )r"   r$   )r   r<   r   rb   r   r   r   xpath_attrib_dashmatch  s
    
z(GenericTranslator.xpath_attrib_dashmatchc             C   s.   |r |j d||| j|f  n
|j d |S )Nz%s and starts-with(%s, %s)rR   )r"   r$   )r   r<   r   rb   r   r   r   xpath_attrib_prefixmatch#  s
    
z*GenericTranslator.xpath_attrib_prefixmatchc             C   s:   |r,|j d|||t|d | j|f  n
|j d |S )Nz/%s and substring(%s, string-length(%s)-%s) = %srs   rR   )r"   lenr$   )r   r<   r   rb   r   r   r   xpath_attrib_suffixmatch+  s    "
z*GenericTranslator.xpath_attrib_suffixmatchc             C   s.   |r |j d||| j|f  n
|j d |S )Nz%s and contains(%s, %s)rR   )r"   r$   )r   r<   r   rb   r   r   r   xpath_attrib_substringmatch5  s
    
z-GenericTranslator.xpath_attrib_substringmatchN)r2   )r2   F)FT)?r   r   r   r   rN   r[   Zid_attributelang_attributerj   r]   ra   r   r>   r:   r4   rA   staticmethodr$   r<   rQ   rS   rW   rY   rd   rg   ri   rk   rn   rp   rq   rr   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   rh   r   re   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)xhtmlrj   r]   )r   r   r   r   r   r   R  s    zHTMLTranslator.__init__c             C   s
   |j 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   r   Y  s    z#HTMLTranslator.xpath_checked_pseudoc             C   sP   |j  dgdgfkr"td|j |jd j}|jd| j| j|j d f S )Nr   r   z5Expected a single string or ident for :lang(), got %rr   zancestor-or-self::*[@lang][1][starts-with(concat(translate(@%s, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'), '-'), %s)]rT   )r   r   rt   rb   r"   r   r$   rK   )r   r<   rV   rb   r   r   r   r   a  s    
z"HTMLTranslator.xpath_lang_functionc             C   s
   |j dS )NzA@href and (name(.) = 'a' or name(.) = 'link' or name(.) = 'area'))r"   )r   r<   r   r   r   r   o  s    z HTMLTranslator.xpath_link_pseudoc             C   s
   |j 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   r   v  s    z$HTMLTranslator.xpath_disabled_pseudoc             C   s
   |j 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   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_info
basestringZ_basestringunicoder   rv   r   RuntimeErrorr   objectr   compilesplitrH   matchr_   r   r#   r   r   r   r   r   <module>   s&   
1   [