B
    îq\è(  ã               @   sh   d Z ddlZddlZyddlmZ W n$ ek
rH   dd„ Zdd„ ZY nX ejZej	ZG d	d
„ d
ƒZ
dS )zZ
Contains a class that makes it simple to stream out well-formed and
nicely-indented XML.
é    Né   )Ú_iterparserc             C   s(   |   dd¡} |   dd¡} |   dd¡} | S )z<
        Escapes &, < and > in an XML CDATA string.
        ú&z&amp;ú<z&lt;ú>z&gt;)Úreplace)Ús© r	   ú7lib/python3.7/site-packages/astropy/utils/xml/writer.pyÚxml_escape_cdata   s    r   c             C   s@   |   dd¡} |   dd¡} |   dd¡} |   dd¡} |   d	d
¡} | S )zE
        Escapes &, ', ", < and > in an XML attribute value.
        r   z&amp;ú'z&apos;ú"z&quot;r   z&lt;r   z&gt;)r   )r   r	   r	   r
   Ú
xml_escape   s    r   c               @   s¨   e Zd ZdZdd„ Zd#dd„Zi fdd	„Zejd$dd„ƒZ	eji fdd„ƒZ
dd„ Zdd„ Zd%dd„Zdd„ Zddi fdd„Zdd„ Zdd„ Zd&dd „Zed!d"„ ƒZdS )'Ú	XMLWriteraN  
    A class to write well-formed and nicely indented XML.

    Use like this::

        w = XMLWriter(fh)
        with w.tag('html'):
            with w.tag('body'):
                w.data('This is the content')

    Which produces::

        <html>
         <body>
          This is the content
         </body>
        </html>
    c             C   sB   |j | _ t|dƒr|j| _d| _g | _g | _d| _t| _t| _dS )zY
        Parameters
        ----------
        file : writable file-like object.
        Úflushr   z@                                                                N)	ÚwriteÚhasattrr   Ú_openÚ_tagsÚ_dataÚ_indentationr   r   )ÚselfÚfiler	   r	   r
   Ú__init__:   s    
zXMLWriter.__init__TFc             C   s¤   | j r&|r|  d¡ n
|  d¡ d| _ | jr d | j¡}|rŠ|  d¡}tj|||d}|  d¡ |  |  |¡¡ |  d¡ |  |  ¡ ¡ n|  |  |¡¡ g | _dS )	z)
        Flush internal buffers.
        z>
r   r   Ú r   )Zinitial_indentZsubsequent_indentÚ
N)r   r   r   ÚjoinÚget_indentation_spacesÚtextwrapZfillr   )r   ÚindentÚwrapÚdatar	   r	   r
   Ú_flushK   s&    



zXMLWriter._flushc             K   s®   |   ¡  g | _| j |¡ |  |  d¡¡ |  d |¡¡ |sB|rž| ¡ }| |¡ t	| 
¡ ƒ}| ¡  x4|D ],\}}|dk	rn|  |¡}|  d ||¡¡ qnW d| _t| jƒS )am  
        Opens a new element.  Attributes can be given as keyword
        arguments, or as a string/string dictionary.  The method
        returns an opaque identifier that can be passed to the
        :meth:`close` method, to close all open elements up to and
        including this one.

        Parameters
        ----------
        tag : str
            The element name

        attrib : dict of str -> str
            Attribute dictionary.  Alternatively, attributes can
            be given as keyword arguments.

        Returns
        -------
        id : int
            Returns an element identifier.
        éÿÿÿÿz<{}Nz {}="{}"r   )r"   r   r   Úappendr   r   ÚformatÚcopyÚupdateÚlistÚitemsÚsortr   r   Úlen)r   ÚtagÚattribÚextraÚkÚvr	   r	   r
   Ústarte   s     

zXMLWriter.startÚ
escape_xmlc             +   sŠ   | j }|dkrVyddl‰ W n tk
r6   tdƒ‚Y nX ˆdkrDi ‰‡ ‡fdd„| _ n$|dkrjdd„ | _ n|d	krztd
ƒ‚dV  || _ dS )aY  Context manager to control how XML data tags are cleaned (escaped) to
        remove potentially unsafe characters or constructs.

        The default (``method='escape_xml'``) applies brute-force escaping of
        certain key XML characters like ``<``, ``>``, and ``&`` to ensure that
        the output is not valid XML.

        In order to explicitly allow certain XML tags (e.g. link reference or
        emphasis tags), use ``method='bleach_clean'``.  This sanitizes the data
        string using the ``clean`` function of the
        `http://bleach.readthedocs.io/en/latest/clean.html <bleach>`_ package.
        Any additional keyword arguments will be passed directly to the
        ``clean`` function.

        Finally, use ``method='none'`` to disable any sanitization. This should
        be used sparingly.

        Example::

          w = writer.XMLWriter(ListWriter(lines))
          with w.xml_cleaning_method('bleach_clean'):
              w.start('td')
              w.data('<a href="http://google.com">google.com</a>')
              w.end()

        Parameters
        ----------
        method : str
            Cleaning method.  Allowed values are "escape_xml",
            "bleach_clean", and "none".

        **clean_kwargs : keyword args
            Additional keyword args that are passed to the
            bleach.clean() function.
        Zbleach_cleanr   NzTbleach package is required when HTML escaping is disabled.
Use "pip install bleach".c                s   ˆ j | fˆŽS )N)Zclean)Úx)ÚbleachÚclean_kwargsr	   r
   Ú<lambda>Ã   s    z/XMLWriter.xml_cleaning_method.<locals>.<lambda>Znonec             S   s   | S )Nr	   )r3   r	   r	   r
   r6   Å   s    r2   zEallowed values of method are "escape_xml", "bleach_clean", and "none")r   r4   ÚImportErrorÚ
ValueError)r   Úmethodr5   Zcurrent_xml_escape_cdatar	   )r4   r5   r
   Úxml_cleaning_method‘   s    %zXMLWriter.xml_cleaning_methodc             k   s$   | j ||f|Ž dV  |  |¡ dS )aU  
        A convenience method for creating wrapper elements using the
        ``with`` statement.

        Examples
        --------

        >>> with writer.tag('foo'):  # doctest: +SKIP
        ...     writer.element('bar')
        ... # </foo> is implicitly closed here
        ...

        Parameters are the same as to `start`.
        N)r1   Úend)r   r,   r-   r.   r	   r	   r
   r,   Í   s    zXMLWriter.tagc             C   s0   |   ¡  |  |  ¡ ¡ |  d |  |¡¡¡ dS )z¢
        Adds a comment to the output stream.

        Parameters
        ----------
        comment : str
            Comment text, as a Unicode string.
        z<!-- {} -->
N)r"   r   r   r%   r   )r   Úcommentr	   r	   r
   r<   á   s    	zXMLWriter.commentc             C   s   | j  |¡ dS )z¦
        Adds character data to the output stream.

        Parameters
        ----------
        text : str
            Character data, as a Unicode string.
        N)r   r$   )r   Útextr	   r	   r
   r!   î   s    	zXMLWriter.dataNc             C   sª   |r>| j std |¡ƒ‚|| j d krLtd | j d |¡ƒ‚n| j sLtdƒ‚| j  ¡ }| jrj|  ||¡ n| jr„d| _|  d¡ dS |r–|  |  ¡ ¡ |  d |¡¡ dS )	a  
        Closes the current element (opened by the most recent call to
        `start`).

        Parameters
        ----------
        tag : str
            Element name.  If given, the tag must match the start tag.
            If omitted, the current element is closed.
        zunbalanced end({})r#   zexpected end({}), got {}zunbalanced end()r   z/>
Nz</{}>
)	r   r8   r%   Úpopr   r"   r   r   r   )r   r,   r   r    r	   r	   r
   r;   ù   s$    

zXMLWriter.endc             C   s    xt | jƒ|kr|  ¡  qW dS )zð
        Closes open elements, up to (and including) the element identified
        by the given identifier.

        Parameters
        ----------
        id : int
            Element identifier, as returned by the `start` method.
        N)r+   r   r;   )r   Úidr	   r	   r
   Úclose  s    
zXMLWriter.closec             K   s0   | j ||f|Ž |r|  |¡ | jd|d dS )z¤
        Adds an entire element.  This is the same as calling `start`,
        `data`, and `end` in sequence. The ``text`` argument
        can be omitted.
        F)r   r    N)r1   r!   r;   )r   r,   r=   r    r-   r.   r	   r	   r
   Úelement%  s    
zXMLWriter.elementc             C   s   d S )Nr	   )r   r	   r	   r
   r   0  s    zXMLWriter.flushc             C   s
   t | jƒS )z\
        Returns the number of indentation levels the file is currently
        in.
        )r+   r   )r   r	   r	   r
   Úget_indentation3  s    zXMLWriter.get_indentationr   c             C   s   | j dt| jƒ| … S )z`
        Returns a string of spaces that matches the current
        indentation level.
        N)r   r+   r   )r   Úoffsetr	   r	   r
   r   :  s    z XMLWriter.get_indentation_spacesc             C   s>   i }x4|D ],}t | |ƒdk	r
tt | |ƒƒ|| dd¡< q
W |S )a  
        Converts an object with a bunch of attributes on an object
        into a dictionary for use by the `XMLWriter`.

        Parameters
        ----------
        obj : object
            Any Python object

        attrs : sequence of str
            Attribute names to pull from the object

        Returns
        -------
        attrs : dict
            Maps attribute names to the values retrieved from
            ``obj.attr``.  If any of the attributes is `None`, it will
            not appear in the output dictionary.
        NÚ_ú-)ÚgetattrÚstrr   )ÚobjZattrsÚdÚattrr	   r	   r
   Úobject_attrsA  s
    
zXMLWriter.object_attrs)TF)r2   )NTF)r   )Ú__name__Ú
__module__Ú__qualname__Ú__doc__r   r"   r1   Ú
contextlibÚcontextmanagerr:   r,   r<   r!   r;   r@   rA   r   rB   r   ÚstaticmethodrK   r	   r	   r	   r
   r   &   s"   
,;

r   )rO   rP   r   r   r   r7   r   r   Zescape_xml_cdatar2   r   r	   r	   r	   r
   Ú<module>   s   	