instrumentation: add next-share/
[cs-p2p-next.git] / instrumentation / next-share / BaseLib / Core / Statistics / Status / XmlPrinter.py
1 # Written by Njaal Borch
2 # see LICENSE.txt for license information
3
4 def to_unicode(string):
5     """
6     Function to change a string (unicode or not) into a unicode string
7     Will try utf-8 first, then latin-1.
8     TODO: Is there a better way?  There HAS to be!!!
9     """
10
11     if string.__class__ != str:
12         return string
13     try:
14         return unicode(string, "utf-8")
15     except:
16         pass
17     print "Warning: Fallback to latin-1 for unicode conversion"
18     return unicode(string, "latin-1")
19
20
21 class XmlPrinter:
22
23     """
24     An XML printer that will print XML *with namespaces*
25
26     Why minidom.toxml() does not do so really makes absolutenly no sense
27     
28     """
29
30
31     def __init__(self, doc):
32         """
33         doc should be a xml.dom.minidom document
34         
35         """
36
37         self.root = doc
38         self.namespace_counter=0
39         
40     def to_xml(self, encoding="UTF8"):
41         """
42         Like minidom toxml, just using namespaces too
43         """
44         return self._toxml(self.root, indent='', newl='').encode(encoding, "replace")
45     
46     def to_pretty_xml(self, indent=' ', newl='\n', encoding="UTF8"):
47         """
48         Like minidom toxml, just using namespaces too
49         """
50         return self._toxml(self.root, indent, newl).encode(encoding, "replace")
51     
52
53     def _make_header(self, encoding):
54         
55         return u'<?xml version="1.0" encoding="%s" ?>\n'%encoding
56
57     def _new_namespace(self, namespace):
58         # Make new namespace
59         ns_short = "ns%d"%self.namespace_counter
60         self.namespace_counter += 1
61         return ns_short
62         
63     def _toxml(self, element, indent=' ', newl='\n', encoding='UTF8', namespaces=None):
64         """
65         Recursive, internal function - do not use directly
66         """
67
68         if not element:
69             return ""
70
71         if not namespaces:
72             namespaces = {}
73         buffer = u""
74         define_ns_list = []
75
76         if element == self.root:
77             # Print the header
78             buffer = self._make_header(encoding)
79
80         if element.nodeType == element.TEXT_NODE:
81             buffer += indent + to_unicode(element.nodeValue) + newl
82             return buffer
83         if element.nodeType == element.ELEMENT_NODE:
84             ns = element.namespaceURI
85             name = to_unicode(element.localName)
86             if name.find(" ") > -1:
87                 raise Exception("Refusing spaces in tag names")
88             
89             if namespaces.has_key(ns):
90                 ns_short = namespaces[ns]
91                 define_ns = False
92             else:
93                 if ns not in ["", None]:
94                     ns_short = self._new_namespace(ns)
95                     define_ns_list.append((ns, ns_short))
96                 else:
97                     ns_short = None
98                     
99                 define_ns = True
100                 namespaces[ns] = ns_short
101
102             # Should we define more namespaces?  Will peak into the
103             # children and see if there are any
104             for child in element.childNodes:
105                 if child.nodeType != child.ELEMENT_NODE:
106                     continue
107
108                 if not namespaces.has_key(child.namespaceURI) and \
109                        child.namespaceURI not in [None, ""]:
110                     # Should define this one too!
111                     new_ns = self._new_namespace(child.namespaceURI)
112                     define_ns_list.append((child.namespaceURI, new_ns))
113                     namespaces[child.namespaceURI] = new_ns
114             buffer += indent
115             
116             # If we have no children, we will write <tag/>
117             if not element.hasChildNodes():
118                 if ns != None:
119                     if define_ns:
120                         if ns_short:
121                             buffer += '<%s:%s xmlns:%s="%s"/>%s'%\
122                                       (ns_short, name,ns_short,ns,newl)
123                         else:
124                             buffer += '<%s xmlns="%s"/>%s'%(name,ns,newl)
125                     else:
126                         if ns_short:
127                             buffer += '<%s:%s/>%s'%(ns_short, name, newl)
128                         else:
129                             buffer += '<%s/>%s'%(name, newl)
130
131                 else:
132                     buffer += '<%s/>%s'%(name, newl)
133
134                 # Clean up - namespaces is passed as a reference, and is
135                 # as such not cleaned up.  Let it be so to save some speed
136                 for (n,short) in define_ns_list:
137                     del namespaces[n]
138                 return buffer
139
140             # Have children
141             ns_string = ""
142             if len(define_ns_list) > 0:
143                 for (url, short) in define_ns_list:
144                     ns_string += ' xmlns:%s="%s"'%(short, url)
145                         
146             if ns != None:
147                 if define_ns:
148                     if ns_short:
149                         # Define all namespaces of next level children too
150                         buffer += '<%s:%s xmlns:%s="%s"%s>%s'%\
151                                   (ns_short, name, ns_short, ns, ns_string, newl)
152                     else:
153                         buffer += '<%s xmlns="%s"%s>%s'%(name,ns,ns_string,newl)
154                 else:
155                     if ns_short:
156                         buffer += '<%s:%s%s>%s'%(ns_short, name, ns_string, newl)
157                     else:
158                         buffer += '<%s%s>%s'%(name, ns_string, newl)
159             elif ns_string:
160                 buffer += '<%s %s>%s'%(name, ns_string, newl)
161             else:
162                 buffer += '<%s>%s'%(name, newl)
163
164             # Recursively process
165             for child in element.childNodes:
166                 new_indent = indent
167                 if new_indent:
168                     new_indent += "  "
169                 buffer += self._toxml(child, new_indent, newl, encoding, namespaces)
170             if ns_short:
171                 buffer += "%s</%s:%s>%s"%(indent, ns_short, name, newl)
172             else:
173                 buffer += "%s</%s>%s"%(indent, name, newl)
174
175             for (n, short) in define_ns_list:
176                 del namespaces[n]
177             try:
178                 return buffer
179             except Exception,e:
180                 print "-----------------"
181                 print "Exception:",e
182                 print "Buffer:",buffer
183                 print "-----------------"
184                 raise e
185
186         raise Exception("Could not serialize DOM")