annotate scripts-java/visualizer/PListReader.py @ 63:b342dc9b52eb

add document
author axmo
date Tue, 24 Feb 2009 17:59:45 +0900
parents 1809e2b05824
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
7
1809e2b05824 Initial revision
fuchita
parents:
diff changeset
1 """PListReader
1809e2b05824 Initial revision
fuchita
parents:
diff changeset
2
1809e2b05824 Initial revision
fuchita
parents:
diff changeset
3 Reads Apple's plist XML data structure serialization format and returns a
1809e2b05824 Initial revision
fuchita
parents:
diff changeset
4 native Python data structure. In conjunction with XMLFilter, it should
1809e2b05824 Initial revision
fuchita
parents:
diff changeset
5 be compatible with all versions of Python from 1.5.2 up, on all platforms.
1809e2b05824 Initial revision
fuchita
parents:
diff changeset
6
1809e2b05824 Initial revision
fuchita
parents:
diff changeset
7 Copyright Andrew Shearer 2003-2004
1809e2b05824 Initial revision
fuchita
parents:
diff changeset
8 <mailto:awshearer@shearersoftware.com>
1809e2b05824 Initial revision
fuchita
parents:
diff changeset
9 For the current version, see:
1809e2b05824 Initial revision
fuchita
parents:
diff changeset
10 http://www.shearersoftware.com/software/developers/plist/
1809e2b05824 Initial revision
fuchita
parents:
diff changeset
11
1809e2b05824 Initial revision
fuchita
parents:
diff changeset
12 Revision History:
1809e2b05824 Initial revision
fuchita
parents:
diff changeset
13 2003-08-16 ashearer Initial version
1809e2b05824 Initial revision
fuchita
parents:
diff changeset
14 2003-09-04 ashearer Support getRecommendedFeatures() & the XMLFilter features
1809e2b05824 Initial revision
fuchita
parents:
diff changeset
15 API, and use it to disable feature_external_ges, allowing
1809e2b05824 Initial revision
fuchita
parents:
diff changeset
16 parsing to work even while disconnected from the Internet
1809e2b05824 Initial revision
fuchita
parents:
diff changeset
17 2004-02-14 ashearer Use native booleans if available; minor changes to
1809e2b05824 Initial revision
fuchita
parents:
diff changeset
18 documentation
1809e2b05824 Initial revision
fuchita
parents:
diff changeset
19
1809e2b05824 Initial revision
fuchita
parents:
diff changeset
20 Dependencies:
1809e2b05824 Initial revision
fuchita
parents:
diff changeset
21 XMLFilter module (optional). Provides compatibility for versions
1809e2b05824 Initial revision
fuchita
parents:
diff changeset
22 of Python without xml.sax support, such as the version of Python
1809e2b05824 Initial revision
fuchita
parents:
diff changeset
23 2.2 that shipped with Jaguar (Mac OS X 10.2). If XMLFilter isn't
1809e2b05824 Initial revision
fuchita
parents:
diff changeset
24 found, xml.sax.handler will be tried instead. See:
1809e2b05824 Initial revision
fuchita
parents:
diff changeset
25 http://www.shearersoftware.com/software/developers/xmlfilter/
1809e2b05824 Initial revision
fuchita
parents:
diff changeset
26
1809e2b05824 Initial revision
fuchita
parents:
diff changeset
27 W3CDate module. Parses the W3C Date format (a subset of ISO 8601), which
1809e2b05824 Initial revision
fuchita
parents:
diff changeset
28 is the standard datetime format for plists. See:
1809e2b05824 Initial revision
fuchita
parents:
diff changeset
29 http://www.shearersoftware.com/software/developers/w3cdate/
1809e2b05824 Initial revision
fuchita
parents:
diff changeset
30
1809e2b05824 Initial revision
fuchita
parents:
diff changeset
31
1809e2b05824 Initial revision
fuchita
parents:
diff changeset
32 Usage:
1809e2b05824 Initial revision
fuchita
parents:
diff changeset
33 import XMLFilter
1809e2b05824 Initial revision
fuchita
parents:
diff changeset
34 reader = PListReader()
1809e2b05824 Initial revision
fuchita
parents:
diff changeset
35 XMLFilter.parseFilePath(filePath, reader,
1809e2b05824 Initial revision
fuchita
parents:
diff changeset
36 features = reader.getRecommendedFeatures())
1809e2b05824 Initial revision
fuchita
parents:
diff changeset
37 result = reader.getResult()
1809e2b05824 Initial revision
fuchita
parents:
diff changeset
38 # result could be a Python dict, list, string, number, etc.
1809e2b05824 Initial revision
fuchita
parents:
diff changeset
39
1809e2b05824 Initial revision
fuchita
parents:
diff changeset
40 Notes: This class assumes the target file is a valid plist file. In
1809e2b05824 Initial revision
fuchita
parents:
diff changeset
41 particular, the root element isn't checked to make sure that it's
1809e2b05824 Initial revision
fuchita
parents:
diff changeset
42 "plist", and unknown elements are ignored. So it's more lax than a
1809e2b05824 Initial revision
fuchita
parents:
diff changeset
43 validating parser. If nothing in the document was recognized, the result
1809e2b05824 Initial revision
fuchita
parents:
diff changeset
44 will be Python's None value. If the known elements are corrupt, the
1809e2b05824 Initial revision
fuchita
parents:
diff changeset
45 error messages may not be that helpful. Exceptions will generally be
1809e2b05824 Initial revision
fuchita
parents:
diff changeset
46 thrown at the right times, but their contents could be improved.
1809e2b05824 Initial revision
fuchita
parents:
diff changeset
47
1809e2b05824 Initial revision
fuchita
parents:
diff changeset
48 License: dual-licensed under the Python License and MPSL 1.1 (Mozilla License).
1809e2b05824 Initial revision
fuchita
parents:
diff changeset
49
1809e2b05824 Initial revision
fuchita
parents:
diff changeset
50 """
1809e2b05824 Initial revision
fuchita
parents:
diff changeset
51
1809e2b05824 Initial revision
fuchita
parents:
diff changeset
52 try:
1809e2b05824 Initial revision
fuchita
parents:
diff changeset
53 from XMLFilter import XMLSAXHandler, \
1809e2b05824 Initial revision
fuchita
parents:
diff changeset
54 feature_namespaces, feature_external_ges, feature_external_pes
1809e2b05824 Initial revision
fuchita
parents:
diff changeset
55 except ImportError:
1809e2b05824 Initial revision
fuchita
parents:
diff changeset
56 try:
1809e2b05824 Initial revision
fuchita
parents:
diff changeset
57 from xml.sax.handler import ContentHandler as XMLSAXHandler, \
1809e2b05824 Initial revision
fuchita
parents:
diff changeset
58 feature_namespaces, feature_external_ges, feature_external_pes
1809e2b05824 Initial revision
fuchita
parents:
diff changeset
59
1809e2b05824 Initial revision
fuchita
parents:
diff changeset
60 except ImportError:
1809e2b05824 Initial revision
fuchita
parents:
diff changeset
61 raise ImportError, "PListReader requires either the XMLFilter module (available separately from www.shearersoftware.com) or a version of Python with xml.sax support."
1809e2b05824 Initial revision
fuchita
parents:
diff changeset
62
1809e2b05824 Initial revision
fuchita
parents:
diff changeset
63 import W3CDate
1809e2b05824 Initial revision
fuchita
parents:
diff changeset
64 import base64
1809e2b05824 Initial revision
fuchita
parents:
diff changeset
65
1809e2b05824 Initial revision
fuchita
parents:
diff changeset
66 class PListReader(XMLSAXHandler):
1809e2b05824 Initial revision
fuchita
parents:
diff changeset
67 def __init__(self):
1809e2b05824 Initial revision
fuchita
parents:
diff changeset
68 XMLSAXHandler.__init__(self)
1809e2b05824 Initial revision
fuchita
parents:
diff changeset
69 self._currentKey = None # pending key; can tell us we're in a dict
1809e2b05824 Initial revision
fuchita
parents:
diff changeset
70 self._text = None # accumulated text
1809e2b05824 Initial revision
fuchita
parents:
diff changeset
71 self._result = None # parsed Python data structure
1809e2b05824 Initial revision
fuchita
parents:
diff changeset
72 self._stack = [] # stack for nested arrays/dicts
1809e2b05824 Initial revision
fuchita
parents:
diff changeset
73
1809e2b05824 Initial revision
fuchita
parents:
diff changeset
74 def getRecommendedFeatures(self):
1809e2b05824 Initial revision
fuchita
parents:
diff changeset
75 """The recommended features (which clients should pass along to the
1809e2b05824 Initial revision
fuchita
parents:
diff changeset
76 SAX parser) disable namespace parsing and external entities.
1809e2b05824 Initial revision
fuchita
parents:
diff changeset
77
1809e2b05824 Initial revision
fuchita
parents:
diff changeset
78 If external_ges aren't disabled, xml.sax.handler may try to load the DTD
1809e2b05824 Initial revision
fuchita
parents:
diff changeset
79 from Apple's web server, which prevents parsing when there's no Internet
1809e2b05824 Initial revision
fuchita
parents:
diff changeset
80 connection."""
1809e2b05824 Initial revision
fuchita
parents:
diff changeset
81 return {feature_namespaces: 0, feature_external_ges: 0, feature_external_pes: 0}
1809e2b05824 Initial revision
fuchita
parents:
diff changeset
82
1809e2b05824 Initial revision
fuchita
parents:
diff changeset
83 # map plist element names to functions that make an empty Python object
1809e2b05824 Initial revision
fuchita
parents:
diff changeset
84 complexTypeConstructors = {'dict': dict, 'array': list}
1809e2b05824 Initial revision
fuchita
parents:
diff changeset
85
1809e2b05824 Initial revision
fuchita
parents:
diff changeset
86 def startElement(self, name, attrs):
1809e2b05824 Initial revision
fuchita
parents:
diff changeset
87 constructor = self.complexTypeConstructors.get(name)
1809e2b05824 Initial revision
fuchita
parents:
diff changeset
88 if constructor is not None:
1809e2b05824 Initial revision
fuchita
parents:
diff changeset
89 # call constructor func, making an empty Python dict or list
1809e2b05824 Initial revision
fuchita
parents:
diff changeset
90 newItem = constructor()
1809e2b05824 Initial revision
fuchita
parents:
diff changeset
91 # add it to the current container; it will be populated in place
1809e2b05824 Initial revision
fuchita
parents:
diff changeset
92 self._handleValue(newItem)
1809e2b05824 Initial revision
fuchita
parents:
diff changeset
93 # push onto stack, making it the new "current container"
1809e2b05824 Initial revision
fuchita
parents:
diff changeset
94 self._stack.append(newItem)
1809e2b05824 Initial revision
fuchita
parents:
diff changeset
95 else: # not a complex type?
1809e2b05824 Initial revision
fuchita
parents:
diff changeset
96 self._text = '' # turn on text accumulation
1809e2b05824 Initial revision
fuchita
parents:
diff changeset
97
1809e2b05824 Initial revision
fuchita
parents:
diff changeset
98 # map plist element names to functions that convert text into a Python object
1809e2b05824 Initial revision
fuchita
parents:
diff changeset
99 simpleTypeConverterFunctions = {
1809e2b05824 Initial revision
fuchita
parents:
diff changeset
100 'data': base64.decodestring, 'date': W3CDate.W3CDate,
1809e2b05824 Initial revision
fuchita
parents:
diff changeset
101 'integer': int, 'real': float, 'string': lambda x: x,
1809e2b05824 Initial revision
fuchita
parents:
diff changeset
102 'true': lambda x: 1==1, 'false': lambda x: 0==1}
1809e2b05824 Initial revision
fuchita
parents:
diff changeset
103
1809e2b05824 Initial revision
fuchita
parents:
diff changeset
104 def endElement(self, name):
1809e2b05824 Initial revision
fuchita
parents:
diff changeset
105 converter = self.simpleTypeConverterFunctions.get(name)
1809e2b05824 Initial revision
fuchita
parents:
diff changeset
106 if converter is not None:
1809e2b05824 Initial revision
fuchita
parents:
diff changeset
107 self._handleValue(converter(self._text)) # call converter func on text
1809e2b05824 Initial revision
fuchita
parents:
diff changeset
108 self._currentKey = None
1809e2b05824 Initial revision
fuchita
parents:
diff changeset
109 elif name == 'key':
1809e2b05824 Initial revision
fuchita
parents:
diff changeset
110 self._currentKey = self._text # stash dict key for next _endValue
1809e2b05824 Initial revision
fuchita
parents:
diff changeset
111 elif name in ('array', 'dict'):
1809e2b05824 Initial revision
fuchita
parents:
diff changeset
112 self._stack.pop() # array or dict was already updated in place
1809e2b05824 Initial revision
fuchita
parents:
diff changeset
113 self._currentKey = None
1809e2b05824 Initial revision
fuchita
parents:
diff changeset
114 self._text = None # turn off text accumulation
1809e2b05824 Initial revision
fuchita
parents:
diff changeset
115
1809e2b05824 Initial revision
fuchita
parents:
diff changeset
116 def _handleValue(self, value):
1809e2b05824 Initial revision
fuchita
parents:
diff changeset
117 """
1809e2b05824 Initial revision
fuchita
parents:
diff changeset
118 Add a parsed value to the current container.
1809e2b05824 Initial revision
fuchita
parents:
diff changeset
119 The container could be a dict, array, or even the root.
1809e2b05824 Initial revision
fuchita
parents:
diff changeset
120 """
1809e2b05824 Initial revision
fuchita
parents:
diff changeset
121 if self._result is None: # first item in file (the result's root)
1809e2b05824 Initial revision
fuchita
parents:
diff changeset
122 self._result = value
1809e2b05824 Initial revision
fuchita
parents:
diff changeset
123 self._stack.append(value)
1809e2b05824 Initial revision
fuchita
parents:
diff changeset
124 elif self._currentKey is not None: # put value into dict; there was a key
1809e2b05824 Initial revision
fuchita
parents:
diff changeset
125 self._stack[-1][self._currentKey] = value
1809e2b05824 Initial revision
fuchita
parents:
diff changeset
126 self._currentKey = None
1809e2b05824 Initial revision
fuchita
parents:
diff changeset
127 else: # append value to array
1809e2b05824 Initial revision
fuchita
parents:
diff changeset
128 self._stack[-1].append(value) # (must be array; there was no <key>)
1809e2b05824 Initial revision
fuchita
parents:
diff changeset
129
1809e2b05824 Initial revision
fuchita
parents:
diff changeset
130 def characters(self, content):
1809e2b05824 Initial revision
fuchita
parents:
diff changeset
131 if self._text is not None: # accumulate text
1809e2b05824 Initial revision
fuchita
parents:
diff changeset
132 self._text = self._text + content
1809e2b05824 Initial revision
fuchita
parents:
diff changeset
133
1809e2b05824 Initial revision
fuchita
parents:
diff changeset
134 def getResult(self):
1809e2b05824 Initial revision
fuchita
parents:
diff changeset
135 return self._result
1809e2b05824 Initial revision
fuchita
parents:
diff changeset
136