source: exist/trunk/python/elementtree-1.3a6-20070220-badc/elementtree/ElementIron.py @ 3578

Subversion URL: http://proj.badc.rl.ac.uk/svn/ndg/exist/trunk/python/elementtree-1.3a6-20070220-badc/elementtree/ElementIron.py@3578
Revision 3578, 6.9 KB checked in by pjkersha, 11 years ago (diff)

Latest releases from Fredrik Lundh. 10 March release has exclusive C14N support with namespace prefixes.

Line 
1#
2# ElementTree
3# $Id: ElementIron.py 3375 2008-02-13 08:05:08Z fredrik $
4#
5# an ElementTree driver for IronPython.
6#
7# Copyright (c) 2006 by Fredrik Lundh.  All rights reserved.
8#
9# fredrik@pythonware.com
10# http://www.pythonware.com
11#
12# --------------------------------------------------------------------
13# The ElementTree toolkit is
14#
15# Copyright (c) 1999-2008 by Fredrik Lundh
16#
17# By obtaining, using, and/or copying this software and/or its
18# associated documentation, you agree that you have read, understood,
19# and will comply with the following terms and conditions:
20#
21# Permission to use, copy, modify, and distribute this software and
22# its associated documentation for any purpose and without fee is
23# hereby granted, provided that the above copyright notice appears in
24# all copies, and that both that copyright notice and this permission
25# notice appear in supporting documentation, and that the name of
26# Secret Labs AB or the author not be used in advertising or publicity
27# pertaining to distribution of the software without specific, written
28# prior permission.
29#
30# SECRET LABS AB AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
31# TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANT-
32# ABILITY AND FITNESS.  IN NO EVENT SHALL SECRET LABS AB OR THE AUTHOR
33# BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
34# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
35# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
36# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
37# OF THIS SOFTWARE.
38# --------------------------------------------------------------------
39
40import clr
41clr.AddReference("System.Xml")
42
43from System.IO import StringReader, TextReader
44from System.Xml import XmlReader, XmlNodeType
45
46# node types/categories
47START = XmlNodeType.Element
48DATA_TEXT = XmlNodeType.Text
49DATA_CDATA = XmlNodeType.CDATA
50DATA_SPACE = XmlNodeType.Whitespace
51END = XmlNodeType.EndElement
52
53def _ironparse(source):
54
55    # internal event generator.  takes a TextReader subclass, a file-
56    # like object, or a filename, and generates an event stream.  use
57    # the parse() and iterparse() adapters to access this from user-
58    # code.
59
60    if isinstance(source, TextReader):
61        pass # use as is
62    elif hasattr(source, "read"):
63        # FIXME: implement TextReader wrapper for Python I/O objects
64        source = StringReader(source.read())
65
66    # FIXME: handle settings here? (disable comments, etc)
67
68    reader = XmlReader.Create(source)
69
70    # tag cache
71    tags = {}
72    namespaces = []
73
74    def gettag():
75        key = reader.NamespaceURI, reader.LocalName
76        try:
77            tag = tags[key]
78        except KeyError:
79            if key[0]:
80                tag = "{%s}%s" % key
81            else:
82                tag = key[1]
83            tags[key] = tag
84        return tag
85
86    while reader.Read():
87        node = reader.NodeType
88        if node == START:
89            tag = gettag()
90            attrib = {}
91            ns = 0 # count namespace declarations
92            while reader.MoveToNextAttribute():
93                if reader.LocalName == "xmlns":
94                    ns += 1 # default namespace
95                    yield "start-ns", ("", reader.Value)
96                elif reader.Prefix == "xmlns":
97                    ns += 1 # prefixed namespace
98                    yield "start-ns", (reader.LocalName, reader.Value)
99                else:
100                    attrib[gettag()] = reader.Value
101            namespaces.append(ns)
102            reader.MoveToElement()
103            yield "start", tag, attrib
104            if reader.IsEmptyElement:
105                yield "end", tag
106                for i in xrange(namespaces.pop()):
107                    yield "end-ns", None
108        elif node == END:
109            yield "end", tags[reader.NamespaceURI, reader.LocalName]
110            for i in xrange(namespaces.pop()):
111                yield "end-ns", None
112        elif node == DATA_TEXT or node == DATA_SPACE or node == DATA_CDATA:
113            yield "data", reader.Value
114        else:
115            pass # yield "unknown", node
116    reader.Close()
117
118class _iterparse:
119
120    # iterparse generator.  we could use a generator method for this,
121    # but we need to expose a custom attribute as well, and generators
122    # cannot have arbitrary attributes
123
124    def __init__(self, source, target, events):
125        self.root = None
126        self.source = source
127        self.target = target
128        self.events = events
129    def __iter__(self):
130        source = self.source
131        target = self.target
132        events = self.events
133        if not events:
134            events = ["end"]
135        start = end = start_ns = end_ns = None
136        for event in events:
137            # use the passed-in objects as event codes
138            if event == "start":
139                start = event
140            elif event == "end":
141                end = event
142            elif event == "start-ns":
143                start_ns = event
144            elif event == "end-ns":
145                end_ns = event
146        for event in _ironparse(source):
147            code = event[0]
148            if code == "start":
149                elem = target.start(event[1], event[2])
150                if start:
151                    yield start, elem
152            elif code == "end":
153                elem = target.end(event[1])
154                if end:
155                    yield end, elem
156            elif code == "data":
157                target.data(event[1])
158            elif code == "start-ns":
159                if start_ns:
160                    yield start_ns, event[1]
161            elif code == "end-ns":
162                if end_ns:
163                    yield end_ns, event[1]
164        self.root = target.close()
165
166class ParserAPI(object):
167
168    def __init__(self, target_factory):
169        self.target_factory = target_factory
170
171    def parse(self, source):
172        target = self.target_factory()
173        for event in _ironparse(source):
174            code = event[0]
175            if code == "start":
176                target.start(event[1], event[2])
177            elif code == "end":
178                target.end(event[1])
179            elif code == "data":
180                target.data(event[1])
181        return target.close()
182
183    def iterparse(self, source, events=None):
184        target = self.target_factory()
185        return _iterparse(source, target, events)
186
187    def fromstring(self, source):
188        return self.parse(StringReader(source))
189
190# --------------------------------------------------------------------
191# helpers
192
193def parse(source):
194    from ElementTree import ElementTree, TreeBuilder
195    api = ParserAPI(TreeBuilder)
196    return ElementTree(api.parse(source))
197
198def iterparse(source, events=None):
199    from ElementTree import ElementTree, TreeBuilder
200    api = ParserAPI(TreeBuilder)
201    return ElementTree(api.iterparse(source, events))
Note: See TracBrowser for help on using the repository browser.