Salome HOME
Artifact 8885 : add traces to find the log problems when testing
[tools/sat.git] / src / ElementTree.py
1 #
2 # ElementTree
3 # $Id: ElementTree.py 2326 2005-03-17 07:45:21Z fredrik $
4 #
5 # light-weight XML support for Python 1.5.2 and later.
6 #
7 # history:
8 # 2001-10-20 fl   created (from various sources)
9 # 2001-11-01 fl   return root from parse method
10 # 2002-02-16 fl   sort attributes in lexical order
11 # 2002-04-06 fl   TreeBuilder refactoring, added PythonDoc markup
12 # 2002-05-01 fl   finished TreeBuilder refactoring
13 # 2002-07-14 fl   added basic namespace support to ElementTree.write
14 # 2002-07-25 fl   added QName attribute support
15 # 2002-10-20 fl   fixed encoding in write
16 # 2002-11-24 fl   changed default encoding to ascii; fixed attribute encoding
17 # 2002-11-27 fl   accept file objects or file names for parse/write
18 # 2002-12-04 fl   moved XMLTreeBuilder back to this module
19 # 2003-01-11 fl   fixed entity encoding glitch for us-ascii
20 # 2003-02-13 fl   added XML literal factory
21 # 2003-02-21 fl   added ProcessingInstruction/PI factory
22 # 2003-05-11 fl   added tostring/fromstring helpers
23 # 2003-05-26 fl   added ElementPath support
24 # 2003-07-05 fl   added makeelement factory method
25 # 2003-07-28 fl   added more well-known namespace prefixes
26 # 2003-08-15 fl   fixed typo in ElementTree.findtext (Thomas Dartsch)
27 # 2003-09-04 fl   fall back on emulator if ElementPath is not installed
28 # 2003-10-31 fl   markup updates
29 # 2003-11-15 fl   fixed nested namespace bug
30 # 2004-03-28 fl   added XMLID helper
31 # 2004-06-02 fl   added default support to findtext
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
36 #
37 # Copyright (c) 1999-2005 by Fredrik Lundh.  All rights reserved.
38 #
39 # fredrik@pythonware.com
40 # http://www.pythonware.com
41 #
42 # --------------------------------------------------------------------
43 # The ElementTree toolkit is
44 #
45 # Copyright (c) 1999-2005 by Fredrik Lundh
46 #
47 # By obtaining, using, and/or copying this software and/or its
48 # associated documentation, you agree that you have read, understood,
49 # and will comply with the following terms and conditions:
50 #
51 # Permission to use, copy, modify, and distribute this software and
52 # its associated documentation for any purpose and without fee is
53 # hereby granted, provided that the above copyright notice appears in
54 # all copies, and that both that copyright notice and this permission
55 # notice appear in supporting documentation, and that the name of
56 # Secret Labs AB or the author not be used in advertising or publicity
57 # pertaining to distribution of the software without specific, written
58 # prior permission.
59 #
60 # SECRET LABS AB AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
61 # TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANT-
62 # ABILITY AND FITNESS.  IN NO EVENT SHALL SECRET LABS AB OR THE AUTHOR
63 # BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
64 # DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
65 # WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
66 # ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
67 # OF THIS SOFTWARE.
68 # --------------------------------------------------------------------
69
70 __all__ = [
71     # public symbols
72     "Comment",
73     "dump",
74     "Element", "ElementTree",
75     "fromstring",
76     "iselement", "iterparse",
77     "parse",
78     "PI", "ProcessingInstruction",
79     "QName",
80     "SubElement",
81     "tostring",
82     "TreeBuilder",
83     "VERSION", "XML",
84     "XMLTreeBuilder",
85     ]
86
87 ##
88 # The <b>Element</b> type is a flexible container object, designed to
89 # store hierarchical data structures in memory. The type can be
90 # described as a cross between a list and a dictionary.
91 # <p>
92 # Each element has a number of properties associated with it:
93 # <ul>
94 # <li>a <i>tag</i>. This is a string identifying what kind of data
95 # this element represents (the element type, in other words).</li>
96 # <li>a number of <i>attributes</i>, stored in a Python dictionary.</li>
97 # <li>a <i>text</i> string.</li>
98 # <li>an optional <i>tail</i> string.</li>
99 # <li>a number of <i>child elements</i>, stored in a Python sequence</li>
100 # </ul>
101 #
102 # To create an element instance, use the {@link #Element} or {@link
103 # #SubElement} factory functions.
104 # <p>
105 # The {@link #ElementTree} class can be used to wrap an element
106 # structure, and convert it from and to XML.
107 ##
108
109 import string, sys, re, platform
110
111 class _SimpleElementPath:
112     # emulate pre-1.2 find/findtext/findall behaviour
113     def find(self, element, tag):
114         for elem in element:
115             if elem.tag == tag:
116                 return elem
117         return None
118     def findtext(self, element, tag, default=None):
119         for elem in element:
120             if elem.tag == tag:
121                 return elem.text or ""
122         return default
123     def findall(self, element, tag):
124         if tag[:3] == ".//":
125             return element.getiterator(tag[3:])
126         result = []
127         for elem in element:
128             if elem.tag == tag:
129                 result.append(elem)
130         return result
131
132 try:
133     import ElementPath
134 except ImportError:
135     # FIXME: issue warning in this case?
136     ElementPath = _SimpleElementPath()
137
138 # TODO: add support for custom namespace resolvers/default namespaces
139 # TODO: add improved support for incremental parsing
140
141 VERSION = "1.2.6"
142
143 ##
144 # Internal element class.  This class defines the Element interface,
145 # and provides a reference implementation of this interface.
146 # <p>
147 # You should not create instances of this class directly.  Use the
148 # appropriate factory functions instead, such as {@link #Element}
149 # and {@link #SubElement}.
150 #
151 # @see Element
152 # @see SubElement
153 # @see Comment
154 # @see ProcessingInstruction
155
156 class _ElementInterface:
157     # <tag attrib>text<child/>...</tag>tail
158
159     ##
160     # (Attribute) Element tag.
161
162     tag = None
163
164     ##
165     # (Attribute) Element attribute dictionary.  Where possible, use
166     # {@link #_ElementInterface.get},
167     # {@link #_ElementInterface.set},
168     # {@link #_ElementInterface.keys}, and
169     # {@link #_ElementInterface.items} to access
170     # element attributes.
171
172     attrib = None
173
174     ##
175     # (Attribute) Text before first subelement.  This is either a
176     # string or the value None, if there was no text.
177
178     text = None
179
180     ##
181     # (Attribute) Text after this element's end tag, but before the
182     # next sibling element's start tag.  This is either a string or
183     # the value None, if there was no text.
184
185     tail = None # text after end tag, if any
186
187     def __init__(self, tag, attrib):
188         self.tag = tag
189         self.attrib = attrib
190         self._children = []
191
192     def __repr__(self):
193         return "<Element %s at %x>" % (self.tag, id(self))
194
195     ##
196     # Creates a new element object of the same type as this element.
197     #
198     # @param tag Element tag.
199     # @param attrib Element attributes, given as a dictionary.
200     # @return A new element instance.
201
202     def makeelement(self, tag, attrib):
203         return Element(tag, attrib)
204
205     ##
206     # Returns the number of subelements.
207     #
208     # @return The number of subelements.
209
210     def __len__(self):
211         return len(self._children)
212
213     ##
214     # Returns the given subelement.
215     #
216     # @param index What subelement to return.
217     # @return The given subelement.
218     # @exception IndexError If the given element does not exist.
219
220     def __getitem__(self, index):
221         return self._children[index]
222
223     ##
224     # Replaces the given subelement.
225     #
226     # @param index What subelement to replace.
227     # @param element The new element value.
228     # @exception IndexError If the given element does not exist.
229     # @exception AssertionError If element is not a valid object.
230
231     def __setitem__(self, index, element):
232         assert iselement(element)
233         self._children[index] = element
234
235     ##
236     # Deletes the given subelement.
237     #
238     # @param index What subelement to delete.
239     # @exception IndexError If the given element does not exist.
240
241     def __delitem__(self, index):
242         del self._children[index]
243
244     ##
245     # Returns a list containing subelements in the given range.
246     #
247     # @param start The first subelement to return.
248     # @param stop The first subelement that shouldn't be returned.
249     # @return A sequence object containing subelements.
250
251     def __getslice__(self, start, stop):
252         return self._children[start:stop]
253
254     ##
255     # Replaces a number of subelements with elements from a sequence.
256     #
257     # @param start The first subelement to replace.
258     # @param stop The first subelement that shouldn't be replaced.
259     # @param elements A sequence object with zero or more elements.
260     # @exception AssertionError If a sequence member is not a valid object.
261
262     def __setslice__(self, start, stop, elements):
263         for element in elements:
264             assert iselement(element)
265         self._children[start:stop] = list(elements)
266
267     ##
268     # Deletes a number of subelements.
269     #
270     # @param start The first subelement to delete.
271     # @param stop The first subelement to leave in there.
272
273     def __delslice__(self, start, stop):
274         del self._children[start:stop]
275
276     ##
277     # Adds a subelement to the end of this element.
278     #
279     # @param element The element to add.
280     # @exception AssertionError If a sequence member is not a valid object.
281
282     def append(self, element):
283         assert iselement(element)
284         self._children.append(element)
285
286     ##
287     # Inserts a subelement at the given position in this element.
288     #
289     # @param index Where to insert the new subelement.
290     # @exception AssertionError If the element is not a valid object.
291
292     def insert(self, index, element):
293         assert iselement(element)
294         self._children.insert(index, element)
295
296     ##
297     # Removes a matching subelement.  Unlike the <b>find</b> methods,
298     # this method compares elements based on identity, not on tag
299     # value or contents.
300     #
301     # @param element What element to remove.
302     # @exception ValueError If a matching element could not be found.
303     # @exception AssertionError If the element is not a valid object.
304
305     def remove(self, element):
306         assert iselement(element)
307         self._children.remove(element)
308
309     ##
310     # Returns all subelements.  The elements are returned in document
311     # order.
312     #
313     # @return A list of subelements.
314     # @defreturn list of Element instances
315
316     def getchildren(self):
317         return self._children
318
319     ##
320     # Finds the first matching subelement, by tag name or path.
321     #
322     # @param path What element to look for.
323     # @return The first matching element, or None if no element was found.
324     # @defreturn Element or None
325
326     def find(self, path):
327         if ElementPath.find(self, path) == None:
328             return ElementPath.find(self, path.encode())
329         return ElementPath.find(self, path)
330
331     ##
332     # Finds text for the first matching subelement, by tag name or path.
333     #
334     # @param path What element to look for.
335     # @param default What to return if the element was not found.
336     # @return The text content of the first matching element, or the
337     #     default value no element was found.  Note that if the element
338     #     has is found, but has no text content, this method returns an
339     #     empty string.
340     # @defreturn string
341
342     def findtext(self, path, default=None):
343         return ElementPath.findtext(self, path, default)
344
345     ##
346     # Finds all matching subelements, by tag name or path.
347     #
348     # @param path What element to look for.
349     # @return A list or iterator containing all matching elements,
350     #    in document order.
351     # @defreturn list of Element instances
352
353     def findall(self, path):
354         return ElementPath.findall(self, path)
355
356     ##
357     # Resets an element.  This function removes all subelements, clears
358     # all attributes, and sets the text and tail attributes to None.
359
360     def clear(self):
361         self.attrib.clear()
362         self._children = []
363         self.text = self.tail = None
364
365     ##
366     # Gets an element attribute.
367     #
368     # @param key What attribute to look for.
369     # @param default What to return if the attribute was not found.
370     # @return The attribute value, or the default value, if the
371     #     attribute was not found.
372     # @defreturn string or None
373
374     def get(self, key, default=None):
375         res = self.attrib.get(key, default)
376         if not res:
377             res = self.attrib.get(key.encode(), default)
378         if isinstance(res, bytes):
379             return res.decode()
380         else:
381             return res
382
383     ##
384     # Sets an element attribute.
385     #
386     # @param key What attribute to set.
387     # @param value The attribute value.
388
389     def set(self, key, value):
390         self.attrib[key] = value
391
392     ##
393     # Gets a list of attribute names.  The names are returned in an
394     # arbitrary order (just like for an ordinary Python dictionary).
395     #
396     # @return A list of element attribute names.
397     # @defreturn list of strings
398
399     def keys(self):
400         res = []
401         for key in self.attrib.keys():
402             if isinstance(key, bytes):
403                 res.append(key.decode())
404             else:
405                 res.append(key)
406         return res
407                 
408     ##
409     # Gets element attributes, as a sequence.  The attributes are
410     # returned in an arbitrary order.
411     #
412     # @return A list of (name, value) tuples for all attributes.
413     # @defreturn list of (string, string) tuples
414
415     def items(self):
416         return self.attrib.items()
417
418     ##
419     # Creates a tree iterator.  The iterator loops over this element
420     # and all subelements, in document order, and returns all elements
421     # with a matching tag.
422     # <p>
423     # If the tree structure is modified during iteration, the result
424     # is undefined.
425     #
426     # @param tag What tags to look for (default is to return all elements).
427     # @return A list or iterator containing all the matching elements.
428     # @defreturn list or iterator
429
430     def getiterator(self, tag=None):
431         nodes = []
432         if tag == "*":
433             tag = None
434         if tag is None or self.tag == tag:
435             nodes.append(self)
436         for node in self._children:
437             nodes.extend(node.getiterator(tag))
438         return nodes
439
440 # compatibility
441 _Element = _ElementInterface
442
443 ##
444 # Element factory.  This function returns an object implementing the
445 # standard Element interface.  The exact class or type of that object
446 # is implementation dependent, but it will always be compatible with
447 # the {@link #_ElementInterface} class in this module.
448 # <p>
449 # The element name, attribute names, and attribute values can be
450 # either 8-bit ASCII strings or Unicode strings.
451 #
452 # @param tag The element name.
453 # @param attrib An optional dictionary, containing element attributes.
454 # @param **extra Additional attributes, given as keyword arguments.
455 # @return An element instance.
456 # @defreturn Element
457
458 def Element(tag, attrib={}, **extra):
459     attrib = attrib.copy()
460     attrib.update(extra)
461     return _ElementInterface(tag, attrib)
462
463 ##
464 # Subelement factory.  This function creates an element instance, and
465 # appends it to an existing element.
466 # <p>
467 # The element name, attribute names, and attribute values can be
468 # either 8-bit ASCII strings or Unicode strings.
469 #
470 # @param parent The parent element.
471 # @param tag The subelement name.
472 # @param attrib An optional dictionary, containing element attributes.
473 # @param **extra Additional attributes, given as keyword arguments.
474 # @return An element instance.
475 # @defreturn Element
476
477 def SubElement(parent, tag, attrib={}, **extra):
478     attrib = attrib.copy()
479     attrib.update(extra)
480     element = parent.makeelement(tag, attrib)
481     parent.append(element)
482     return element
483
484 ##
485 # Comment element factory.  This factory function creates a special
486 # element that will be serialized as an XML comment.
487 # <p>
488 # The comment string can be either an 8-bit ASCII string or a Unicode
489 # string.
490 #
491 # @param text A string containing the comment string.
492 # @return An element instance, representing a comment.
493 # @defreturn Element
494
495 def Comment(text=None):
496     element = Element(Comment)
497     element.text = text
498     return element
499
500 ##
501 # PI element factory.  This factory function creates a special element
502 # that will be serialized as an XML processing instruction.
503 #
504 # @param target A string containing the PI target.
505 # @param text A string containing the PI contents, if any.
506 # @return An element instance, representing a PI.
507 # @defreturn Element
508
509 def ProcessingInstruction(target, text=None):
510     element = Element(ProcessingInstruction)
511     element.text = target
512     if text:
513         element.text = element.text + " " + text
514     return element
515
516 PI = ProcessingInstruction
517
518 ##
519 # QName wrapper.  This can be used to wrap a QName attribute value, in
520 # order to get proper namespace handling on output.
521 #
522 # @param text A string containing the QName value, in the form {uri}local,
523 #     or, if the tag argument is given, the URI part of a QName.
524 # @param tag Optional tag.  If given, the first argument is interpreted as
525 #     an URI, and this argument is interpreted as a local name.
526 # @return An opaque object, representing the QName.
527
528 class QName:
529     def __init__(self, text_or_uri, tag=None):
530         if tag:
531             text_or_uri = "{%s}%s" % (text_or_uri, tag)
532         self.text = text_or_uri
533     def __str__(self):
534         return self.text
535     def __hash__(self):
536         return hash(self.text)
537     def __cmp__(self, other):
538         if isinstance(other, QName):
539             return cmp(self.text, other.text)
540         return cmp(self.text, other)
541
542 ##
543 # ElementTree wrapper class.  This class represents an entire element
544 # hierarchy, and adds some extra support for serialization to and from
545 # standard XML.
546 #
547 # @param element Optional root element.
548 # @keyparam file Optional file handle or name.  If given, the
549 #     tree is initialized with the contents of this XML file.
550
551 class ElementTree:
552
553     def __init__(self, element=None, file=None):
554         assert element is None or iselement(element)
555         self._root = element # first node
556         if file:
557             self.parse(file)
558
559     ##
560     # Gets the root element for this tree.
561     #
562     # @return An element instance.
563     # @defreturn Element
564
565     def getroot(self):
566         return self._root
567
568     ##
569     # Replaces the root element for this tree.  This discards the
570     # current contents of the tree, and replaces it with the given
571     # element.  Use with care.
572     #
573     # @param element An element instance.
574
575     def _setroot(self, element):
576         assert iselement(element)
577         self._root = element
578
579     ##
580     # Loads an external XML document into this element tree.
581     #
582     # @param source A file name or file object.
583     # @param parser An optional parser instance.  If not given, the
584     #     standard {@link XMLTreeBuilder} parser is used.
585     # @return The document root element.
586     # @defreturn Element
587
588     def parse(self, source, parser=None):
589         if not hasattr(source, "read"):
590             # OP 14/11/2017 Ajout de traces pour essayer de decouvrir le pb
591     #               de remontee de log des tests
592             print "TRACES OP - ElementTree.py/ElementTree.parse() source = '#%s#'" %source
593             source = open(source, "rb")
594         if not parser:
595             parser = XMLTreeBuilder()
596         while 1:
597             data = source.read(32768)
598             if not data:
599                 break
600             parser.feed(data)
601         self._root = parser.close()
602         return self._root
603
604     ##
605     # Creates a tree iterator for the root element.  The iterator loops
606     # over all elements in this tree, in document order.
607     #
608     # @param tag What tags to look for (default is to return all elements)
609     # @return An iterator.
610     # @defreturn iterator
611
612     def getiterator(self, tag=None):
613         assert self._root is not None
614         return self._root.getiterator(tag)
615
616     ##
617     # Finds the first toplevel element with given tag.
618     # Same as getroot().find(path).
619     #
620     # @param path What element to look for.
621     # @return The first matching element, or None if no element was found.
622     # @defreturn Element or None
623
624     def find(self, path):
625         assert self._root is not None
626         if path[:1] == "/":
627             path = "." + path
628         return self._root.find(path)
629
630     ##
631     # Finds the element text for the first toplevel element with given
632     # tag.  Same as getroot().findtext(path).
633     #
634     # @param path What toplevel element to look for.
635     # @param default What to return if the element was not found.
636     # @return The text content of the first matching element, or the
637     #     default value no element was found.  Note that if the element
638     #     has is found, but has no text content, this method returns an
639     #     empty string.
640     # @defreturn string
641
642     def findtext(self, path, default=None):
643         assert self._root is not None
644         if path[:1] == "/":
645             path = "." + path
646         return self._root.findtext(path, default)
647
648     ##
649     # Finds all toplevel elements with the given tag.
650     # Same as getroot().findall(path).
651     #
652     # @param path What element to look for.
653     # @return A list or iterator containing all matching elements,
654     #    in document order.
655     # @defreturn list of Element instances
656
657     def findall(self, path):
658         assert self._root is not None
659         if path[:1] == "/":
660             path = "." + path
661         return self._root.findall(path)
662
663     ##
664     # Writes the element tree to a file, as XML.
665     #
666     # @param file A file name, or a file object opened for writing.
667     # @param encoding Optional output encoding (default is US-ASCII).
668
669     def write(self, file, encoding="us-ascii"):
670         assert self._root is not None
671         if not hasattr(file, "write"):
672             file = open(file, "wb")
673         if not encoding:
674             encoding = "us-ascii"
675         elif encoding != "utf-8" and encoding != "us-ascii":
676             file.write("<?xml version='1.0' encoding='%s'?>\n" % encoding)
677         self._write(file, self._root, encoding, {})
678
679     def _write(self, file, node, encoding, namespaces, margin=0):
680         # write XML to file
681         tag = node.tag
682         if tag is Comment:
683             file.write("<!-- %s -->\n" % _escape_cdata(node.text, encoding))
684         elif tag is ProcessingInstruction:
685             file.write("<?%s?>\n" % _escape_cdata(node.text, encoding))
686         else:
687             items = node.items()
688             xmlns_items = [] # new namespaces in this scope
689             try:
690                 if isinstance(tag, QName) or tag[:1] == "{":
691                     tag, xmlns = fixtag(tag, namespaces)
692                     if xmlns: xmlns_items.append(xmlns)
693             except TypeError:
694                 _raise_serialization_error(tag)
695             file.write(' ' * margin)
696             file.write(_encode("<", encoding) + _encode(tag, encoding))
697             if items or xmlns_items:
698                 items = sorted(items) # lexical order
699                 for k, v in items:
700                     try:
701                         if isinstance(k, QName) or k[:1] == "{":
702                             k, xmlns = fixtag(k, namespaces)
703                             if xmlns: xmlns_items.append(xmlns)
704                     except TypeError:
705                         _raise_serialization_error(k)
706                     try:
707                         if isinstance(v, QName):
708                             v, xmlns = fixtag(v, namespaces)
709                             if xmlns: xmlns_items.append(xmlns)
710                     except TypeError:
711                         _raise_serialization_error(v)
712                     file.write(" %s=\"%s\"" % (k,v))
713                 for k, v in xmlns_items:
714                     file.write(" %s=\"%s\"" % (k,v))
715             if node.text or len(node):
716                 file.write(">")
717                 if node.text:
718                     file.write(_escape_cdata(node.text, encoding))
719                 if len(node) > 0: file.write("\n")
720                 for n in node:
721                     self._write(file, n, encoding, namespaces, margin + 2)
722                 if len(node) > 0: file.write(' ' * margin)
723                 file.write(_encode("</", encoding) + _encode(tag, encoding) + _encode(">\n", encoding))
724             else:
725                 file.write("/>\n")
726             for k, v in xmlns_items:
727                 del namespaces[v]
728         if node.tail:
729             file.write(_escape_cdata(node.tail, encoding))
730
731 # --------------------------------------------------------------------
732 # helpers
733
734 ##
735 # Checks if an object appears to be a valid element object.
736 #
737 # @param An element instance.
738 # @return A true value if this is an element object.
739 # @defreturn flag
740
741 def iselement(element):
742     # FIXME: not sure about this; might be a better idea to look
743     # for tag/attrib/text attributes
744     return isinstance(element, _ElementInterface) or hasattr(element, "tag")
745
746 ##
747 # Writes an element tree or element structure to sys.stdout.  This
748 # function should be used for debugging only.
749 # <p>
750 # The exact output format is implementation dependent.  In this
751 # version, it's written as an ordinary XML file.
752 #
753 # @param elem An element tree or an individual element.
754
755 def dump(elem):
756     # debugging
757     if not isinstance(elem, ElementTree):
758         elem = ElementTree(elem)
759     elem.write(sys.stdout)
760     tail = elem.getroot().tail
761     if not tail or tail[-1] != "\n":
762         sys.stdout.write("\n")
763
764 def _encode(s, encoding):
765     try:
766         return s.encode(encoding)
767     except AttributeError:
768         return s # 1.5.2: assume the string uses the right encoding
769
770 if sys.version[:3] == "1.5":
771     _escape = re.compile(r"[&<>\"\x80-\xff]+") # 1.5.2
772 else:
773     _escape = re.compile(eval(r'u"[&<>\"\u0080-\uffff]+"'))
774
775 _escape_map = {
776     "&": "&amp;",
777     "<": "&lt;",
778     ">": "&gt;",
779     '"': "&quot;",
780 }
781
782 _namespace_map = {
783     # "well-known" namespace prefixes
784     "http://www.w3.org/XML/1998/namespace": "xml",
785     "http://www.w3.org/1999/xhtml": "html",
786     "http://www.w3.org/1999/02/22-rdf-syntax-ns#": "rdf",
787     "http://schemas.xmlsoap.org/wsdl/": "wsdl",
788 }
789
790 def _raise_serialization_error(text):
791     raise TypeError(
792         "cannot serialize %r (type %s)" % (text, type(text).__name__)
793         )
794
795 def _encode_entity(text, pattern=_escape):
796     # map reserved and non-ascii characters to numerical entities
797     def escape_entities(m, map=_escape_map):
798         out = []
799         append = out.append
800         for char in m.group():
801             text = map.get(char)
802             if text is None:
803                 text = "&#%d;" % ord(char)
804             append(text)
805         return string.join(out, "")
806     try:
807         return _encode(pattern.sub(escape_entities, text), "ascii")
808     except TypeError:
809         _raise_serialization_error(text)
810
811 #
812 # the following functions assume an ascii-compatible encoding
813 # (or "utf-16")
814
815 def _escape_cdata(text, encoding=None, replace=str.replace):
816     # escape character data
817     try:
818         if platform.python_version()[0] == '2': # python 2.x.y
819             if encoding:
820                 try:
821                     text = _encode(text, encoding)
822                 except UnicodeError:
823                     return _encode_entity(text)
824             
825         text = replace(text, "&", "&amp;")
826         text = replace(text, "<", "&lt;")
827         text = replace(text, ">", "&gt;")
828         text = replace(text, "####newLine####", "<br \>")
829         if encoding:
830             try:
831                 text = _encode(text, encoding)
832             except UnicodeError:
833                 return _encode_entity(text)
834         return text
835     except (TypeError, AttributeError):
836         _raise_serialization_error(text)
837
838 def _escape_attrib(text, encoding=None, replace=str.replace):
839     # escape attribute value
840     try:
841         text = replace(text, "&", "&amp;")
842         text = replace(text, "'", "&apos;") # FIXME: overkill
843         text = replace(text, "\"", "&quot;")
844         text = replace(text, "<", "&lt;")
845         text = replace(text, ">", "&gt;")
846         if encoding:
847             try:
848                 text = _encode(text, encoding)
849             except UnicodeError:
850                 return _encode_entity(text)
851         return text
852     except (TypeError, AttributeError):
853         _raise_serialization_error(text)
854
855 def fixtag(tag, namespaces):
856     # given a decorated tag (of the form {uri}tag), return prefixed
857     # tag and namespace declaration, if any
858     if isinstance(tag, QName):
859         tag = tag.text
860     namespace_uri, tag = string.split(tag[1:], "}", 1)
861     prefix = namespaces.get(namespace_uri)
862     if prefix is None:
863         prefix = _namespace_map.get(namespace_uri)
864         if prefix is None:
865             prefix = "ns%d" % len(namespaces)
866         namespaces[namespace_uri] = prefix
867         if prefix == "xml":
868             xmlns = None
869         else:
870             xmlns = ("xmlns:%s" % prefix, namespace_uri)
871     else:
872         xmlns = None
873     return "%s:%s" % (prefix, tag), xmlns
874
875 ##
876 # Parses an XML document into an element tree.
877 #
878 # @param source A filename or file object containing XML data.
879 # @param parser An optional parser instance.  If not given, the
880 #     standard {@link XMLTreeBuilder} parser is used.
881 # @return An ElementTree instance
882
883 def parse(source, parser=None):
884     # OP 14/11/2017 Ajout de traces pour essayer de decouvrir le pb
885     #               de remontee de log des tests
886     print "TRACES OP - ElementTree.py/parse() source = '#%s#'" %source
887     tree = ElementTree()
888     tree.parse(source, parser)
889     return tree
890
891 ##
892 # Parses an XML document into an element tree incrementally, and reports
893 # what's going on to the user.
894 #
895 # @param source A filename or file object containing XML data.
896 # @param events A list of events to report back.  If omitted, only "end"
897 #     events are reported.
898 # @return A (event, elem) iterator.
899
900 class iterparse:
901
902     def __init__(self, source, events=None):
903         if not hasattr(source, "read"):
904             # OP TEST
905             print "iterparse.__init__ source = %s" %source
906             source = open(source, "rb")
907         self._file = source
908         self._events = []
909         self._index = 0
910         self.root = self._root = None
911         self._parser = XMLTreeBuilder()
912         # wire up the parser for event reporting
913         parser = self._parser._parser
914         append = self._events.append
915         if events is None:
916             events = ["end"]
917         for event in events:
918             if event == "start":
919                 try:
920                     parser.ordered_attributes = 1
921                     parser.specified_attributes = 1
922                     def handler(tag, attrib_in, event=event, append=append,
923                                 start=self._parser._start_list):
924                         append((event, start(tag, attrib_in)))
925                     parser.StartElementHandler = handler
926                 except AttributeError:
927                     def handler(tag, attrib_in, event=event, append=append,
928                                 start=self._parser._start):
929                         append((event, start(tag, attrib_in)))
930                     parser.StartElementHandler = handler
931             elif event == "end":
932                 def handler(tag, event=event, append=append,
933                             end=self._parser._end):
934                     append((event, end(tag)))
935                 parser.EndElementHandler = handler
936             elif event == "start-ns":
937                 def handler(prefix, uri, event=event, append=append):
938                     try:
939                         uri = _encode(uri, "ascii")
940                     except UnicodeError:
941                         pass
942                     append((event, (prefix or "", uri)))
943                 parser.StartNamespaceDeclHandler = handler
944             elif event == "end-ns":
945                 def handler(prefix, event=event, append=append):
946                     append((event, None))
947                 parser.EndNamespaceDeclHandler = handler
948
949     def next(self):
950         while 1:
951             try:
952                 item = self._events[self._index]
953             except IndexError:
954                 if self._parser is None:
955                     self.root = self._root
956                     try:
957                         raise StopIteration
958                     except NameError:
959                         raise IndexError
960                 # load event buffer
961                 del self._events[:]
962                 self._index = 0
963                 data = self._file.read(16384)
964                 if data:
965                     self._parser.feed(data)
966                 else:
967                     self._root = self._parser.close()
968                     self._parser = None
969             else:
970                 self._index = self._index + 1
971                 return item
972
973     try:
974         iter
975         def __iter__(self):
976             return self
977     except NameError:
978         def __getitem__(self, index):
979             return self.next()
980
981 ##
982 # Parses an XML document from a string constant.  This function can
983 # be used to embed "XML literals" in Python code.
984 #
985 # @param source A string containing XML data.
986 # @return An Element instance.
987 # @defreturn Element
988
989 def XML(text):
990     parser = XMLTreeBuilder()
991     parser.feed(text)
992     return parser.close()
993
994 ##
995 # Parses an XML document from a string constant, and also returns
996 # a dictionary which maps from element id:s to elements.
997 #
998 # @param source A string containing XML data.
999 # @return A tuple containing an Element instance and a dictionary.
1000 # @defreturn (Element, dictionary)
1001
1002 def XMLID(text):
1003     parser = XMLTreeBuilder()
1004     parser.feed(text)
1005     tree = parser.close()
1006     ids = {}
1007     for elem in tree.getiterator():
1008         id = elem.get("id")
1009         if id:
1010             ids[id] = elem
1011     return tree, ids
1012
1013 ##
1014 # Parses an XML document from a string constant.  Same as {@link #XML}.
1015 #
1016 # @def fromstring(text)
1017 # @param source A string containing XML data.
1018 # @return An Element instance.
1019 # @defreturn Element
1020
1021 fromstring = XML
1022
1023 ##
1024 # Generates a string representation of an XML element, including all
1025 # subelements.
1026 #
1027 # @param element An Element instance.
1028 # @return An encoded string containing the XML data.
1029 # @defreturn string
1030
1031 def tostring(element, encoding=None):
1032     class dummy:
1033         pass
1034     data = []
1035     file = dummy()
1036     file.write = data.append
1037     ElementTree(element).write(file, encoding)
1038     data2 = []
1039     for item in data:
1040         if isinstance(item, bytes):
1041             item = item.decode()
1042         data2.append(item)
1043     return "".join(data2)
1044
1045 ##
1046 # Generic element structure builder.  This builder converts a sequence
1047 # of {@link #TreeBuilder.start}, {@link #TreeBuilder.data}, and {@link
1048 # #TreeBuilder.end} method calls to a well-formed element structure.
1049 # <p>
1050 # You can use this class to build an element structure using a custom XML
1051 # parser, or a parser for some other XML-like format.
1052 #
1053 # @param element_factory Optional element factory.  This factory
1054 #    is called to create new Element instances, as necessary.
1055
1056 class TreeBuilder:
1057
1058     def __init__(self, element_factory=None):
1059         self._data = [] # data collector
1060         self._elem = [] # element stack
1061         self._last = None # last element
1062         self._tail = None # true if we're after an end tag
1063         if element_factory is None:
1064             element_factory = _ElementInterface
1065         self._factory = element_factory
1066
1067     ##
1068     # Flushes the parser buffers, and returns the toplevel documen
1069     # element.
1070     #
1071     # @return An Element instance.
1072     # @defreturn Element
1073
1074     def close(self):
1075         assert len(self._elem) == 0, "missing end tags"
1076         assert self._last != None, "missing toplevel element"
1077         return self._last
1078
1079     def _flush(self):
1080         if self._data:
1081             if self._last is not None:
1082                 text = ""
1083                 for item in self._data:
1084                     try:
1085                         text += item
1086                     except:
1087                         text += item.decode()
1088                 if self._tail:
1089                     assert self._last.tail is None, "internal error (tail)"
1090                     self._last.tail = text
1091                 else:
1092                     assert self._last.text is None, "internal error (text)"
1093                     self._last.text = text
1094             self._data = []
1095
1096     ##
1097     # Adds text to the current element.
1098     #
1099     # @param data A string.  This should be either an 8-bit string
1100     #    containing ASCII text, or a Unicode string.
1101
1102     def data(self, data):
1103         self._data.append(data)
1104
1105     ##
1106     # Opens a new element.
1107     #
1108     # @param tag The element name.
1109     # @param attrib A dictionary containing element attributes.
1110     # @return The opened element.
1111     # @defreturn Element
1112
1113     def start(self, tag, attrs):
1114         self._flush()
1115         self._last = elem = self._factory(tag, attrs)
1116         if self._elem:
1117             self._elem[-1].append(elem)
1118         self._elem.append(elem)
1119         self._tail = 0
1120         return elem
1121
1122     ##
1123     # Closes the current element.
1124     #
1125     # @param tag The element name.
1126     # @return The closed element.
1127     # @defreturn Element
1128
1129     def end(self, tag):
1130         self._flush()
1131         self._last = self._elem.pop()
1132         assert self._last.tag == tag,\
1133                "end tag mismatch (expected %s, got %s)" % (
1134                    self._last.tag, tag)
1135         self._tail = 1
1136         return self._last
1137
1138 ##
1139 # Element structure builder for XML source data, based on the
1140 # <b>expat</b> parser.
1141 #
1142 # @keyparam target Target object.  If omitted, the builder uses an
1143 #     instance of the standard {@link #TreeBuilder} class.
1144 # @keyparam html Predefine HTML entities.  This flag is not supported
1145 #     by the current implementation.
1146 # @see #ElementTree
1147 # @see #TreeBuilder
1148
1149 class XMLTreeBuilder:
1150
1151     def __init__(self, html=0, target=None):
1152         try:
1153             from xml.parsers import expat
1154         except ImportError:
1155             raise ImportError(
1156                 "No module named expat; use SimpleXMLTreeBuilder instead"
1157                 )
1158         self._parser = parser = expat.ParserCreate(None, "}")
1159         if target is None:
1160             target = TreeBuilder()
1161         self._target = target
1162         self._names = {} # name memo cache
1163         # callbacks
1164         parser.DefaultHandlerExpand = self._default
1165         parser.StartElementHandler = self._start
1166         parser.EndElementHandler = self._end
1167         parser.CharacterDataHandler = self._data
1168         # let expat do the buffering, if supported
1169         try:
1170             self._parser.buffer_text = 1
1171         except AttributeError:
1172             pass
1173         # use new-style attribute handling, if supported
1174         try:
1175             self._parser.ordered_attributes = 1
1176             self._parser.specified_attributes = 1
1177             parser.StartElementHandler = self._start_list
1178         except AttributeError:
1179             pass
1180         #encoding = None
1181         #if not parser.returns_unicode:
1182         #    encoding = "utf-8"
1183         # target.xml(encoding, None)
1184         self._doctype = None
1185         self.entity = {}
1186
1187     def _fixtext(self, text):
1188         # convert text string to ascii, if possible
1189         try:
1190             return _encode(text, "ascii")
1191         except UnicodeError:
1192             return text
1193
1194     def _fixname(self, key):
1195         # expand qname, and convert name string to ascii, if possible
1196         try:
1197             name = self._names[key]
1198         except KeyError:
1199             name = key
1200             if "}" in name:
1201                 name = "{" + name
1202             self._names[key] = name = self._fixtext(name)
1203         return name
1204
1205     def _start(self, tag, attrib_in):
1206         fixname = self._fixname
1207         tag = fixname(tag)
1208         attrib = {}
1209         for key, value in attrib_in.items():
1210             attrib[fixname(key)] = self._fixtext(value)
1211         return self._target.start(tag, attrib)
1212
1213     def _start_list(self, tag, attrib_in):
1214         fixname = self._fixname
1215         tag = fixname(tag)
1216         attrib = {}
1217         if attrib_in:
1218             for i in range(0, len(attrib_in), 2):
1219                 attrib[fixname(attrib_in[i])] = self._fixtext(attrib_in[i+1])
1220         return self._target.start(tag, attrib)
1221
1222     def _data(self, text):
1223         return self._target.data(self._fixtext(text))
1224
1225     def _end(self, tag):
1226         return self._target.end(self._fixname(tag))
1227
1228     def _default(self, text):
1229         prefix = text[:1]
1230         if prefix == "&":
1231             # deal with undefined entities
1232             try:
1233                 self._target.data(self.entity[text[1:-1]])
1234             except KeyError:
1235                 from xml.parsers import expat
1236                 raise expat.error(
1237                     "undefined entity %s: line %d, column %d" %
1238                     (text, self._parser.ErrorLineNumber,
1239                     self._parser.ErrorColumnNumber)
1240                     )
1241         elif prefix == "<" and text[:9] == "<!DOCTYPE":
1242             self._doctype = [] # inside a doctype declaration
1243         elif self._doctype is not None:
1244             # parse doctype contents
1245             if prefix == ">":
1246                 self._doctype = None
1247                 return
1248             text = string.strip(text)
1249             if not text:
1250                 return
1251             self._doctype.append(text)
1252             n = len(self._doctype)
1253             if n > 2:
1254                 type = self._doctype[1]
1255                 if type == "PUBLIC" and n == 4:
1256                     name, type, pubid, system = self._doctype
1257                 elif type == "SYSTEM" and n == 3:
1258                     name, type, system = self._doctype
1259                     pubid = None
1260                 else:
1261                     return
1262                 if pubid:
1263                     pubid = pubid[1:-1]
1264                 self.doctype(name, pubid, system[1:-1])
1265                 self._doctype = None
1266
1267     ##
1268     # Handles a doctype declaration.
1269     #
1270     # @param name Doctype name.
1271     # @param pubid Public identifier.
1272     # @param system System identifier.
1273
1274     def doctype(self, name, pubid, system):
1275         pass
1276
1277     ##
1278     # Feeds data to the parser.
1279     #
1280     # @param data Encoded data.
1281
1282     def feed(self, data):
1283         # OP 14/11/2017 Ajout de traces pour essayer de decouvrir le pb
1284         #               de remontee de log des tests
1285         print "TRACES OP - ElementTree.py/XMLTreeBuilder.feed() data = '#%s#'" %data
1286         self._parser.Parse(data, 0)
1287
1288     ##
1289     # Finishes feeding data to the parser.
1290     #
1291     # @return An element structure.
1292     # @defreturn Element
1293
1294     def close(self):
1295         self._parser.Parse("", 1) # end of data
1296         tree = self._target.close()
1297         del self._target, self._parser # get rid of circular references
1298         return tree