~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to elementtree/ElementTree.py

  • Committer: Martin Pool
  • Date: 2005-05-11 01:09:41 UTC
  • Revision ID: mbp@sourcefrog.net-20050511010941-6438198e54086ddb
todo

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
#
2
2
# ElementTree
3
 
# $Id: ElementTree.py 1862 2004-06-18 07:31:02Z Fredrik $
 
3
# $Id: ElementTree.py 2326 2005-03-17 07:45:21Z fredrik $
4
4
#
5
5
# light-weight XML support for Python 1.5.2 and later.
6
6
#
7
 
# this is a stripped-down version of Secret Labs' effDOM library (part
8
 
# of xmlToolkit).  compared to effDOM, this implementation has:
9
 
#
10
 
# - no support for observers
11
 
# - no html-specific extensions (e.g. entity preload)
12
 
# - no custom entities, doctypes, etc
13
 
# - no accelerator module
14
 
#
15
7
# history:
16
8
# 2001-10-20 fl   created (from various sources)
17
9
# 2001-11-01 fl   return root from parse method
38
30
# 2004-03-28 fl   added XMLID helper
39
31
# 2004-06-02 fl   added default support to findtext
40
32
# 2004-06-08 fl   fixed encoding of non-ascii element/attribute names
 
33
# 2004-08-23 fl   take advantage of post-2.1 expat features
 
34
# 2005-02-01 fl   added iterparse implementation
 
35
# 2005-03-02 fl   fixed iterparse support for pre-2.2 versions
41
36
#
42
 
# Copyright (c) 1999-2004 by Fredrik Lundh.  All rights reserved.
 
37
# Copyright (c) 1999-2005 by Fredrik Lundh.  All rights reserved.
43
38
#
44
39
# fredrik@pythonware.com
45
40
# http://www.pythonware.com
47
42
# --------------------------------------------------------------------
48
43
# The ElementTree toolkit is
49
44
#
50
 
# Copyright (c) 1999-2004 by Fredrik Lundh
 
45
# Copyright (c) 1999-2005 by Fredrik Lundh
51
46
#
52
47
# By obtaining, using, and/or copying this software and/or its
53
48
# associated documentation, you agree that you have read, understood,
78
73
    "dump",
79
74
    "Element", "ElementTree",
80
75
    "fromstring",
81
 
    "iselement",
 
76
    "iselement", "iterparse",
82
77
    "parse",
83
78
    "PI", "ProcessingInstruction",
84
79
    "QName",
143
138
# TODO: add support for custom namespace resolvers/default namespaces
144
139
# TODO: add improved support for incremental parsing
145
140
 
146
 
VERSION = "1.2"
 
141
VERSION = "1.2.6"
147
142
 
148
143
##
149
144
# Internal element class.  This class defines the Element interface,
701
696
                for k, v in xmlns_items:
702
697
                    file.write(" %s=\"%s\"" % (_encode(k, encoding),
703
698
                                               _escape_attrib(v, encoding)))
704
 
            if node.text or node:
 
699
            if node.text or len(node):
705
700
                file.write(">")
706
701
                if node.text:
707
702
                    file.write(_escape_cdata(node.text, encoding))
865
860
    return tree
866
861
 
867
862
##
 
863
# Parses an XML document into an element tree incrementally, and reports
 
864
# what's going on to the user.
 
865
#
 
866
# @param source A filename or file object containing XML data.
 
867
# @param events A list of events to report back.  If omitted, only "end"
 
868
#     events are reported.
 
869
# @return A (event, elem) iterator.
 
870
 
 
871
class iterparse:
 
872
 
 
873
    def __init__(self, source, events=None):
 
874
        if not hasattr(source, "read"):
 
875
            source = open(source, "rb")
 
876
        self._file = source
 
877
        self._events = []
 
878
        self._index = 0
 
879
        self.root = self._root = None
 
880
        self._parser = XMLTreeBuilder()
 
881
        # wire up the parser for event reporting
 
882
        parser = self._parser._parser
 
883
        append = self._events.append
 
884
        if events is None:
 
885
            events = ["end"]
 
886
        for event in events:
 
887
            if event == "start":
 
888
                try:
 
889
                    parser.ordered_attributes = 1
 
890
                    parser.specified_attributes = 1
 
891
                    def handler(tag, attrib_in, event=event, append=append,
 
892
                                start=self._parser._start_list):
 
893
                        append((event, start(tag, attrib_in)))
 
894
                    parser.StartElementHandler = handler
 
895
                except AttributeError:
 
896
                    def handler(tag, attrib_in, event=event, append=append,
 
897
                                start=self._parser._start):
 
898
                        append((event, start(tag, attrib_in)))
 
899
                    parser.StartElementHandler = handler
 
900
            elif event == "end":
 
901
                def handler(tag, event=event, append=append,
 
902
                            end=self._parser._end):
 
903
                    append((event, end(tag)))
 
904
                parser.EndElementHandler = handler
 
905
            elif event == "start-ns":
 
906
                def handler(prefix, uri, event=event, append=append):
 
907
                    try:
 
908
                        uri = _encode(uri, "ascii")
 
909
                    except UnicodeError:
 
910
                        pass
 
911
                    append((event, (prefix or "", uri)))
 
912
                parser.StartNamespaceDeclHandler = handler
 
913
            elif event == "end-ns":
 
914
                def handler(prefix, event=event, append=append):
 
915
                    append((event, None))
 
916
                parser.EndNamespaceDeclHandler = handler
 
917
 
 
918
    def next(self):
 
919
        while 1:
 
920
            try:
 
921
                item = self._events[self._index]
 
922
            except IndexError:
 
923
                if self._parser is None:
 
924
                    self.root = self._root
 
925
                    try:
 
926
                        raise StopIteration
 
927
                    except NameError:
 
928
                        raise IndexError
 
929
                # load event buffer
 
930
                del self._events[:]
 
931
                self._index = 0
 
932
                data = self._file.read(16384)
 
933
                if data:
 
934
                    self._parser.feed(data)
 
935
                else:
 
936
                    self._root = self._parser.close()
 
937
                    self._parser = None
 
938
            else:
 
939
                self._index = self._index + 1
 
940
                return item
 
941
 
 
942
    try:
 
943
        iter
 
944
        def __iter__(self):
 
945
            return self
 
946
    except NameError:
 
947
        def __getitem__(self, index):
 
948
            return self.next()
 
949
 
 
950
##
868
951
# Parses an XML document from a string constant.  This function can
869
952
# be used to embed "XML literals" in Python code.
870
953
#
1025
1108
class XMLTreeBuilder:
1026
1109
 
1027
1110
    def __init__(self, html=0, target=None):
1028
 
        from xml.parsers import expat
 
1111
        try:
 
1112
            from xml.parsers import expat
 
1113
        except ImportError:
 
1114
            raise ImportError(
 
1115
                "No module named expat; use SimpleXMLTreeBuilder instead"
 
1116
                )
1029
1117
        self._parser = parser = expat.ParserCreate(None, "}")
1030
1118
        if target is None:
1031
1119
            target = TreeBuilder()
1032
1120
        self._target = target
1033
1121
        self._names = {} # name memo cache
1034
 
        parser.DefaultHandler = self._default
 
1122
        # callbacks
 
1123
        parser.DefaultHandlerExpand = self._default
1035
1124
        parser.StartElementHandler = self._start
1036
1125
        parser.EndElementHandler = self._end
1037
1126
        parser.CharacterDataHandler = self._data
 
1127
        # let expat do the buffering, if supported
 
1128
        try:
 
1129
            self._parser.buffer_text = 1
 
1130
        except AttributeError:
 
1131
            pass
 
1132
        # use new-style attribute handling, if supported
 
1133
        try:
 
1134
            self._parser.ordered_attributes = 1
 
1135
            self._parser.specified_attributes = 1
 
1136
            parser.StartElementHandler = self._start_list
 
1137
        except AttributeError:
 
1138
            pass
1038
1139
        encoding = None
1039
1140
        if not parser.returns_unicode:
1040
1141
            encoding = "utf-8"
1045
1146
    def _fixtext(self, text):
1046
1147
        # convert text string to ascii, if possible
1047
1148
        try:
1048
 
            return str(text) # what if the default encoding is changed?
 
1149
            return _encode(text, "ascii")
1049
1150
        except UnicodeError:
1050
1151
            return text
1051
1152
 
1068
1169
            attrib[fixname(key)] = self._fixtext(value)
1069
1170
        return self._target.start(tag, attrib)
1070
1171
 
 
1172
    def _start_list(self, tag, attrib_in):
 
1173
        fixname = self._fixname
 
1174
        tag = fixname(tag)
 
1175
        attrib = {}
 
1176
        if attrib_in:
 
1177
            for i in range(0, len(attrib_in), 2):
 
1178
                attrib[fixname(attrib_in[i])] = self._fixtext(attrib_in[i+1])
 
1179
        return self._target.start(tag, attrib)
 
1180
 
1071
1181
    def _data(self, text):
1072
1182
        return self._target.data(self._fixtext(text))
1073
1183