scripts/python/findpackage/BeautifulSoup.py
author nithyar
Mon, 20 Sep 2010 13:47:38 +0100
changeset 61 3c5e0637d4d3
parent 12 d2f4d301e581
permissions -rw-r--r--
Integration plan updates, week37
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
12
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
     1
"""Beautiful Soup
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
     2
Elixir and Tonic
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
     3
"The Screen-Scraper's Friend"
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
     4
http://www.crummy.com/software/BeautifulSoup/
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
     5
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
     6
Beautiful Soup parses a (possibly invalid) XML or HTML document into a
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
     7
tree representation. It provides methods and Pythonic idioms that make
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
     8
it easy to navigate, search, and modify the tree.
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
     9
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
    10
A well-formed XML/HTML document yields a well-formed data
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
    11
structure. An ill-formed XML/HTML document yields a correspondingly
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
    12
ill-formed data structure. If your document is only locally
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
    13
well-formed, you can use this library to find and process the
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
    14
well-formed part of it.
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
    15
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
    16
Beautiful Soup works with Python 2.2 and up. It has no external
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
    17
dependencies, but you'll have more success at converting data to UTF-8
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
    18
if you also install these three packages:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
    19
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
    20
* chardet, for auto-detecting character encodings
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
    21
  http://chardet.feedparser.org/
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
    22
* cjkcodecs and iconv_codec, which add more encodings to the ones supported
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
    23
  by stock Python.
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
    24
  http://cjkpython.i18n.org/
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
    25
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
    26
Beautiful Soup defines classes for two main parsing strategies:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
    27
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
    28
 * BeautifulStoneSoup, for parsing XML, SGML, or your domain-specific
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
    29
   language that kind of looks like XML.
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
    30
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
    31
 * BeautifulSoup, for parsing run-of-the-mill HTML code, be it valid
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
    32
   or invalid. This class has web browser-like heuristics for
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
    33
   obtaining a sensible parse tree in the face of common HTML errors.
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
    34
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
    35
Beautiful Soup also defines a class (UnicodeDammit) for autodetecting
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
    36
the encoding of an HTML or XML document, and converting it to
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
    37
Unicode. Much of this code is taken from Mark Pilgrim's Universal Feed Parser.
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
    38
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
    39
For more than you ever wanted to know about Beautiful Soup, see the
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
    40
documentation:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
    41
http://www.crummy.com/software/BeautifulSoup/documentation.html
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
    42
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
    43
Here, have some legalese:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
    44
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
    45
Copyright (c) 2004-2009, Leonard Richardson
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
    46
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
    47
All rights reserved.
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
    48
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
    49
Redistribution and use in source and binary forms, with or without
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
    50
modification, are permitted provided that the following conditions are
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
    51
met:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
    52
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
    53
  * Redistributions of source code must retain the above copyright
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
    54
    notice, this list of conditions and the following disclaimer.
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
    55
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
    56
  * Redistributions in binary form must reproduce the above
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
    57
    copyright notice, this list of conditions and the following
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
    58
    disclaimer in the documentation and/or other materials provided
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
    59
    with the distribution.
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
    60
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
    61
  * Neither the name of the the Beautiful Soup Consortium and All
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
    62
    Night Kosher Bakery nor the names of its contributors may be
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
    63
    used to endorse or promote products derived from this software
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
    64
    without specific prior written permission.
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
    65
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
    66
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
    67
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
    68
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
    69
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
    70
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
    71
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
    72
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
    73
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
    74
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
    75
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
    76
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE, DAMMIT.
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
    77
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
    78
"""
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
    79
from __future__ import generators
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
    80
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
    81
__author__ = "Leonard Richardson (leonardr@segfault.org)"
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
    82
__version__ = "3.1.0.1"
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
    83
__copyright__ = "Copyright (c) 2004-2009 Leonard Richardson"
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
    84
__license__ = "New-style BSD"
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
    85
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
    86
import codecs
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
    87
import markupbase
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
    88
import types
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
    89
import re
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
    90
from HTMLParser import HTMLParser, HTMLParseError
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
    91
try:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
    92
    from htmlentitydefs import name2codepoint
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
    93
except ImportError:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
    94
    name2codepoint = {}
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
    95
try:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
    96
    set
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
    97
except NameError:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
    98
    from sets import Set as set
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
    99
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   100
#These hacks make Beautiful Soup able to parse XML with namespaces
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   101
markupbase._declname_match = re.compile(r'[a-zA-Z][-_.:a-zA-Z0-9]*\s*').match
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   102
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   103
DEFAULT_OUTPUT_ENCODING = "utf-8"
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   104
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   105
# First, the classes that represent markup elements.
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   106
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   107
def sob(unicode, encoding):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   108
    """Returns either the given Unicode string or its encoding."""
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   109
    if encoding is None:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   110
        return unicode
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   111
    else:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   112
        return unicode.encode(encoding)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   113
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   114
class PageElement:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   115
    """Contains the navigational information for some part of the page
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   116
    (either a tag or a piece of text)"""
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   117
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   118
    def setup(self, parent=None, previous=None):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   119
        """Sets up the initial relations between this element and
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   120
        other elements."""
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   121
        self.parent = parent
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   122
        self.previous = previous
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   123
        self.next = None
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   124
        self.previousSibling = None
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   125
        self.nextSibling = None
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   126
        if self.parent and self.parent.contents:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   127
            self.previousSibling = self.parent.contents[-1]
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   128
            self.previousSibling.nextSibling = self
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   129
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   130
    def replaceWith(self, replaceWith):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   131
        oldParent = self.parent
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   132
        myIndex = self.parent.contents.index(self)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   133
        if hasattr(replaceWith, 'parent') and replaceWith.parent == self.parent:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   134
            # We're replacing this element with one of its siblings.
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   135
            index = self.parent.contents.index(replaceWith)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   136
            if index and index < myIndex:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   137
                # Furthermore, it comes before this element. That
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   138
                # means that when we extract it, the index of this
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   139
                # element will change.
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   140
                myIndex = myIndex - 1
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   141
        self.extract()
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   142
        oldParent.insert(myIndex, replaceWith)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   143
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   144
    def extract(self):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   145
        """Destructively rips this element out of the tree."""
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   146
        if self.parent:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   147
            try:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   148
                self.parent.contents.remove(self)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   149
            except ValueError:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   150
                pass
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   151
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   152
        #Find the two elements that would be next to each other if
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   153
        #this element (and any children) hadn't been parsed. Connect
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   154
        #the two.
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   155
        lastChild = self._lastRecursiveChild()
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   156
        nextElement = lastChild.next
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   157
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   158
        if self.previous:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   159
            self.previous.next = nextElement
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   160
        if nextElement:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   161
            nextElement.previous = self.previous
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   162
        self.previous = None
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   163
        lastChild.next = None
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   164
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   165
        self.parent = None
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   166
        if self.previousSibling:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   167
            self.previousSibling.nextSibling = self.nextSibling
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   168
        if self.nextSibling:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   169
            self.nextSibling.previousSibling = self.previousSibling
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   170
        self.previousSibling = self.nextSibling = None
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   171
        return self
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   172
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   173
    def _lastRecursiveChild(self):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   174
        "Finds the last element beneath this object to be parsed."
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   175
        lastChild = self
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   176
        while hasattr(lastChild, 'contents') and lastChild.contents:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   177
            lastChild = lastChild.contents[-1]
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   178
        return lastChild
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   179
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   180
    def insert(self, position, newChild):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   181
        if (isinstance(newChild, basestring)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   182
            or isinstance(newChild, unicode)) \
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   183
            and not isinstance(newChild, NavigableString):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   184
            newChild = NavigableString(newChild)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   185
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   186
        position =  min(position, len(self.contents))
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   187
        if hasattr(newChild, 'parent') and newChild.parent != None:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   188
            # We're 'inserting' an element that's already one
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   189
            # of this object's children.
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   190
            if newChild.parent == self:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   191
                index = self.find(newChild)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   192
                if index and index < position:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   193
                    # Furthermore we're moving it further down the
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   194
                    # list of this object's children. That means that
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   195
                    # when we extract this element, our target index
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   196
                    # will jump down one.
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   197
                    position = position - 1
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   198
            newChild.extract()
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   199
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   200
        newChild.parent = self
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   201
        previousChild = None
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   202
        if position == 0:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   203
            newChild.previousSibling = None
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   204
            newChild.previous = self
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   205
        else:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   206
            previousChild = self.contents[position-1]
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   207
            newChild.previousSibling = previousChild
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   208
            newChild.previousSibling.nextSibling = newChild
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   209
            newChild.previous = previousChild._lastRecursiveChild()
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   210
        if newChild.previous:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   211
            newChild.previous.next = newChild
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   212
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   213
        newChildsLastElement = newChild._lastRecursiveChild()
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   214
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   215
        if position >= len(self.contents):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   216
            newChild.nextSibling = None
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   217
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   218
            parent = self
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   219
            parentsNextSibling = None
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   220
            while not parentsNextSibling:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   221
                parentsNextSibling = parent.nextSibling
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   222
                parent = parent.parent
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   223
                if not parent: # This is the last element in the document.
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   224
                    break
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   225
            if parentsNextSibling:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   226
                newChildsLastElement.next = parentsNextSibling
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   227
            else:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   228
                newChildsLastElement.next = None
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   229
        else:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   230
            nextChild = self.contents[position]
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   231
            newChild.nextSibling = nextChild
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   232
            if newChild.nextSibling:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   233
                newChild.nextSibling.previousSibling = newChild
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   234
            newChildsLastElement.next = nextChild
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   235
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   236
        if newChildsLastElement.next:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   237
            newChildsLastElement.next.previous = newChildsLastElement
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   238
        self.contents.insert(position, newChild)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   239
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   240
    def append(self, tag):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   241
        """Appends the given tag to the contents of this tag."""
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   242
        self.insert(len(self.contents), tag)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   243
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   244
    def findNext(self, name=None, attrs={}, text=None, **kwargs):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   245
        """Returns the first item that matches the given criteria and
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   246
        appears after this Tag in the document."""
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   247
        return self._findOne(self.findAllNext, name, attrs, text, **kwargs)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   248
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   249
    def findAllNext(self, name=None, attrs={}, text=None, limit=None,
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   250
                    **kwargs):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   251
        """Returns all items that match the given criteria and appear
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   252
        after this Tag in the document."""
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   253
        return self._findAll(name, attrs, text, limit, self.nextGenerator,
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   254
                             **kwargs)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   255
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   256
    def findNextSibling(self, name=None, attrs={}, text=None, **kwargs):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   257
        """Returns the closest sibling to this Tag that matches the
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   258
        given criteria and appears after this Tag in the document."""
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   259
        return self._findOne(self.findNextSiblings, name, attrs, text,
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   260
                             **kwargs)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   261
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   262
    def findNextSiblings(self, name=None, attrs={}, text=None, limit=None,
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   263
                         **kwargs):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   264
        """Returns the siblings of this Tag that match the given
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   265
        criteria and appear after this Tag in the document."""
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   266
        return self._findAll(name, attrs, text, limit,
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   267
                             self.nextSiblingGenerator, **kwargs)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   268
    fetchNextSiblings = findNextSiblings # Compatibility with pre-3.x
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   269
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   270
    def findPrevious(self, name=None, attrs={}, text=None, **kwargs):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   271
        """Returns the first item that matches the given criteria and
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   272
        appears before this Tag in the document."""
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   273
        return self._findOne(self.findAllPrevious, name, attrs, text, **kwargs)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   274
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   275
    def findAllPrevious(self, name=None, attrs={}, text=None, limit=None,
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   276
                        **kwargs):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   277
        """Returns all items that match the given criteria and appear
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   278
        before this Tag in the document."""
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   279
        return self._findAll(name, attrs, text, limit, self.previousGenerator,
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   280
                           **kwargs)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   281
    fetchPrevious = findAllPrevious # Compatibility with pre-3.x
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   282
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   283
    def findPreviousSibling(self, name=None, attrs={}, text=None, **kwargs):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   284
        """Returns the closest sibling to this Tag that matches the
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   285
        given criteria and appears before this Tag in the document."""
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   286
        return self._findOne(self.findPreviousSiblings, name, attrs, text,
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   287
                             **kwargs)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   288
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   289
    def findPreviousSiblings(self, name=None, attrs={}, text=None,
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   290
                             limit=None, **kwargs):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   291
        """Returns the siblings of this Tag that match the given
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   292
        criteria and appear before this Tag in the document."""
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   293
        return self._findAll(name, attrs, text, limit,
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   294
                             self.previousSiblingGenerator, **kwargs)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   295
    fetchPreviousSiblings = findPreviousSiblings # Compatibility with pre-3.x
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   296
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   297
    def findParent(self, name=None, attrs={}, **kwargs):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   298
        """Returns the closest parent of this Tag that matches the given
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   299
        criteria."""
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   300
        # NOTE: We can't use _findOne because findParents takes a different
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   301
        # set of arguments.
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   302
        r = None
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   303
        l = self.findParents(name, attrs, 1)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   304
        if l:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   305
            r = l[0]
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   306
        return r
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   307
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   308
    def findParents(self, name=None, attrs={}, limit=None, **kwargs):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   309
        """Returns the parents of this Tag that match the given
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   310
        criteria."""
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   311
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   312
        return self._findAll(name, attrs, None, limit, self.parentGenerator,
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   313
                             **kwargs)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   314
    fetchParents = findParents # Compatibility with pre-3.x
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   315
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   316
    #These methods do the real heavy lifting.
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   317
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   318
    def _findOne(self, method, name, attrs, text, **kwargs):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   319
        r = None
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   320
        l = method(name, attrs, text, 1, **kwargs)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   321
        if l:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   322
            r = l[0]
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   323
        return r
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   324
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   325
    def _findAll(self, name, attrs, text, limit, generator, **kwargs):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   326
        "Iterates over a generator looking for things that match."
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   327
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   328
        if isinstance(name, SoupStrainer):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   329
            strainer = name
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   330
        else:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   331
            # Build a SoupStrainer
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   332
            strainer = SoupStrainer(name, attrs, text, **kwargs)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   333
        results = ResultSet(strainer)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   334
        g = generator()
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   335
        while True:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   336
            try:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   337
                i = g.next()
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   338
            except StopIteration:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   339
                break
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   340
            if i:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   341
                found = strainer.search(i)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   342
                if found:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   343
                    results.append(found)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   344
                    if limit and len(results) >= limit:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   345
                        break
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   346
        return results
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   347
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   348
    #These Generators can be used to navigate starting from both
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   349
    #NavigableStrings and Tags.
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   350
    def nextGenerator(self):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   351
        i = self
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   352
        while i:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   353
            i = i.next
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   354
            yield i
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   355
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   356
    def nextSiblingGenerator(self):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   357
        i = self
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   358
        while i:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   359
            i = i.nextSibling
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   360
            yield i
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   361
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   362
    def previousGenerator(self):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   363
        i = self
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   364
        while i:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   365
            i = i.previous
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   366
            yield i
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   367
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   368
    def previousSiblingGenerator(self):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   369
        i = self
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   370
        while i:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   371
            i = i.previousSibling
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   372
            yield i
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   373
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   374
    def parentGenerator(self):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   375
        i = self
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   376
        while i:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   377
            i = i.parent
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   378
            yield i
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   379
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   380
    # Utility methods
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   381
    def substituteEncoding(self, str, encoding=None):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   382
        encoding = encoding or "utf-8"
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   383
        return str.replace("%SOUP-ENCODING%", encoding)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   384
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   385
    def toEncoding(self, s, encoding=None):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   386
        """Encodes an object to a string in some encoding, or to Unicode.
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   387
        ."""
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   388
        if isinstance(s, unicode):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   389
            if encoding:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   390
                s = s.encode(encoding)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   391
        elif isinstance(s, str):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   392
            if encoding:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   393
                s = s.encode(encoding)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   394
            else:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   395
                s = unicode(s)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   396
        else:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   397
            if encoding:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   398
                s  = self.toEncoding(str(s), encoding)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   399
            else:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   400
                s = unicode(s)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   401
        return s
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   402
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   403
class NavigableString(unicode, PageElement):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   404
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   405
    def __new__(cls, value):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   406
        """Create a new NavigableString.
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   407
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   408
        When unpickling a NavigableString, this method is called with
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   409
        the string in DEFAULT_OUTPUT_ENCODING. That encoding needs to be
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   410
        passed in to the superclass's __new__ or the superclass won't know
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   411
        how to handle non-ASCII characters.
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   412
        """
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   413
        if isinstance(value, unicode):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   414
            return unicode.__new__(cls, value)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   415
        return unicode.__new__(cls, value, DEFAULT_OUTPUT_ENCODING)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   416
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   417
    def __getnewargs__(self):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   418
        return (unicode(self),)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   419
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   420
    def __getattr__(self, attr):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   421
        """text.string gives you text. This is for backwards
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   422
        compatibility for Navigable*String, but for CData* it lets you
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   423
        get the string without the CData wrapper."""
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   424
        if attr == 'string':
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   425
            return self
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   426
        else:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   427
            raise AttributeError, "'%s' object has no attribute '%s'" % (self.__class__.__name__, attr)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   428
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   429
    def encode(self, encoding=DEFAULT_OUTPUT_ENCODING):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   430
        return self.decode().encode(encoding)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   431
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   432
    def decodeGivenEventualEncoding(self, eventualEncoding):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   433
        return self
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   434
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   435
class CData(NavigableString):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   436
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   437
    def decodeGivenEventualEncoding(self, eventualEncoding):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   438
        return u'<![CDATA[' + self + u']]>'
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   439
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   440
class ProcessingInstruction(NavigableString):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   441
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   442
    def decodeGivenEventualEncoding(self, eventualEncoding):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   443
        output = self
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   444
        if u'%SOUP-ENCODING%' in output:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   445
            output = self.substituteEncoding(output, eventualEncoding)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   446
        return u'<?' + output + u'?>'
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   447
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   448
class Comment(NavigableString):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   449
    def decodeGivenEventualEncoding(self, eventualEncoding):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   450
        return u'<!--' + self + u'-->'
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   451
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   452
class Declaration(NavigableString):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   453
    def decodeGivenEventualEncoding(self, eventualEncoding):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   454
        return u'<!' + self + u'>'
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   455
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   456
class Tag(PageElement):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   457
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   458
    """Represents a found HTML tag with its attributes and contents."""
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   459
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   460
    def _invert(h):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   461
        "Cheap function to invert a hash."
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   462
        i = {}
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   463
        for k,v in h.items():
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   464
            i[v] = k
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   465
        return i
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   466
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   467
    XML_ENTITIES_TO_SPECIAL_CHARS = { "apos" : "'",
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   468
                                      "quot" : '"',
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   469
                                      "amp" : "&",
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   470
                                      "lt" : "<",
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   471
                                      "gt" : ">" }
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   472
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   473
    XML_SPECIAL_CHARS_TO_ENTITIES = _invert(XML_ENTITIES_TO_SPECIAL_CHARS)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   474
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   475
    def _convertEntities(self, match):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   476
        """Used in a call to re.sub to replace HTML, XML, and numeric
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   477
        entities with the appropriate Unicode characters. If HTML
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   478
        entities are being converted, any unrecognized entities are
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   479
        escaped."""
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   480
        x = match.group(1)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   481
        if self.convertHTMLEntities and x in name2codepoint:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   482
            return unichr(name2codepoint[x])
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   483
        elif x in self.XML_ENTITIES_TO_SPECIAL_CHARS:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   484
            if self.convertXMLEntities:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   485
                return self.XML_ENTITIES_TO_SPECIAL_CHARS[x]
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   486
            else:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   487
                return u'&%s;' % x
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   488
        elif len(x) > 0 and x[0] == '#':
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   489
            # Handle numeric entities
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   490
            if len(x) > 1 and x[1] == 'x':
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   491
                return unichr(int(x[2:], 16))
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   492
            else:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   493
                return unichr(int(x[1:]))
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   494
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   495
        elif self.escapeUnrecognizedEntities:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   496
            return u'&amp;%s;' % x
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   497
        else:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   498
            return u'&%s;' % x
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   499
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   500
    def __init__(self, parser, name, attrs=None, parent=None,
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   501
                 previous=None):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   502
        "Basic constructor."
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   503
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   504
        # We don't actually store the parser object: that lets extracted
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   505
        # chunks be garbage-collected
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   506
        self.parserClass = parser.__class__
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   507
        self.isSelfClosing = parser.isSelfClosingTag(name)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   508
        self.name = name
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   509
        if attrs == None:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   510
            attrs = []
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   511
        self.attrs = attrs
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   512
        self.contents = []
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   513
        self.setup(parent, previous)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   514
        self.hidden = False
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   515
        self.containsSubstitutions = False
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   516
        self.convertHTMLEntities = parser.convertHTMLEntities
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   517
        self.convertXMLEntities = parser.convertXMLEntities
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   518
        self.escapeUnrecognizedEntities = parser.escapeUnrecognizedEntities
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   519
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   520
        def convert(kval):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   521
            "Converts HTML, XML and numeric entities in the attribute value."
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   522
            k, val = kval
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   523
            if val is None:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   524
                return kval
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   525
            return (k, re.sub("&(#\d+|#x[0-9a-fA-F]+|\w+);",
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   526
                              self._convertEntities, val))
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   527
        self.attrs = map(convert, self.attrs)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   528
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   529
    def get(self, key, default=None):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   530
        """Returns the value of the 'key' attribute for the tag, or
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   531
        the value given for 'default' if it doesn't have that
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   532
        attribute."""
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   533
        return self._getAttrMap().get(key, default)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   534
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   535
    def has_key(self, key):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   536
        return self._getAttrMap().has_key(key)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   537
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   538
    def __getitem__(self, key):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   539
        """tag[key] returns the value of the 'key' attribute for the tag,
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   540
        and throws an exception if it's not there."""
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   541
        return self._getAttrMap()[key]
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   542
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   543
    def __iter__(self):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   544
        "Iterating over a tag iterates over its contents."
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   545
        return iter(self.contents)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   546
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   547
    def __len__(self):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   548
        "The length of a tag is the length of its list of contents."
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   549
        return len(self.contents)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   550
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   551
    def __contains__(self, x):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   552
        return x in self.contents
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   553
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   554
    def __nonzero__(self):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   555
        "A tag is non-None even if it has no contents."
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   556
        return True
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   557
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   558
    def __setitem__(self, key, value):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   559
        """Setting tag[key] sets the value of the 'key' attribute for the
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   560
        tag."""
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   561
        self._getAttrMap()
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   562
        self.attrMap[key] = value
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   563
        found = False
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   564
        for i in range(0, len(self.attrs)):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   565
            if self.attrs[i][0] == key:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   566
                self.attrs[i] = (key, value)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   567
                found = True
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   568
        if not found:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   569
            self.attrs.append((key, value))
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   570
        self._getAttrMap()[key] = value
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   571
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   572
    def __delitem__(self, key):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   573
        "Deleting tag[key] deletes all 'key' attributes for the tag."
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   574
        for item in self.attrs:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   575
            if item[0] == key:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   576
                self.attrs.remove(item)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   577
                #We don't break because bad HTML can define the same
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   578
                #attribute multiple times.
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   579
            self._getAttrMap()
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   580
            if self.attrMap.has_key(key):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   581
                del self.attrMap[key]
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   582
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   583
    def __call__(self, *args, **kwargs):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   584
        """Calling a tag like a function is the same as calling its
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   585
        findAll() method. Eg. tag('a') returns a list of all the A tags
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   586
        found within this tag."""
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   587
        return apply(self.findAll, args, kwargs)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   588
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   589
    def __getattr__(self, tag):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   590
        #print "Getattr %s.%s" % (self.__class__, tag)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   591
        if len(tag) > 3 and tag.rfind('Tag') == len(tag)-3:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   592
            return self.find(tag[:-3])
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   593
        elif tag.find('__') != 0:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   594
            return self.find(tag)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   595
        raise AttributeError, "'%s' object has no attribute '%s'" % (self.__class__, tag)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   596
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   597
    def __eq__(self, other):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   598
        """Returns true iff this tag has the same name, the same attributes,
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   599
        and the same contents (recursively) as the given tag.
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   600
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   601
        NOTE: right now this will return false if two tags have the
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   602
        same attributes in a different order. Should this be fixed?"""
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   603
        if not hasattr(other, 'name') or not hasattr(other, 'attrs') or not hasattr(other, 'contents') or self.name != other.name or self.attrs != other.attrs or len(self) != len(other):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   604
            return False
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   605
        for i in range(0, len(self.contents)):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   606
            if self.contents[i] != other.contents[i]:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   607
                return False
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   608
        return True
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   609
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   610
    def __ne__(self, other):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   611
        """Returns true iff this tag is not identical to the other tag,
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   612
        as defined in __eq__."""
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   613
        return not self == other
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   614
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   615
    def __repr__(self, encoding=DEFAULT_OUTPUT_ENCODING):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   616
        """Renders this tag as a string."""
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   617
        return self.decode(eventualEncoding=encoding)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   618
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   619
    BARE_AMPERSAND_OR_BRACKET = re.compile("([<>]|"
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   620
                                           + "&(?!#\d+;|#x[0-9a-fA-F]+;|\w+;)"
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   621
                                           + ")")
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   622
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   623
    def _sub_entity(self, x):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   624
        """Used with a regular expression to substitute the
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   625
        appropriate XML entity for an XML special character."""
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   626
        return "&" + self.XML_SPECIAL_CHARS_TO_ENTITIES[x.group(0)[0]] + ";"
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   627
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   628
    def __unicode__(self):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   629
        return self.decode()
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   630
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   631
    def __str__(self):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   632
        return self.encode()
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   633
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   634
    def encode(self, encoding=DEFAULT_OUTPUT_ENCODING,
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   635
               prettyPrint=False, indentLevel=0):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   636
        return self.decode(prettyPrint, indentLevel, encoding).encode(encoding)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   637
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   638
    def decode(self, prettyPrint=False, indentLevel=0,
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   639
               eventualEncoding=DEFAULT_OUTPUT_ENCODING):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   640
        """Returns a string or Unicode representation of this tag and
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   641
        its contents. To get Unicode, pass None for encoding."""
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   642
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   643
        attrs = []
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   644
        if self.attrs:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   645
            for key, val in self.attrs:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   646
                fmt = '%s="%s"'
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   647
                if isString(val):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   648
                    if (self.containsSubstitutions
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   649
                        and eventualEncoding is not None
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   650
                        and '%SOUP-ENCODING%' in val):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   651
                        val = self.substituteEncoding(val, eventualEncoding)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   652
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   653
                    # The attribute value either:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   654
                    #
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   655
                    # * Contains no embedded double quotes or single quotes.
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   656
                    #   No problem: we enclose it in double quotes.
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   657
                    # * Contains embedded single quotes. No problem:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   658
                    #   double quotes work here too.
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   659
                    # * Contains embedded double quotes. No problem:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   660
                    #   we enclose it in single quotes.
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   661
                    # * Embeds both single _and_ double quotes. This
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   662
                    #   can't happen naturally, but it can happen if
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   663
                    #   you modify an attribute value after parsing
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   664
                    #   the document. Now we have a bit of a
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   665
                    #   problem. We solve it by enclosing the
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   666
                    #   attribute in single quotes, and escaping any
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   667
                    #   embedded single quotes to XML entities.
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   668
                    if '"' in val:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   669
                        fmt = "%s='%s'"
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   670
                        if "'" in val:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   671
                            # TODO: replace with apos when
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   672
                            # appropriate.
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   673
                            val = val.replace("'", "&squot;")
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   674
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   675
                    # Now we're okay w/r/t quotes. But the attribute
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   676
                    # value might also contain angle brackets, or
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   677
                    # ampersands that aren't part of entities. We need
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   678
                    # to escape those to XML entities too.
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   679
                    val = self.BARE_AMPERSAND_OR_BRACKET.sub(self._sub_entity, val)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   680
                if val is None:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   681
                    # Handle boolean attributes.
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   682
                    decoded = key
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   683
                else:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   684
                    decoded = fmt % (key, val)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   685
                attrs.append(decoded)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   686
        close = ''
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   687
        closeTag = ''
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   688
        if self.isSelfClosing:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   689
            close = ' /'
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   690
        else:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   691
            closeTag = '</%s>' % self.name
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   692
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   693
        indentTag, indentContents = 0, 0
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   694
        if prettyPrint:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   695
            indentTag = indentLevel
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   696
            space = (' ' * (indentTag-1))
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   697
            indentContents = indentTag + 1
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   698
        contents = self.decodeContents(prettyPrint, indentContents,
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   699
                                       eventualEncoding)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   700
        if self.hidden:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   701
            s = contents
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   702
        else:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   703
            s = []
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   704
            attributeString = ''
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   705
            if attrs:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   706
                attributeString = ' ' + ' '.join(attrs)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   707
            if prettyPrint:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   708
                s.append(space)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   709
            s.append('<%s%s%s>' % (self.name, attributeString, close))
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   710
            if prettyPrint:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   711
                s.append("\n")
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   712
            s.append(contents)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   713
            if prettyPrint and contents and contents[-1] != "\n":
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   714
                s.append("\n")
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   715
            if prettyPrint and closeTag:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   716
                s.append(space)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   717
            s.append(closeTag)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   718
            if prettyPrint and closeTag and self.nextSibling:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   719
                s.append("\n")
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   720
            s = ''.join(s)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   721
        return s
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   722
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   723
    def decompose(self):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   724
        """Recursively destroys the contents of this tree."""
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   725
        contents = [i for i in self.contents]
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   726
        for i in contents:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   727
            if isinstance(i, Tag):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   728
                i.decompose()
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   729
            else:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   730
                i.extract()
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   731
        self.extract()
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   732
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   733
    def prettify(self, encoding=DEFAULT_OUTPUT_ENCODING):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   734
        return self.encode(encoding, True)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   735
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   736
    def encodeContents(self, encoding=DEFAULT_OUTPUT_ENCODING,
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   737
                       prettyPrint=False, indentLevel=0):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   738
        return self.decodeContents(prettyPrint, indentLevel).encode(encoding)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   739
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   740
    def decodeContents(self, prettyPrint=False, indentLevel=0,
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   741
                       eventualEncoding=DEFAULT_OUTPUT_ENCODING):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   742
        """Renders the contents of this tag as a string in the given
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   743
        encoding. If encoding is None, returns a Unicode string.."""
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   744
        s=[]
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   745
        for c in self:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   746
            text = None
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   747
            if isinstance(c, NavigableString):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   748
                text = c.decodeGivenEventualEncoding(eventualEncoding)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   749
            elif isinstance(c, Tag):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   750
                s.append(c.decode(prettyPrint, indentLevel, eventualEncoding))
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   751
            if text and prettyPrint:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   752
                text = text.strip()
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   753
            if text:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   754
                if prettyPrint:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   755
                    s.append(" " * (indentLevel-1))
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   756
                s.append(text)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   757
                if prettyPrint:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   758
                    s.append("\n")
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   759
        return ''.join(s)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   760
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   761
    #Soup methods
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   762
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   763
    def find(self, name=None, attrs={}, recursive=True, text=None,
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   764
             **kwargs):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   765
        """Return only the first child of this Tag matching the given
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   766
        criteria."""
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   767
        r = None
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   768
        l = self.findAll(name, attrs, recursive, text, 1, **kwargs)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   769
        if l:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   770
            r = l[0]
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   771
        return r
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   772
    findChild = find
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   773
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   774
    def findAll(self, name=None, attrs={}, recursive=True, text=None,
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   775
                limit=None, **kwargs):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   776
        """Extracts a list of Tag objects that match the given
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   777
        criteria.  You can specify the name of the Tag and any
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   778
        attributes you want the Tag to have.
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   779
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   780
        The value of a key-value pair in the 'attrs' map can be a
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   781
        string, a list of strings, a regular expression object, or a
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   782
        callable that takes a string and returns whether or not the
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   783
        string matches for some custom definition of 'matches'. The
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   784
        same is true of the tag name."""
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   785
        generator = self.recursiveChildGenerator
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   786
        if not recursive:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   787
            generator = self.childGenerator
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   788
        return self._findAll(name, attrs, text, limit, generator, **kwargs)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   789
    findChildren = findAll
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   790
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   791
    # Pre-3.x compatibility methods. Will go away in 4.0.
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   792
    first = find
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   793
    fetch = findAll
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   794
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   795
    def fetchText(self, text=None, recursive=True, limit=None):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   796
        return self.findAll(text=text, recursive=recursive, limit=limit)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   797
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   798
    def firstText(self, text=None, recursive=True):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   799
        return self.find(text=text, recursive=recursive)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   800
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   801
    # 3.x compatibility methods. Will go away in 4.0.
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   802
    def renderContents(self, encoding=DEFAULT_OUTPUT_ENCODING,
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   803
                       prettyPrint=False, indentLevel=0):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   804
        if encoding is None:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   805
            return self.decodeContents(prettyPrint, indentLevel, encoding)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   806
        else:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   807
            return self.encodeContents(encoding, prettyPrint, indentLevel)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   808
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   809
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   810
    #Private methods
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   811
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   812
    def _getAttrMap(self):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   813
        """Initializes a map representation of this tag's attributes,
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   814
        if not already initialized."""
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   815
        if not getattr(self, 'attrMap'):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   816
            self.attrMap = {}
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   817
            for (key, value) in self.attrs:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   818
                self.attrMap[key] = value
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   819
        return self.attrMap
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   820
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   821
    #Generator methods
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   822
    def recursiveChildGenerator(self):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   823
        if not len(self.contents):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   824
            raise StopIteration
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   825
        stopNode = self._lastRecursiveChild().next
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   826
        current = self.contents[0]
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   827
        while current is not stopNode:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   828
            yield current
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   829
            current = current.next
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   830
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   831
    def childGenerator(self):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   832
        if not len(self.contents):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   833
            raise StopIteration
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   834
        current = self.contents[0]
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   835
        while current:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   836
            yield current
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   837
            current = current.nextSibling
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   838
        raise StopIteration
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   839
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   840
# Next, a couple classes to represent queries and their results.
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   841
class SoupStrainer:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   842
    """Encapsulates a number of ways of matching a markup element (tag or
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   843
    text)."""
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   844
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   845
    def __init__(self, name=None, attrs={}, text=None, **kwargs):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   846
        self.name = name
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   847
        if isString(attrs):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   848
            kwargs['class'] = attrs
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   849
            attrs = None
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   850
        if kwargs:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   851
            if attrs:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   852
                attrs = attrs.copy()
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   853
                attrs.update(kwargs)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   854
            else:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   855
                attrs = kwargs
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   856
        self.attrs = attrs
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   857
        self.text = text
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   858
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   859
    def __str__(self):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   860
        if self.text:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   861
            return self.text
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   862
        else:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   863
            return "%s|%s" % (self.name, self.attrs)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   864
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   865
    def searchTag(self, markupName=None, markupAttrs={}):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   866
        found = None
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   867
        markup = None
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   868
        if isinstance(markupName, Tag):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   869
            markup = markupName
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   870
            markupAttrs = markup
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   871
        callFunctionWithTagData = callable(self.name) \
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   872
                                and not isinstance(markupName, Tag)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   873
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   874
        if (not self.name) \
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   875
               or callFunctionWithTagData \
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   876
               or (markup and self._matches(markup, self.name)) \
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   877
               or (not markup and self._matches(markupName, self.name)):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   878
            if callFunctionWithTagData:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   879
                match = self.name(markupName, markupAttrs)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   880
            else:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   881
                match = True
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   882
                markupAttrMap = None
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   883
                for attr, matchAgainst in self.attrs.items():
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   884
                    if not markupAttrMap:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   885
                         if hasattr(markupAttrs, 'get'):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   886
                            markupAttrMap = markupAttrs
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   887
                         else:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   888
                            markupAttrMap = {}
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   889
                            for k,v in markupAttrs:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   890
                                markupAttrMap[k] = v
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   891
                    attrValue = markupAttrMap.get(attr)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   892
                    if not self._matches(attrValue, matchAgainst):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   893
                        match = False
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   894
                        break
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   895
            if match:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   896
                if markup:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   897
                    found = markup
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   898
                else:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   899
                    found = markupName
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   900
        return found
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   901
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   902
    def search(self, markup):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   903
        #print 'looking for %s in %s' % (self, markup)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   904
        found = None
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   905
        # If given a list of items, scan it for a text element that
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   906
        # matches.
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   907
        if isList(markup) and not isinstance(markup, Tag):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   908
            for element in markup:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   909
                if isinstance(element, NavigableString) \
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   910
                       and self.search(element):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   911
                    found = element
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   912
                    break
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   913
        # If it's a Tag, make sure its name or attributes match.
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   914
        # Don't bother with Tags if we're searching for text.
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   915
        elif isinstance(markup, Tag):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   916
            if not self.text:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   917
                found = self.searchTag(markup)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   918
        # If it's text, make sure the text matches.
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   919
        elif isinstance(markup, NavigableString) or \
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   920
                 isString(markup):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   921
            if self._matches(markup, self.text):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   922
                found = markup
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   923
        else:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   924
            raise Exception, "I don't know how to match against a %s" \
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   925
                  % markup.__class__
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   926
        return found
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   927
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   928
    def _matches(self, markup, matchAgainst):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   929
        #print "Matching %s against %s" % (markup, matchAgainst)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   930
        result = False
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   931
        if matchAgainst == True and type(matchAgainst) == types.BooleanType:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   932
            result = markup != None
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   933
        elif callable(matchAgainst):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   934
            result = matchAgainst(markup)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   935
        else:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   936
            #Custom match methods take the tag as an argument, but all
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   937
            #other ways of matching match the tag name as a string.
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   938
            if isinstance(markup, Tag):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   939
                markup = markup.name
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   940
            if markup is not None and not isString(markup):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   941
                markup = unicode(markup)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   942
            #Now we know that chunk is either a string, or None.
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   943
            if hasattr(matchAgainst, 'match'):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   944
                # It's a regexp object.
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   945
                result = markup and matchAgainst.search(markup)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   946
            elif (isList(matchAgainst)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   947
                  and (markup is not None or not isString(matchAgainst))):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   948
                result = markup in matchAgainst
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   949
            elif hasattr(matchAgainst, 'items'):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   950
                result = markup.has_key(matchAgainst)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   951
            elif matchAgainst and isString(markup):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   952
                if isinstance(markup, unicode):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   953
                    matchAgainst = unicode(matchAgainst)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   954
                else:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   955
                    matchAgainst = str(matchAgainst)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   956
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   957
            if not result:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   958
                result = matchAgainst == markup
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   959
        return result
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   960
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   961
class ResultSet(list):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   962
    """A ResultSet is just a list that keeps track of the SoupStrainer
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   963
    that created it."""
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   964
    def __init__(self, source):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   965
        list.__init__([])
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   966
        self.source = source
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   967
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   968
# Now, some helper functions.
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   969
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   970
def isList(l):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   971
    """Convenience method that works with all 2.x versions of Python
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   972
    to determine whether or not something is listlike."""
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   973
    return ((hasattr(l, '__iter__') and not isString(l))
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   974
            or (type(l) in (types.ListType, types.TupleType)))
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   975
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   976
def isString(s):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   977
    """Convenience method that works with all 2.x versions of Python
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   978
    to determine whether or not something is stringlike."""
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   979
    try:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   980
        return isinstance(s, unicode) or isinstance(s, basestring)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   981
    except NameError:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   982
        return isinstance(s, str)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   983
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   984
def buildTagMap(default, *args):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   985
    """Turns a list of maps, lists, or scalars into a single map.
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   986
    Used to build the SELF_CLOSING_TAGS, NESTABLE_TAGS, and
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   987
    NESTING_RESET_TAGS maps out of lists and partial maps."""
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   988
    built = {}
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   989
    for portion in args:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   990
        if hasattr(portion, 'items'):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   991
            #It's a map. Merge it.
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   992
            for k,v in portion.items():
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   993
                built[k] = v
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   994
        elif isList(portion) and not isString(portion):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   995
            #It's a list. Map each item to the default.
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   996
            for k in portion:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   997
                built[k] = default
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   998
        else:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
   999
            #It's a scalar. Map it to the default.
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1000
            built[portion] = default
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1001
    return built
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1002
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1003
# Now, the parser classes.
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1004
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1005
class HTMLParserBuilder(HTMLParser):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1006
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1007
    def __init__(self, soup):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1008
        HTMLParser.__init__(self)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1009
        self.soup = soup
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1010
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1011
    # We inherit feed() and reset().
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1012
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1013
    def handle_starttag(self, name, attrs):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1014
        if name == 'meta':
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1015
            self.soup.extractCharsetFromMeta(attrs)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1016
        else:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1017
            self.soup.unknown_starttag(name, attrs)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1018
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1019
    def handle_endtag(self, name):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1020
        self.soup.unknown_endtag(name)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1021
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1022
    def handle_data(self, content):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1023
        self.soup.handle_data(content)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1024
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1025
    def _toStringSubclass(self, text, subclass):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1026
        """Adds a certain piece of text to the tree as a NavigableString
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1027
        subclass."""
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1028
        self.soup.endData()
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1029
        self.handle_data(text)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1030
        self.soup.endData(subclass)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1031
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1032
    def handle_pi(self, text):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1033
        """Handle a processing instruction as a ProcessingInstruction
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1034
        object, possibly one with a %SOUP-ENCODING% slot into which an
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1035
        encoding will be plugged later."""
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1036
        if text[:3] == "xml":
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1037
            text = u"xml version='1.0' encoding='%SOUP-ENCODING%'"
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1038
        self._toStringSubclass(text, ProcessingInstruction)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1039
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1040
    def handle_comment(self, text):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1041
        "Handle comments as Comment objects."
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1042
        self._toStringSubclass(text, Comment)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1043
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1044
    def handle_charref(self, ref):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1045
        "Handle character references as data."
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1046
        if self.soup.convertEntities:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1047
            data = unichr(int(ref))
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1048
        else:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1049
            data = '&#%s;' % ref
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1050
        self.handle_data(data)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1051
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1052
    def handle_entityref(self, ref):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1053
        """Handle entity references as data, possibly converting known
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1054
        HTML and/or XML entity references to the corresponding Unicode
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1055
        characters."""
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1056
        data = None
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1057
        if self.soup.convertHTMLEntities:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1058
            try:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1059
                data = unichr(name2codepoint[ref])
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1060
            except KeyError:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1061
                pass
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1062
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1063
        if not data and self.soup.convertXMLEntities:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1064
                data = self.soup.XML_ENTITIES_TO_SPECIAL_CHARS.get(ref)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1065
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1066
        if not data and self.soup.convertHTMLEntities and \
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1067
            not self.soup.XML_ENTITIES_TO_SPECIAL_CHARS.get(ref):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1068
                # TODO: We've got a problem here. We're told this is
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1069
                # an entity reference, but it's not an XML entity
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1070
                # reference or an HTML entity reference. Nonetheless,
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1071
                # the logical thing to do is to pass it through as an
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1072
                # unrecognized entity reference.
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1073
                #
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1074
                # Except: when the input is "&carol;" this function
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1075
                # will be called with input "carol". When the input is
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1076
                # "AT&T", this function will be called with input
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1077
                # "T". We have no way of knowing whether a semicolon
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1078
                # was present originally, so we don't know whether
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1079
                # this is an unknown entity or just a misplaced
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1080
                # ampersand.
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1081
                #
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1082
                # The more common case is a misplaced ampersand, so I
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1083
                # escape the ampersand and omit the trailing semicolon.
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1084
                data = "&amp;%s" % ref
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1085
        if not data:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1086
            # This case is different from the one above, because we
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1087
            # haven't already gone through a supposedly comprehensive
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1088
            # mapping of entities to Unicode characters. We might not
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1089
            # have gone through any mapping at all. So the chances are
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1090
            # very high that this is a real entity, and not a
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1091
            # misplaced ampersand.
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1092
            data = "&%s;" % ref
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1093
        self.handle_data(data)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1094
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1095
    def handle_decl(self, data):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1096
        "Handle DOCTYPEs and the like as Declaration objects."
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1097
        self._toStringSubclass(data, Declaration)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1098
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1099
    def parse_declaration(self, i):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1100
        """Treat a bogus SGML declaration as raw data. Treat a CDATA
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1101
        declaration as a CData object."""
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1102
        j = None
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1103
        if self.rawdata[i:i+9] == '<![CDATA[':
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1104
             k = self.rawdata.find(']]>', i)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1105
             if k == -1:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1106
                 k = len(self.rawdata)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1107
             data = self.rawdata[i+9:k]
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1108
             j = k+3
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1109
             self._toStringSubclass(data, CData)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1110
        else:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1111
            try:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1112
                j = HTMLParser.parse_declaration(self, i)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1113
            except HTMLParseError:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1114
                toHandle = self.rawdata[i:]
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1115
                self.handle_data(toHandle)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1116
                j = i + len(toHandle)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1117
        return j
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1118
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1119
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1120
class BeautifulStoneSoup(Tag):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1121
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1122
    """This class contains the basic parser and search code. It defines
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1123
    a parser that knows nothing about tag behavior except for the
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1124
    following:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1125
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1126
      You can't close a tag without closing all the tags it encloses.
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1127
      That is, "<foo><bar></foo>" actually means
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1128
      "<foo><bar></bar></foo>".
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1129
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1130
    [Another possible explanation is "<foo><bar /></foo>", but since
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1131
    this class defines no SELF_CLOSING_TAGS, it will never use that
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1132
    explanation.]
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1133
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1134
    This class is useful for parsing XML or made-up markup languages,
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1135
    or when BeautifulSoup makes an assumption counter to what you were
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1136
    expecting."""
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1137
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1138
    SELF_CLOSING_TAGS = {}
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1139
    NESTABLE_TAGS = {}
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1140
    RESET_NESTING_TAGS = {}
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1141
    QUOTE_TAGS = {}
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1142
    PRESERVE_WHITESPACE_TAGS = []
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1143
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1144
    MARKUP_MASSAGE = [(re.compile('(<[^<>]*)/>'),
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1145
                       lambda x: x.group(1) + ' />'),
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1146
                      (re.compile('<!\s+([^<>]*)>'),
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1147
                       lambda x: '<!' + x.group(1) + '>')
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1148
                      ]
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1149
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1150
    ROOT_TAG_NAME = u'[document]'
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1151
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1152
    HTML_ENTITIES = "html"
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1153
    XML_ENTITIES = "xml"
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1154
    XHTML_ENTITIES = "xhtml"
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1155
    # TODO: This only exists for backwards-compatibility
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1156
    ALL_ENTITIES = XHTML_ENTITIES
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1157
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1158
    # Used when determining whether a text node is all whitespace and
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1159
    # can be replaced with a single space. A text node that contains
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1160
    # fancy Unicode spaces (usually non-breaking) should be left
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1161
    # alone.
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1162
    STRIP_ASCII_SPACES = { 9: None, 10: None, 12: None, 13: None, 32: None, }
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1163
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1164
    def __init__(self, markup="", parseOnlyThese=None, fromEncoding=None,
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1165
                 markupMassage=True, smartQuotesTo=XML_ENTITIES,
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1166
                 convertEntities=None, selfClosingTags=None, isHTML=False,
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1167
                 builder=HTMLParserBuilder):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1168
        """The Soup object is initialized as the 'root tag', and the
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1169
        provided markup (which can be a string or a file-like object)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1170
        is fed into the underlying parser.
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1171
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1172
        HTMLParser will process most bad HTML, and the BeautifulSoup
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1173
        class has some tricks for dealing with some HTML that kills
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1174
        HTMLParser, but Beautiful Soup can nonetheless choke or lose data
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1175
        if your data uses self-closing tags or declarations
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1176
        incorrectly.
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1177
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1178
        By default, Beautiful Soup uses regexes to sanitize input,
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1179
        avoiding the vast majority of these problems. If the problems
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1180
        don't apply to you, pass in False for markupMassage, and
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1181
        you'll get better performance.
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1182
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1183
        The default parser massage techniques fix the two most common
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1184
        instances of invalid HTML that choke HTMLParser:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1185
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1186
         <br/> (No space between name of closing tag and tag close)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1187
         <! --Comment--> (Extraneous whitespace in declaration)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1188
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1189
        You can pass in a custom list of (RE object, replace method)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1190
        tuples to get Beautiful Soup to scrub your input the way you
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1191
        want."""
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1192
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1193
        self.parseOnlyThese = parseOnlyThese
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1194
        self.fromEncoding = fromEncoding
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1195
        self.smartQuotesTo = smartQuotesTo
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1196
        self.convertEntities = convertEntities
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1197
        # Set the rules for how we'll deal with the entities we
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1198
        # encounter
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1199
        if self.convertEntities:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1200
            # It doesn't make sense to convert encoded characters to
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1201
            # entities even while you're converting entities to Unicode.
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1202
            # Just convert it all to Unicode.
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1203
            self.smartQuotesTo = None
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1204
            if convertEntities == self.HTML_ENTITIES:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1205
                self.convertXMLEntities = False
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1206
                self.convertHTMLEntities = True
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1207
                self.escapeUnrecognizedEntities = True
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1208
            elif convertEntities == self.XHTML_ENTITIES:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1209
                self.convertXMLEntities = True
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1210
                self.convertHTMLEntities = True
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1211
                self.escapeUnrecognizedEntities = False
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1212
            elif convertEntities == self.XML_ENTITIES:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1213
                self.convertXMLEntities = True
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1214
                self.convertHTMLEntities = False
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1215
                self.escapeUnrecognizedEntities = False
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1216
        else:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1217
            self.convertXMLEntities = False
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1218
            self.convertHTMLEntities = False
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1219
            self.escapeUnrecognizedEntities = False
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1220
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1221
        self.instanceSelfClosingTags = buildTagMap(None, selfClosingTags)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1222
        self.builder = builder(self)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1223
        self.reset()
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1224
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1225
        if hasattr(markup, 'read'):        # It's a file-type object.
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1226
            markup = markup.read()
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1227
        self.markup = markup
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1228
        self.markupMassage = markupMassage
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1229
        try:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1230
            self._feed(isHTML=isHTML)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1231
        except StopParsing:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1232
            pass
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1233
        self.markup = None                 # The markup can now be GCed.
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1234
        self.builder = None                # So can the builder.
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1235
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1236
    def _feed(self, inDocumentEncoding=None, isHTML=False):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1237
        # Convert the document to Unicode.
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1238
        markup = self.markup
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1239
        if isinstance(markup, unicode):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1240
            if not hasattr(self, 'originalEncoding'):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1241
                self.originalEncoding = None
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1242
        else:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1243
            dammit = UnicodeDammit\
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1244
                     (markup, [self.fromEncoding, inDocumentEncoding],
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1245
                      smartQuotesTo=self.smartQuotesTo, isHTML=isHTML)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1246
            markup = dammit.unicode
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1247
            self.originalEncoding = dammit.originalEncoding
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1248
            self.declaredHTMLEncoding = dammit.declaredHTMLEncoding
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1249
        if markup:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1250
            if self.markupMassage:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1251
                if not isList(self.markupMassage):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1252
                    self.markupMassage = self.MARKUP_MASSAGE
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1253
                for fix, m in self.markupMassage:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1254
                    markup = fix.sub(m, markup)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1255
                # TODO: We get rid of markupMassage so that the
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1256
                # soup object can be deepcopied later on. Some
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1257
                # Python installations can't copy regexes. If anyone
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1258
                # was relying on the existence of markupMassage, this
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1259
                # might cause problems.
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1260
                del(self.markupMassage)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1261
        self.builder.reset()
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1262
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1263
        self.builder.feed(markup)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1264
        # Close out any unfinished strings and close all the open tags.
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1265
        self.endData()
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1266
        while self.currentTag.name != self.ROOT_TAG_NAME:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1267
            self.popTag()
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1268
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1269
    def isSelfClosingTag(self, name):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1270
        """Returns true iff the given string is the name of a
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1271
        self-closing tag according to this parser."""
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1272
        return self.SELF_CLOSING_TAGS.has_key(name) \
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1273
               or self.instanceSelfClosingTags.has_key(name)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1274
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1275
    def reset(self):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1276
        Tag.__init__(self, self, self.ROOT_TAG_NAME)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1277
        self.hidden = 1
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1278
        self.builder.reset()
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1279
        self.currentData = []
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1280
        self.currentTag = None
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1281
        self.tagStack = []
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1282
        self.quoteStack = []
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1283
        self.pushTag(self)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1284
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1285
    def popTag(self):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1286
        tag = self.tagStack.pop()
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1287
        # Tags with just one string-owning child get the child as a
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1288
        # 'string' property, so that soup.tag.string is shorthand for
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1289
        # soup.tag.contents[0]
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1290
        if len(self.currentTag.contents) == 1 and \
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1291
           isinstance(self.currentTag.contents[0], NavigableString):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1292
            self.currentTag.string = self.currentTag.contents[0]
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1293
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1294
        #print "Pop", tag.name
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1295
        if self.tagStack:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1296
            self.currentTag = self.tagStack[-1]
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1297
        return self.currentTag
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1298
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1299
    def pushTag(self, tag):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1300
        #print "Push", tag.name
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1301
        if self.currentTag:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1302
            self.currentTag.contents.append(tag)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1303
        self.tagStack.append(tag)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1304
        self.currentTag = self.tagStack[-1]
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1305
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1306
    def endData(self, containerClass=NavigableString):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1307
        if self.currentData:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1308
            currentData = u''.join(self.currentData)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1309
            if (currentData.translate(self.STRIP_ASCII_SPACES) == '' and
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1310
                not set([tag.name for tag in self.tagStack]).intersection(
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1311
                    self.PRESERVE_WHITESPACE_TAGS)):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1312
                if '\n' in currentData:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1313
                    currentData = '\n'
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1314
                else:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1315
                    currentData = ' '
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1316
            self.currentData = []
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1317
            if self.parseOnlyThese and len(self.tagStack) <= 1 and \
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1318
                   (not self.parseOnlyThese.text or \
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1319
                    not self.parseOnlyThese.search(currentData)):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1320
                return
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1321
            o = containerClass(currentData)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1322
            o.setup(self.currentTag, self.previous)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1323
            if self.previous:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1324
                self.previous.next = o
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1325
            self.previous = o
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1326
            self.currentTag.contents.append(o)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1327
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1328
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1329
    def _popToTag(self, name, inclusivePop=True):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1330
        """Pops the tag stack up to and including the most recent
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1331
        instance of the given tag. If inclusivePop is false, pops the tag
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1332
        stack up to but *not* including the most recent instqance of
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1333
        the given tag."""
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1334
        #print "Popping to %s" % name
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1335
        if name == self.ROOT_TAG_NAME:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1336
            return
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1337
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1338
        numPops = 0
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1339
        mostRecentTag = None
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1340
        for i in range(len(self.tagStack)-1, 0, -1):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1341
            if name == self.tagStack[i].name:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1342
                numPops = len(self.tagStack)-i
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1343
                break
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1344
        if not inclusivePop:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1345
            numPops = numPops - 1
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1346
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1347
        for i in range(0, numPops):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1348
            mostRecentTag = self.popTag()
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1349
        return mostRecentTag
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1350
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1351
    def _smartPop(self, name):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1352
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1353
        """We need to pop up to the previous tag of this type, unless
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1354
        one of this tag's nesting reset triggers comes between this
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1355
        tag and the previous tag of this type, OR unless this tag is a
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1356
        generic nesting trigger and another generic nesting trigger
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1357
        comes between this tag and the previous tag of this type.
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1358
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1359
        Examples:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1360
         <p>Foo<b>Bar *<p>* should pop to 'p', not 'b'.
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1361
         <p>Foo<table>Bar *<p>* should pop to 'table', not 'p'.
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1362
         <p>Foo<table><tr>Bar *<p>* should pop to 'tr', not 'p'.
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1363
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1364
         <li><ul><li> *<li>* should pop to 'ul', not the first 'li'.
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1365
         <tr><table><tr> *<tr>* should pop to 'table', not the first 'tr'
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1366
         <td><tr><td> *<td>* should pop to 'tr', not the first 'td'
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1367
        """
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1368
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1369
        nestingResetTriggers = self.NESTABLE_TAGS.get(name)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1370
        isNestable = nestingResetTriggers != None
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1371
        isResetNesting = self.RESET_NESTING_TAGS.has_key(name)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1372
        popTo = None
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1373
        inclusive = True
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1374
        for i in range(len(self.tagStack)-1, 0, -1):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1375
            p = self.tagStack[i]
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1376
            if (not p or p.name == name) and not isNestable:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1377
                #Non-nestable tags get popped to the top or to their
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1378
                #last occurance.
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1379
                popTo = name
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1380
                break
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1381
            if (nestingResetTriggers != None
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1382
                and p.name in nestingResetTriggers) \
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1383
                or (nestingResetTriggers == None and isResetNesting
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1384
                    and self.RESET_NESTING_TAGS.has_key(p.name)):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1385
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1386
                #If we encounter one of the nesting reset triggers
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1387
                #peculiar to this tag, or we encounter another tag
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1388
                #that causes nesting to reset, pop up to but not
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1389
                #including that tag.
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1390
                popTo = p.name
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1391
                inclusive = False
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1392
                break
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1393
            p = p.parent
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1394
        if popTo:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1395
            self._popToTag(popTo, inclusive)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1396
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1397
    def unknown_starttag(self, name, attrs, selfClosing=0):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1398
        #print "Start tag %s: %s" % (name, attrs)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1399
        if self.quoteStack:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1400
            #This is not a real tag.
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1401
            #print "<%s> is not real!" % name
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1402
            attrs = ''.join(map(lambda(x, y): ' %s="%s"' % (x, y), attrs))
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1403
            self.handle_data('<%s%s>' % (name, attrs))
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1404
            return
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1405
        self.endData()
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1406
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1407
        if not self.isSelfClosingTag(name) and not selfClosing:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1408
            self._smartPop(name)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1409
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1410
        if self.parseOnlyThese and len(self.tagStack) <= 1 \
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1411
               and (self.parseOnlyThese.text or not self.parseOnlyThese.searchTag(name, attrs)):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1412
            return
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1413
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1414
        tag = Tag(self, name, attrs, self.currentTag, self.previous)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1415
        if self.previous:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1416
            self.previous.next = tag
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1417
        self.previous = tag
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1418
        self.pushTag(tag)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1419
        if selfClosing or self.isSelfClosingTag(name):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1420
            self.popTag()
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1421
        if name in self.QUOTE_TAGS:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1422
            #print "Beginning quote (%s)" % name
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1423
            self.quoteStack.append(name)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1424
            self.literal = 1
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1425
        return tag
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1426
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1427
    def unknown_endtag(self, name):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1428
        #print "End tag %s" % name
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1429
        if self.quoteStack and self.quoteStack[-1] != name:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1430
            #This is not a real end tag.
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1431
            #print "</%s> is not real!" % name
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1432
            self.handle_data('</%s>' % name)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1433
            return
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1434
        self.endData()
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1435
        self._popToTag(name)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1436
        if self.quoteStack and self.quoteStack[-1] == name:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1437
            self.quoteStack.pop()
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1438
            self.literal = (len(self.quoteStack) > 0)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1439
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1440
    def handle_data(self, data):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1441
        self.currentData.append(data)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1442
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1443
    def extractCharsetFromMeta(self, attrs):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1444
        self.unknown_starttag('meta', attrs)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1445
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1446
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1447
class BeautifulSoup(BeautifulStoneSoup):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1448
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1449
    """This parser knows the following facts about HTML:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1450
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1451
    * Some tags have no closing tag and should be interpreted as being
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1452
      closed as soon as they are encountered.
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1453
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1454
    * The text inside some tags (ie. 'script') may contain tags which
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1455
      are not really part of the document and which should be parsed
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1456
      as text, not tags. If you want to parse the text as tags, you can
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1457
      always fetch it and parse it explicitly.
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1458
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1459
    * Tag nesting rules:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1460
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1461
      Most tags can't be nested at all. For instance, the occurance of
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1462
      a <p> tag should implicitly close the previous <p> tag.
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1463
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1464
       <p>Para1<p>Para2
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1465
        should be transformed into:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1466
       <p>Para1</p><p>Para2
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1467
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1468
      Some tags can be nested arbitrarily. For instance, the occurance
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1469
      of a <blockquote> tag should _not_ implicitly close the previous
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1470
      <blockquote> tag.
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1471
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1472
       Alice said: <blockquote>Bob said: <blockquote>Blah
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1473
        should NOT be transformed into:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1474
       Alice said: <blockquote>Bob said: </blockquote><blockquote>Blah
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1475
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1476
      Some tags can be nested, but the nesting is reset by the
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1477
      interposition of other tags. For instance, a <tr> tag should
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1478
      implicitly close the previous <tr> tag within the same <table>,
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1479
      but not close a <tr> tag in another table.
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1480
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1481
       <table><tr>Blah<tr>Blah
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1482
        should be transformed into:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1483
       <table><tr>Blah</tr><tr>Blah
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1484
        but,
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1485
       <tr>Blah<table><tr>Blah
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1486
        should NOT be transformed into
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1487
       <tr>Blah<table></tr><tr>Blah
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1488
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1489
    Differing assumptions about tag nesting rules are a major source
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1490
    of problems with the BeautifulSoup class. If BeautifulSoup is not
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1491
    treating as nestable a tag your page author treats as nestable,
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1492
    try ICantBelieveItsBeautifulSoup, MinimalSoup, or
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1493
    BeautifulStoneSoup before writing your own subclass."""
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1494
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1495
    def __init__(self, *args, **kwargs):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1496
        if not kwargs.has_key('smartQuotesTo'):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1497
            kwargs['smartQuotesTo'] = self.HTML_ENTITIES
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1498
        kwargs['isHTML'] = True
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1499
        BeautifulStoneSoup.__init__(self, *args, **kwargs)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1500
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1501
    SELF_CLOSING_TAGS = buildTagMap(None,
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1502
                                    ['br' , 'hr', 'input', 'img', 'meta',
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1503
                                    'spacer', 'link', 'frame', 'base'])
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1504
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1505
    PRESERVE_WHITESPACE_TAGS = set(['pre', 'textarea'])
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1506
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1507
    QUOTE_TAGS = {'script' : None, 'textarea' : None}
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1508
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1509
    #According to the HTML standard, each of these inline tags can
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1510
    #contain another tag of the same type. Furthermore, it's common
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1511
    #to actually use these tags this way.
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1512
    NESTABLE_INLINE_TAGS = ['span', 'font', 'q', 'object', 'bdo', 'sub', 'sup',
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1513
                            'center']
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1514
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1515
    #According to the HTML standard, these block tags can contain
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1516
    #another tag of the same type. Furthermore, it's common
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1517
    #to actually use these tags this way.
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1518
    NESTABLE_BLOCK_TAGS = ['blockquote', 'div', 'fieldset', 'ins', 'del']
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1519
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1520
    #Lists can contain other lists, but there are restrictions.
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1521
    NESTABLE_LIST_TAGS = { 'ol' : [],
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1522
                           'ul' : [],
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1523
                           'li' : ['ul', 'ol'],
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1524
                           'dl' : [],
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1525
                           'dd' : ['dl'],
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1526
                           'dt' : ['dl'] }
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1527
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1528
    #Tables can contain other tables, but there are restrictions.
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1529
    NESTABLE_TABLE_TAGS = {'table' : [],
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1530
                           'tr' : ['table', 'tbody', 'tfoot', 'thead'],
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1531
                           'td' : ['tr'],
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1532
                           'th' : ['tr'],
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1533
                           'thead' : ['table'],
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1534
                           'tbody' : ['table'],
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1535
                           'tfoot' : ['table'],
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1536
                           }
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1537
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1538
    NON_NESTABLE_BLOCK_TAGS = ['address', 'form', 'p', 'pre']
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1539
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1540
    #If one of these tags is encountered, all tags up to the next tag of
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1541
    #this type are popped.
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1542
    RESET_NESTING_TAGS = buildTagMap(None, NESTABLE_BLOCK_TAGS, 'noscript',
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1543
                                     NON_NESTABLE_BLOCK_TAGS,
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1544
                                     NESTABLE_LIST_TAGS,
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1545
                                     NESTABLE_TABLE_TAGS)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1546
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1547
    NESTABLE_TAGS = buildTagMap([], NESTABLE_INLINE_TAGS, NESTABLE_BLOCK_TAGS,
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1548
                                NESTABLE_LIST_TAGS, NESTABLE_TABLE_TAGS)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1549
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1550
    # Used to detect the charset in a META tag; see start_meta
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1551
    CHARSET_RE = re.compile("((^|;)\s*charset=)([^;]*)", re.M)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1552
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1553
    def extractCharsetFromMeta(self, attrs):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1554
        """Beautiful Soup can detect a charset included in a META tag,
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1555
        try to convert the document to that charset, and re-parse the
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1556
        document from the beginning."""
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1557
        httpEquiv = None
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1558
        contentType = None
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1559
        contentTypeIndex = None
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1560
        tagNeedsEncodingSubstitution = False
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1561
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1562
        for i in range(0, len(attrs)):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1563
            key, value = attrs[i]
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1564
            key = key.lower()
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1565
            if key == 'http-equiv':
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1566
                httpEquiv = value
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1567
            elif key == 'content':
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1568
                contentType = value
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1569
                contentTypeIndex = i
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1570
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1571
        if httpEquiv and contentType: # It's an interesting meta tag.
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1572
            match = self.CHARSET_RE.search(contentType)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1573
            if match:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1574
                if (self.declaredHTMLEncoding is not None or
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1575
                    self.originalEncoding == self.fromEncoding):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1576
                    # An HTML encoding was sniffed while converting
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1577
                    # the document to Unicode, or an HTML encoding was
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1578
                    # sniffed during a previous pass through the
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1579
                    # document, or an encoding was specified
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1580
                    # explicitly and it worked. Rewrite the meta tag.
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1581
                    def rewrite(match):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1582
                        return match.group(1) + "%SOUP-ENCODING%"
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1583
                    newAttr = self.CHARSET_RE.sub(rewrite, contentType)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1584
                    attrs[contentTypeIndex] = (attrs[contentTypeIndex][0],
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1585
                                               newAttr)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1586
                    tagNeedsEncodingSubstitution = True
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1587
                else:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1588
                    # This is our first pass through the document.
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1589
                    # Go through it again with the encoding information.
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1590
                    newCharset = match.group(3)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1591
                    if newCharset and newCharset != self.originalEncoding:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1592
                        self.declaredHTMLEncoding = newCharset
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1593
                        self._feed(self.declaredHTMLEncoding)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1594
                        raise StopParsing
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1595
                    pass
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1596
        tag = self.unknown_starttag("meta", attrs)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1597
        if tag and tagNeedsEncodingSubstitution:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1598
            tag.containsSubstitutions = True
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1599
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1600
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1601
class StopParsing(Exception):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1602
    pass
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1603
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1604
class ICantBelieveItsBeautifulSoup(BeautifulSoup):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1605
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1606
    """The BeautifulSoup class is oriented towards skipping over
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1607
    common HTML errors like unclosed tags. However, sometimes it makes
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1608
    errors of its own. For instance, consider this fragment:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1609
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1610
     <b>Foo<b>Bar</b></b>
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1611
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1612
    This is perfectly valid (if bizarre) HTML. However, the
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1613
    BeautifulSoup class will implicitly close the first b tag when it
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1614
    encounters the second 'b'. It will think the author wrote
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1615
    "<b>Foo<b>Bar", and didn't close the first 'b' tag, because
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1616
    there's no real-world reason to bold something that's already
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1617
    bold. When it encounters '</b></b>' it will close two more 'b'
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1618
    tags, for a grand total of three tags closed instead of two. This
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1619
    can throw off the rest of your document structure. The same is
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1620
    true of a number of other tags, listed below.
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1621
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1622
    It's much more common for someone to forget to close a 'b' tag
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1623
    than to actually use nested 'b' tags, and the BeautifulSoup class
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1624
    handles the common case. This class handles the not-co-common
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1625
    case: where you can't believe someone wrote what they did, but
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1626
    it's valid HTML and BeautifulSoup screwed up by assuming it
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1627
    wouldn't be."""
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1628
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1629
    I_CANT_BELIEVE_THEYRE_NESTABLE_INLINE_TAGS = \
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1630
     ['em', 'big', 'i', 'small', 'tt', 'abbr', 'acronym', 'strong',
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1631
      'cite', 'code', 'dfn', 'kbd', 'samp', 'strong', 'var', 'b',
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1632
      'big']
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1633
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1634
    I_CANT_BELIEVE_THEYRE_NESTABLE_BLOCK_TAGS = ['noscript']
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1635
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1636
    NESTABLE_TAGS = buildTagMap([], BeautifulSoup.NESTABLE_TAGS,
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1637
                                I_CANT_BELIEVE_THEYRE_NESTABLE_BLOCK_TAGS,
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1638
                                I_CANT_BELIEVE_THEYRE_NESTABLE_INLINE_TAGS)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1639
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1640
class MinimalSoup(BeautifulSoup):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1641
    """The MinimalSoup class is for parsing HTML that contains
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1642
    pathologically bad markup. It makes no assumptions about tag
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1643
    nesting, but it does know which tags are self-closing, that
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1644
    <script> tags contain Javascript and should not be parsed, that
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1645
    META tags may contain encoding information, and so on.
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1646
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1647
    This also makes it better for subclassing than BeautifulStoneSoup
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1648
    or BeautifulSoup."""
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1649
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1650
    RESET_NESTING_TAGS = buildTagMap('noscript')
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1651
    NESTABLE_TAGS = {}
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1652
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1653
class BeautifulSOAP(BeautifulStoneSoup):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1654
    """This class will push a tag with only a single string child into
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1655
    the tag's parent as an attribute. The attribute's name is the tag
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1656
    name, and the value is the string child. An example should give
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1657
    the flavor of the change:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1658
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1659
    <foo><bar>baz</bar></foo>
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1660
     =>
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1661
    <foo bar="baz"><bar>baz</bar></foo>
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1662
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1663
    You can then access fooTag['bar'] instead of fooTag.barTag.string.
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1664
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1665
    This is, of course, useful for scraping structures that tend to
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1666
    use subelements instead of attributes, such as SOAP messages. Note
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1667
    that it modifies its input, so don't print the modified version
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1668
    out.
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1669
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1670
    I'm not sure how many people really want to use this class; let me
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1671
    know if you do. Mainly I like the name."""
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1672
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1673
    def popTag(self):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1674
        if len(self.tagStack) > 1:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1675
            tag = self.tagStack[-1]
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1676
            parent = self.tagStack[-2]
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1677
            parent._getAttrMap()
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1678
            if (isinstance(tag, Tag) and len(tag.contents) == 1 and
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1679
                isinstance(tag.contents[0], NavigableString) and
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1680
                not parent.attrMap.has_key(tag.name)):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1681
                parent[tag.name] = tag.contents[0]
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1682
        BeautifulStoneSoup.popTag(self)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1683
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1684
#Enterprise class names! It has come to our attention that some people
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1685
#think the names of the Beautiful Soup parser classes are too silly
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1686
#and "unprofessional" for use in enterprise screen-scraping. We feel
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1687
#your pain! For such-minded folk, the Beautiful Soup Consortium And
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1688
#All-Night Kosher Bakery recommends renaming this file to
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1689
#"RobustParser.py" (or, in cases of extreme enterprisiness,
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1690
#"RobustParserBeanInterface.class") and using the following
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1691
#enterprise-friendly class aliases:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1692
class RobustXMLParser(BeautifulStoneSoup):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1693
    pass
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1694
class RobustHTMLParser(BeautifulSoup):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1695
    pass
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1696
class RobustWackAssHTMLParser(ICantBelieveItsBeautifulSoup):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1697
    pass
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1698
class RobustInsanelyWackAssHTMLParser(MinimalSoup):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1699
    pass
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1700
class SimplifyingSOAPParser(BeautifulSOAP):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1701
    pass
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1702
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1703
######################################################
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1704
#
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1705
# Bonus library: Unicode, Dammit
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1706
#
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1707
# This class forces XML data into a standard format (usually to UTF-8
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1708
# or Unicode).  It is heavily based on code from Mark Pilgrim's
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1709
# Universal Feed Parser. It does not rewrite the XML or HTML to
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1710
# reflect a new encoding: that happens in BeautifulStoneSoup.handle_pi
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1711
# (XML) and BeautifulSoup.start_meta (HTML).
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1712
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1713
# Autodetects character encodings.
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1714
# Download from http://chardet.feedparser.org/
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1715
try:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1716
    import chardet
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1717
#    import chardet.constants
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1718
#    chardet.constants._debug = 1
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1719
except ImportError:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1720
    chardet = None
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1721
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1722
# cjkcodecs and iconv_codec make Python know about more character encodings.
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1723
# Both are available from http://cjkpython.i18n.org/
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1724
# They're built in if you use Python 2.4.
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1725
try:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1726
    import cjkcodecs.aliases
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1727
except ImportError:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1728
    pass
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1729
try:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1730
    import iconv_codec
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1731
except ImportError:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1732
    pass
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1733
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1734
class UnicodeDammit:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1735
    """A class for detecting the encoding of a *ML document and
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1736
    converting it to a Unicode string. If the source encoding is
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1737
    windows-1252, can replace MS smart quotes with their HTML or XML
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1738
    equivalents."""
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1739
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1740
    # This dictionary maps commonly seen values for "charset" in HTML
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1741
    # meta tags to the corresponding Python codec names. It only covers
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1742
    # values that aren't in Python's aliases and can't be determined
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1743
    # by the heuristics in find_codec.
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1744
    CHARSET_ALIASES = { "macintosh" : "mac-roman",
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1745
                        "x-sjis" : "shift-jis" }
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1746
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1747
    def __init__(self, markup, overrideEncodings=[],
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1748
                 smartQuotesTo='xml', isHTML=False):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1749
        self.declaredHTMLEncoding = None
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1750
        self.markup, documentEncoding, sniffedEncoding = \
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1751
                     self._detectEncoding(markup, isHTML)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1752
        self.smartQuotesTo = smartQuotesTo
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1753
        self.triedEncodings = []
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1754
        if markup == '' or isinstance(markup, unicode):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1755
            self.originalEncoding = None
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1756
            self.unicode = unicode(markup)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1757
            return
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1758
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1759
        u = None
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1760
        for proposedEncoding in overrideEncodings:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1761
            u = self._convertFrom(proposedEncoding)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1762
            if u: break
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1763
        if not u:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1764
            for proposedEncoding in (documentEncoding, sniffedEncoding):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1765
                u = self._convertFrom(proposedEncoding)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1766
                if u: break
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1767
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1768
        # If no luck and we have auto-detection library, try that:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1769
        if not u and chardet and not isinstance(self.markup, unicode):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1770
            u = self._convertFrom(chardet.detect(self.markup)['encoding'])
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1771
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1772
        # As a last resort, try utf-8 and windows-1252:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1773
        if not u:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1774
            for proposed_encoding in ("utf-8", "windows-1252"):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1775
                u = self._convertFrom(proposed_encoding)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1776
                if u: break
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1777
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1778
        self.unicode = u
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1779
        if not u: self.originalEncoding = None
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1780
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1781
    def _subMSChar(self, match):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1782
        """Changes a MS smart quote character to an XML or HTML
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1783
        entity."""
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1784
        orig = match.group(1)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1785
        sub = self.MS_CHARS.get(orig)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1786
        if type(sub) == types.TupleType:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1787
            if self.smartQuotesTo == 'xml':
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1788
                sub = '&#x'.encode() + sub[1].encode() + ';'.encode()
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1789
            else:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1790
                sub = '&'.encode() + sub[0].encode() + ';'.encode()
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1791
        else:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1792
            sub = sub.encode()
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1793
        return sub
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1794
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1795
    def _convertFrom(self, proposed):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1796
        proposed = self.find_codec(proposed)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1797
        if not proposed or proposed in self.triedEncodings:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1798
            return None
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1799
        self.triedEncodings.append(proposed)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1800
        markup = self.markup
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1801
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1802
        # Convert smart quotes to HTML if coming from an encoding
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1803
        # that might have them.
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1804
        if self.smartQuotesTo and proposed.lower() in("windows-1252",
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1805
                                                      "iso-8859-1",
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1806
                                                      "iso-8859-2"):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1807
            smart_quotes_re = "([\x80-\x9f])"
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1808
            smart_quotes_compiled = re.compile(smart_quotes_re)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1809
            markup = smart_quotes_compiled.sub(self._subMSChar, markup)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1810
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1811
        try:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1812
            # print "Trying to convert document to %s" % proposed
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1813
            u = self._toUnicode(markup, proposed)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1814
            self.markup = u
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1815
            self.originalEncoding = proposed
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1816
        except Exception, e:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1817
            # print "That didn't work!"
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1818
            # print e
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1819
            return None
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1820
        #print "Correct encoding: %s" % proposed
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1821
        return self.markup
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1822
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1823
    def _toUnicode(self, data, encoding):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1824
        '''Given a string and its encoding, decodes the string into Unicode.
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1825
        %encoding is a string recognized by encodings.aliases'''
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1826
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1827
        # strip Byte Order Mark (if present)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1828
        if (len(data) >= 4) and (data[:2] == '\xfe\xff') \
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1829
               and (data[2:4] != '\x00\x00'):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1830
            encoding = 'utf-16be'
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1831
            data = data[2:]
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1832
        elif (len(data) >= 4) and (data[:2] == '\xff\xfe') \
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1833
                 and (data[2:4] != '\x00\x00'):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1834
            encoding = 'utf-16le'
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1835
            data = data[2:]
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1836
        elif data[:3] == '\xef\xbb\xbf':
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1837
            encoding = 'utf-8'
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1838
            data = data[3:]
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1839
        elif data[:4] == '\x00\x00\xfe\xff':
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1840
            encoding = 'utf-32be'
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1841
            data = data[4:]
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1842
        elif data[:4] == '\xff\xfe\x00\x00':
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1843
            encoding = 'utf-32le'
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1844
            data = data[4:]
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1845
        newdata = unicode(data, encoding)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1846
        return newdata
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1847
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1848
    def _detectEncoding(self, xml_data, isHTML=False):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1849
        """Given a document, tries to detect its XML encoding."""
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1850
        xml_encoding = sniffed_xml_encoding = None
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1851
        try:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1852
            if xml_data[:4] == '\x4c\x6f\xa7\x94':
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1853
                # EBCDIC
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1854
                xml_data = self._ebcdic_to_ascii(xml_data)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1855
            elif xml_data[:4] == '\x00\x3c\x00\x3f':
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1856
                # UTF-16BE
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1857
                sniffed_xml_encoding = 'utf-16be'
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1858
                xml_data = unicode(xml_data, 'utf-16be').encode('utf-8')
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1859
            elif (len(xml_data) >= 4) and (xml_data[:2] == '\xfe\xff') \
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1860
                     and (xml_data[2:4] != '\x00\x00'):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1861
                # UTF-16BE with BOM
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1862
                sniffed_xml_encoding = 'utf-16be'
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1863
                xml_data = unicode(xml_data[2:], 'utf-16be').encode('utf-8')
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1864
            elif xml_data[:4] == '\x3c\x00\x3f\x00':
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1865
                # UTF-16LE
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1866
                sniffed_xml_encoding = 'utf-16le'
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1867
                xml_data = unicode(xml_data, 'utf-16le').encode('utf-8')
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1868
            elif (len(xml_data) >= 4) and (xml_data[:2] == '\xff\xfe') and \
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1869
                     (xml_data[2:4] != '\x00\x00'):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1870
                # UTF-16LE with BOM
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1871
                sniffed_xml_encoding = 'utf-16le'
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1872
                xml_data = unicode(xml_data[2:], 'utf-16le').encode('utf-8')
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1873
            elif xml_data[:4] == '\x00\x00\x00\x3c':
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1874
                # UTF-32BE
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1875
                sniffed_xml_encoding = 'utf-32be'
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1876
                xml_data = unicode(xml_data, 'utf-32be').encode('utf-8')
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1877
            elif xml_data[:4] == '\x3c\x00\x00\x00':
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1878
                # UTF-32LE
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1879
                sniffed_xml_encoding = 'utf-32le'
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1880
                xml_data = unicode(xml_data, 'utf-32le').encode('utf-8')
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1881
            elif xml_data[:4] == '\x00\x00\xfe\xff':
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1882
                # UTF-32BE with BOM
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1883
                sniffed_xml_encoding = 'utf-32be'
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1884
                xml_data = unicode(xml_data[4:], 'utf-32be').encode('utf-8')
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1885
            elif xml_data[:4] == '\xff\xfe\x00\x00':
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1886
                # UTF-32LE with BOM
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1887
                sniffed_xml_encoding = 'utf-32le'
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1888
                xml_data = unicode(xml_data[4:], 'utf-32le').encode('utf-8')
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1889
            elif xml_data[:3] == '\xef\xbb\xbf':
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1890
                # UTF-8 with BOM
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1891
                sniffed_xml_encoding = 'utf-8'
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1892
                xml_data = unicode(xml_data[3:], 'utf-8').encode('utf-8')
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1893
            else:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1894
                sniffed_xml_encoding = 'ascii'
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1895
                pass
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1896
        except:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1897
            xml_encoding_match = None
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1898
        xml_encoding_re = '^<\?.*encoding=[\'"](.*?)[\'"].*\?>'.encode()
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1899
        xml_encoding_match = re.compile(xml_encoding_re).match(xml_data)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1900
        if not xml_encoding_match and isHTML:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1901
            meta_re = '<\s*meta[^>]+charset=([^>]*?)[;\'">]'.encode()
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1902
            regexp = re.compile(meta_re, re.I)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1903
            xml_encoding_match = regexp.search(xml_data)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1904
        if xml_encoding_match is not None:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1905
            xml_encoding = xml_encoding_match.groups()[0].decode(
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1906
                'ascii').lower()
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1907
            if isHTML:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1908
                self.declaredHTMLEncoding = xml_encoding
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1909
            if sniffed_xml_encoding and \
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1910
               (xml_encoding in ('iso-10646-ucs-2', 'ucs-2', 'csunicode',
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1911
                                 'iso-10646-ucs-4', 'ucs-4', 'csucs4',
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1912
                                 'utf-16', 'utf-32', 'utf_16', 'utf_32',
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1913
                                 'utf16', 'u16')):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1914
                xml_encoding = sniffed_xml_encoding
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1915
        return xml_data, xml_encoding, sniffed_xml_encoding
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1916
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1917
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1918
    def find_codec(self, charset):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1919
        return self._codec(self.CHARSET_ALIASES.get(charset, charset)) \
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1920
               or (charset and self._codec(charset.replace("-", ""))) \
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1921
               or (charset and self._codec(charset.replace("-", "_"))) \
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1922
               or charset
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1923
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1924
    def _codec(self, charset):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1925
        if not charset: return charset
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1926
        codec = None
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1927
        try:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1928
            codecs.lookup(charset)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1929
            codec = charset
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1930
        except (LookupError, ValueError):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1931
            pass
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1932
        return codec
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1933
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1934
    EBCDIC_TO_ASCII_MAP = None
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1935
    def _ebcdic_to_ascii(self, s):
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1936
        c = self.__class__
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1937
        if not c.EBCDIC_TO_ASCII_MAP:
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1938
            emap = (0,1,2,3,156,9,134,127,151,141,142,11,12,13,14,15,
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1939
                    16,17,18,19,157,133,8,135,24,25,146,143,28,29,30,31,
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1940
                    128,129,130,131,132,10,23,27,136,137,138,139,140,5,6,7,
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1941
                    144,145,22,147,148,149,150,4,152,153,154,155,20,21,158,26,
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1942
                    32,160,161,162,163,164,165,166,167,168,91,46,60,40,43,33,
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1943
                    38,169,170,171,172,173,174,175,176,177,93,36,42,41,59,94,
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1944
                    45,47,178,179,180,181,182,183,184,185,124,44,37,95,62,63,
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1945
                    186,187,188,189,190,191,192,193,194,96,58,35,64,39,61,34,
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1946
                    195,97,98,99,100,101,102,103,104,105,196,197,198,199,200,
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1947
                    201,202,106,107,108,109,110,111,112,113,114,203,204,205,
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1948
                    206,207,208,209,126,115,116,117,118,119,120,121,122,210,
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1949
                    211,212,213,214,215,216,217,218,219,220,221,222,223,224,
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1950
                    225,226,227,228,229,230,231,123,65,66,67,68,69,70,71,72,
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1951
                    73,232,233,234,235,236,237,125,74,75,76,77,78,79,80,81,
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1952
                    82,238,239,240,241,242,243,92,159,83,84,85,86,87,88,89,
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1953
                    90,244,245,246,247,248,249,48,49,50,51,52,53,54,55,56,57,
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1954
                    250,251,252,253,254,255)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1955
            import string
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1956
            c.EBCDIC_TO_ASCII_MAP = string.maketrans( \
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1957
            ''.join(map(chr, range(256))), ''.join(map(chr, emap)))
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1958
        return s.translate(c.EBCDIC_TO_ASCII_MAP)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1959
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1960
    MS_CHARS = { '\x80' : ('euro', '20AC'),
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1961
                 '\x81' : ' ',
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1962
                 '\x82' : ('sbquo', '201A'),
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1963
                 '\x83' : ('fnof', '192'),
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1964
                 '\x84' : ('bdquo', '201E'),
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1965
                 '\x85' : ('hellip', '2026'),
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1966
                 '\x86' : ('dagger', '2020'),
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1967
                 '\x87' : ('Dagger', '2021'),
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1968
                 '\x88' : ('circ', '2C6'),
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1969
                 '\x89' : ('permil', '2030'),
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1970
                 '\x8A' : ('Scaron', '160'),
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1971
                 '\x8B' : ('lsaquo', '2039'),
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1972
                 '\x8C' : ('OElig', '152'),
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1973
                 '\x8D' : '?',
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1974
                 '\x8E' : ('#x17D', '17D'),
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1975
                 '\x8F' : '?',
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1976
                 '\x90' : '?',
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1977
                 '\x91' : ('lsquo', '2018'),
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1978
                 '\x92' : ('rsquo', '2019'),
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1979
                 '\x93' : ('ldquo', '201C'),
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1980
                 '\x94' : ('rdquo', '201D'),
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1981
                 '\x95' : ('bull', '2022'),
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1982
                 '\x96' : ('ndash', '2013'),
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1983
                 '\x97' : ('mdash', '2014'),
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1984
                 '\x98' : ('tilde', '2DC'),
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1985
                 '\x99' : ('trade', '2122'),
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1986
                 '\x9a' : ('scaron', '161'),
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1987
                 '\x9b' : ('rsaquo', '203A'),
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1988
                 '\x9c' : ('oelig', '153'),
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1989
                 '\x9d' : '?',
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1990
                 '\x9e' : ('#x17E', '17E'),
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1991
                 '\x9f' : ('Yuml', ''),}
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1992
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1993
#######################################################################
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1994
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1995
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1996
#By default, act as an HTML pretty-printer.
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1997
if __name__ == '__main__':
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1998
    import sys
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  1999
    soup = BeautifulSoup(sys.stdin)
d2f4d301e581 Cleanup
Sebastian Brannstrom <sebastianb@symbian.org>
parents:
diff changeset
  2000
    print soup.prettify()