chiark / gitweb /
Add back the ultimaker platform, and made the platform mesh simpler.
[cura.git] / Cura / slice / cura_sf / fabmetheus_utilities / xml_simple_reader.py
1 """
2 The xml_simple_reader.py script is an xml parser that can parse a line separated xml text.
3
4 This xml parser will read a line seperated xml text and produce a tree of the xml with a document element.  Each element can have an attribute table, childNodes, a class name, parentNode, text and a link to the document element.
5
6 This example gets an xml tree for the xml file boolean.xml.  This example is run in a terminal in the folder which contains boolean.xml and xml_simple_reader.py.
7
8
9 > python
10 Python 2.5.1 (r251:54863, Sep 22 2007, 01:43:31)
11 [GCC 4.2.1 (SUSE Linux)] on linux2
12 Type "help", "copyright", "credits" or "license" for more information.
13 >>> fileName = 'boolean.xml'
14 >>> file = open(fileName, 'r')
15 >>> xmlText = file.read()
16 >>> file.close()
17 >>> from xml_simple_reader import DocumentNode
18 >>> xmlParser = DocumentNode(fileName, xmlText)
19 >>> print(xmlParser)
20   ?xml, {'version': '1.0'}
21   ArtOfIllusion, {'xmlns:bf': '//babelfiche/codec', 'version': '2.0', 'fileversion': '3'}
22   Scene, {'bf:id': 'theScene'}
23   materials, {'bf:elem-type': 'java.lang.Object', 'bf:list': 'collection', 'bf:id': '1', 'bf:type': 'java.util.Vector'}
24 ..
25 many more lines of the xml tree
26 ..
27
28 """
29
30
31 from __future__ import absolute_import
32
33 from fabmetheus_utilities.geometry.geometry_utilities import evaluate
34 from fabmetheus_utilities.geometry.geometry_utilities import matrix
35 from fabmetheus_utilities import archive
36 from fabmetheus_utilities import euclidean
37 from fabmetheus_utilities import xml_simple_writer
38 import cStringIO
39
40
41 __author__ = 'Enrique Perez (perez_enrique@yahoo.com)'
42 __credits__ = 'Nophead <http://hydraraptor.blogspot.com/>\nArt of Illusion <http://www.artofillusion.org/>'
43 __date__ = '$Date: 2008/21/04 $'
44 __license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
45
46
47 globalGetAccessibleAttributeSet = set('getPaths getPreviousVertex getPreviousElementNode getVertexes parentNode'.split())
48
49
50 def createAppendByText(parentNode, xmlText):
51         'Create and append the child nodes from the xmlText.'
52         monad = OpenMonad(parentNode)
53         for character in xmlText:
54                 monad = monad.getNextMonad(character)
55
56 def createAppendByTextb(parentNode, xmlText):
57         'Create and append the child nodes from the xmlText.'
58         monad = OpenMonad(parentNode)
59         for character in xmlText:
60                 monad = monad.getNextMonad(character)
61
62 def getChildElementsByLocalName(childNodes, localName):
63         'Get the childNodes which have the given local name.'
64         childElementsByLocalName = []
65         for childNode in childNodes:
66                 if localName.lower() == childNode.getNodeName():
67                         childElementsByLocalName.append(childNode)
68         return childElementsByLocalName
69
70 def getDocumentNode(fileName):
71         'Get the document from the file name.'
72         xmlText = getFileText('test.xml')
73         return DocumentNode(fileName, xmlText)
74
75 def getElementsByLocalName(childNodes, localName):
76         'Get the descendents which have the given local name.'
77         elementsByLocalName = getChildElementsByLocalName(childNodes, localName)
78         for childNode in childNodes:
79                 if childNode.getNodeType() == 1:
80                         elementsByLocalName += childNode.getElementsByLocalName(localName)
81         return elementsByLocalName
82
83 def getFileText(fileName, printWarning=True, readMode='r'):
84         'Get the entire text of a file.'
85         try:
86                 file = open(fileName, readMode)
87                 fileText = file.read()
88                 file.close()
89                 return fileText
90         except IOError:
91                 if printWarning:
92                         print('The file ' + fileName + ' does not exist.')
93         return ''
94
95
96 class CDATASectionMonad(object):
97         'A monad to handle a CDATASection node.'
98         def __init__(self, input, parentNode):
99                 'Initialize.'
100                 self.input = input
101                 self.parentNode = parentNode
102
103         def getNextMonad(self, character):
104                 'Get the next monad.'
105                 self.input.write(character)
106                 if character == '>':
107                         inputString = self.input.getvalue()
108                         if inputString.endswith(']]>'):
109                                 textContent = '<%s\n' % inputString
110                                 self.parentNode.childNodes.append(CDATASectionNode(self.parentNode, textContent))
111                                 return OpenMonad(self.parentNode)
112                 return self
113
114
115 class CDATASectionNode(object):
116         'A CDATASection node.'
117         def __init__(self, parentNode, textContent=''):
118                 'Initialize.'
119                 self.parentNode = parentNode
120                 self.textContent = textContent
121
122         def __repr__(self):
123                 'Get the string representation of this CDATASection node.'
124                 return self.textContent
125
126         def addToIdentifierDictionaries(self):
127                 'Add the element to the owner document identifier dictionaries.'
128                 pass
129
130         def addXML(self, depth, output):
131                 'Add xml for this CDATASection node.'
132                 output.write(self.textContent)
133
134         def appendSelfToParent(self):
135                 'Append self to the parentNode.'
136                 self.parentNode.appendChild(self)
137
138         def copyXMLChildNodes(self, idSuffix, parentNode):
139                 'Copy the xml childNodes.'
140                 pass
141
142         def getAttributes(self):
143                 'Get the attributes.'
144                 return {}
145
146         def getChildNodes(self):
147                 'Get the empty set.'
148                 return []
149
150         def getCopy(self, idSuffix, parentNode):
151                 'Copy the xml element, set its dictionary and add it to the parentNode.'
152                 copy = self.getCopyShallow()
153                 copy.parentNode = parentNode
154                 copy.appendSelfToParent()
155                 return copy
156
157         def getCopyShallow(self, attributes=None):
158                 'Copy the node and set its parentNode.'
159                 return CDATASectionNode(self.parentNode, self.textContent)
160
161         def getNodeName(self):
162                 'Get the node name.'
163                 return '#cdata-section'
164
165         def getNodeType(self):
166                 'Get the node type.'
167                 return 4
168
169         def getOwnerDocument(self):
170                 'Get the owner document.'
171                 return self.parentNode.getOwnerDocument()
172
173         def getTextContent(self):
174                 'Get the text content.'
175                 return self.textContent
176
177         def removeChildNodesFromIDNameParent(self):
178                 'Remove the childNodes from the id and name dictionaries and the childNodes.'
179                 pass
180
181         def removeFromIDNameParent(self):
182                 'Remove this from the id and name dictionaries and the childNodes of the parentNode.'
183                 if self.parentNode != None:
184                         self.parentNode.childNodes.remove(self)
185
186         def setParentAddToChildNodes(self, parentNode):
187                 'Set the parentNode and add this to its childNodes.'
188                 self.parentNode = parentNode
189                 if self.parentNode != None:
190                         self.parentNode.childNodes.append(self)
191
192         attributes = property(getAttributes)
193         childNodes = property(getChildNodes)
194         nodeName = property(getNodeName)
195         nodeType = property(getNodeType)
196         ownerDocument = property(getOwnerDocument)
197
198
199 class CommentMonad(CDATASectionMonad):
200         'A monad to handle a comment node.'
201         def getNextMonad(self, character):
202                 'Get the next monad.'
203                 self.input.write(character)
204                 if character == '>':
205                         inputString = self.input.getvalue()
206                         if inputString.endswith('-->'):
207                                 textContent = '<%s\n' % inputString
208                                 self.parentNode.childNodes.append(CommentNode(self.parentNode, textContent))
209                                 return OpenMonad(self.parentNode)
210                 return self
211
212
213 class CommentNode(CDATASectionNode):
214         'A comment node.'
215         def getCopyShallow(self, attributes=None):
216                 'Copy the node and set its parentNode.'
217                 return CommentNode(self.parentNode, self.textContent)
218
219         def getNodeName(self):
220                 'Get the node name.'
221                 return '#comment'
222
223         def getNodeType(self):
224                 'Get the node type.'
225                 return 8
226
227         nodeName = property(getNodeName)
228         nodeType = property(getNodeType)
229
230
231 class DocumentNode(object):
232         'A class to parse an xml text and store the elements.'
233         def __init__(self, fileName, xmlText):
234                 'Initialize.'
235                 self.childNodes = []
236                 self.fileName = fileName
237                 self.idDictionary = {}
238                 self.nameDictionary = {}
239                 self.parentNode = None
240                 self.tagDictionary = {}
241                 self.xmlText = xmlText
242                 createAppendByText(self, xmlText)
243
244         def __repr__(self):
245                 'Get the string representation of this xml document.'
246                 output = cStringIO.StringIO()
247                 for childNode in self.childNodes:
248                         childNode.addXML(0, output)
249                 return output.getvalue()
250
251         def appendChild(self, elementNode):
252                 'Append child elementNode to the child nodes.'
253                 self.childNodes.append(elementNode)
254                 elementNode.addToIdentifierDictionaries()
255                 return elementNode
256
257         def getAttributes(self):
258                 'Get the attributes.'
259                 return {}
260
261         def getCascadeBoolean(self, defaultBoolean, key):
262                 'Get the cascade boolean.'
263                 return defaultBoolean
264
265         def getCascadeFloat(self, defaultFloat, key):
266                 'Get the cascade float.'
267                 return defaultFloat
268
269         def getDocumentElement(self):
270                 'Get the document element.'
271                 if len(self.childNodes) == 0:
272                         return None
273                 return self.childNodes[-1]
274
275         def getElementsByLocalName(self, localName):
276                 'Get the descendents which have the given local name.'
277                 return getElementsByLocalName(self.childNodes, localName)
278
279         def getImportNameChain(self, suffix=''):
280                 'Get the import name chain with the suffix at the end.'
281                 return suffix
282
283         def getNodeName(self):
284                 'Get the node name.'
285                 return '#document'
286
287         def getNodeType(self):
288                 'Get the node type.'
289                 return 9
290
291         def getOriginalRoot(self):
292                 'Get the original reparsed document element.'
293                 if evaluate.getEvaluatedBoolean(True, self.documentElement, 'getOriginalRoot'):
294                         return DocumentNode(self.fileName, self.xmlText).documentElement
295                 return None
296
297         def getOwnerDocument(self):
298                 'Get the owner document.'
299                 return self
300
301         attributes = property(getAttributes)
302         documentElement = property(getDocumentElement)
303         nodeName = property(getNodeName)
304         nodeType = property(getNodeType)
305         ownerDocument = property(getOwnerDocument)
306
307
308 class DocumentTypeMonad(CDATASectionMonad):
309         'A monad to handle a document type node.'
310         def getNextMonad(self, character):
311                 'Get the next monad.'
312                 self.input.write(character)
313                 if character == '>':
314                         inputString = self.input.getvalue()
315                         if inputString.endswith('?>'):
316                                 textContent = '%s\n' % inputString
317                                 self.parentNode.childNodes.append(DocumentTypeNode(self.parentNode, textContent))
318                                 return OpenMonad(self.parentNode)
319                 return self
320
321
322 class DocumentTypeNode(CDATASectionNode):
323         'A document type node.'
324         def getCopyShallow(self, attributes=None):
325                 'Copy the node and set its parentNode.'
326                 return DocumentTypeNode(self.parentNode, self.textContent)
327
328         def getNodeName(self):
329                 'Get the node name.'
330                 return '#forNowDocumentType'
331
332         def getNodeType(self):
333                 'Get the node type.'
334                 return 10
335
336         nodeName = property(getNodeName)
337         nodeType = property(getNodeType)
338
339
340 class ElementEndMonad(object):
341         'A monad to look for the end of an ElementNode tag.'
342         def __init__(self, parentNode):
343                 'Initialize.'
344                 self.parentNode = parentNode
345
346         def getNextMonad(self, character):
347                 'Get the next monad.'
348                 if character == '>':
349                         return TextMonad(self.parentNode)
350                 return self
351
352
353 class ElementLocalNameMonad(object):
354         'A monad to set the local name of an ElementNode.'
355         def __init__(self, character, parentNode):
356                 'Initialize.'
357                 self.input = cStringIO.StringIO()
358                 self.input.write(character)
359                 self.parentNode = parentNode
360
361         def getNextMonad(self, character):
362                 'Get the next monad.'
363                 if character == '[':
364                         if (self.input.getvalue() + character).startswith('![CDATA['):
365                                 self.input.write(character)
366                                 return CDATASectionMonad(self.input, self.parentNode)
367                 if character == '-':
368                         if (self.input.getvalue() + character).startswith('!--'):
369                                 self.input.write(character)
370                                 return CommentMonad(self.input, self.parentNode)
371                 if character.isspace():
372                         self.setLocalName()
373                         return ElementReadMonad(self.elementNode)
374                 if character == '/':
375                         self.setLocalName()
376                         self.elementNode.appendSelfToParent()
377                         return ElementEndMonad(self.elementNode.parentNode)
378                 if character == '>':
379                         self.setLocalName()
380                         self.elementNode.appendSelfToParent()
381                         return TextMonad(self.elementNode)
382                 self.input.write(character)
383                 return self
384
385         def setLocalName(self):
386                 'Set the class name.'
387                 self.elementNode = ElementNode(self.parentNode)
388                 self.elementNode.localName = self.input.getvalue().lower().strip()
389
390
391 class ElementNode(object):
392         'An xml element.'
393         def __init__(self, parentNode=None):
394                 'Initialize.'
395                 self.attributes = {}
396                 self.childNodes = []
397                 self.localName = ''
398                 self.parentNode = parentNode
399                 self.xmlObject = None
400
401         def __repr__(self):
402                 'Get the string representation of this xml document.'
403                 return '%s\n%s\n%s' % (self.localName, self.attributes, self.getTextContent())
404
405         def _getAccessibleAttribute(self, attributeName):
406                 'Get the accessible attribute.'
407                 global globalGetAccessibleAttributeSet
408                 if attributeName in globalGetAccessibleAttributeSet:
409                         return getattr(self, attributeName, None)
410                 return None
411
412         def addSuffixToID(self, idSuffix):
413                 'Add the suffix to the id.'
414                 if 'id' in self.attributes:
415                         self.attributes['id'] += idSuffix
416
417         def addToIdentifierDictionaries(self):
418                 'Add the element to the owner document identifier dictionaries.'
419                 ownerDocument = self.getOwnerDocument()
420                 importNameChain = self.getImportNameChain()
421                 idKey = self.getStrippedAttributesValue('id')
422                 if idKey != None:
423                         ownerDocument.idDictionary[importNameChain + idKey] = self
424                 nameKey = self.getStrippedAttributesValue('name')
425                 if nameKey != None:
426                         euclidean.addElementToListDictionaryIfNotThere(self, importNameChain + nameKey, ownerDocument.nameDictionary)
427                 for tagKey in self.getTagKeys():
428                         euclidean.addElementToListDictionaryIfNotThere(self, tagKey, ownerDocument.tagDictionary)
429
430         def addXML(self, depth, output):
431                 'Add xml for this elementNode.'
432                 innerOutput = cStringIO.StringIO()
433                 xml_simple_writer.addXMLFromObjects(depth + 1, self.childNodes, innerOutput)
434                 innerText = innerOutput.getvalue()
435                 xml_simple_writer.addBeginEndInnerXMLTag(self.attributes, depth, innerText, self.localName, output, self.getTextContent())
436
437         def appendChild(self, elementNode):
438                 'Append child elementNode to the child nodes.'
439                 self.childNodes.append(elementNode)
440                 elementNode.addToIdentifierDictionaries()
441                 return elementNode
442
443         def appendSelfToParent(self):
444                 'Append self to the parentNode.'
445                 self.parentNode.appendChild(self)
446
447         def copyXMLChildNodes(self, idSuffix, parentNode):
448                 'Copy the xml childNodes.'
449                 for childNode in self.childNodes:
450                         childNode.getCopy(idSuffix, parentNode)
451
452         def getCascadeBoolean(self, defaultBoolean, key):
453                 'Get the cascade boolean.'
454                 if key in self.attributes:
455                         value = evaluate.getEvaluatedBoolean(None, self, key)
456                         if value != None:
457                                 return value
458                 return self.parentNode.getCascadeBoolean(defaultBoolean, key)
459
460         def getCascadeFloat(self, defaultFloat, key):
461                 'Get the cascade float.'
462                 if key in self.attributes:
463                         value = evaluate.getEvaluatedFloat(None, self, key)
464                         if value != None:
465                                 return value
466                 return self.parentNode.getCascadeFloat(defaultFloat, key)
467
468         def getChildElementsByLocalName(self, localName):
469                 'Get the childNodes which have the given local name.'
470                 return getChildElementsByLocalName(self.childNodes, localName)
471
472         def getCopy(self, idSuffix, parentNode):
473                 'Copy the xml element, set its dictionary and add it to the parentNode.'
474                 matrix4X4 = matrix.getBranchMatrixSetElementNode(self)
475                 attributesCopy = self.attributes.copy()
476                 attributesCopy.update(matrix4X4.getAttributes('matrix.'))
477                 copy = self.getCopyShallow(attributesCopy)
478                 copy.setParentAddToChildNodes(parentNode)
479                 copy.addSuffixToID(idSuffix)
480                 copy.addToIdentifierDictionaries()
481                 self.copyXMLChildNodes(idSuffix, copy)
482                 return copy
483
484         def getCopyShallow(self, attributes=None):
485                 'Copy the xml element and set its dictionary and parentNode.'
486                 if attributes == None: # to evade default initialization bug where a dictionary is initialized to the last dictionary
487                         attributes = {}
488                 copyShallow = ElementNode(self.parentNode)
489                 copyShallow.attributes = attributes
490                 copyShallow.localName = self.localName
491                 return copyShallow
492
493         def getDocumentElement(self):
494                 'Get the document element.'
495                 return self.getOwnerDocument().getDocumentElement()
496
497         def getElementNodeByID(self, idKey):
498                 'Get the xml element by id.'
499                 idDictionary = self.getOwnerDocument().idDictionary
500                 idKey = self.getImportNameChain() + idKey
501                 if idKey in idDictionary:
502                         return idDictionary[idKey]
503                 return None
504
505         def getElementNodesByName(self, nameKey):
506                 'Get the xml elements by name.'
507                 nameDictionary = self.getOwnerDocument().nameDictionary
508                 nameKey = self.getImportNameChain() + nameKey
509                 if nameKey in nameDictionary:
510                         return nameDictionary[nameKey]
511                 return None
512
513         def getElementNodesByTag(self, tagKey):
514                 'Get the xml elements by tag.'
515                 tagDictionary = self.getOwnerDocument().tagDictionary
516                 if tagKey in tagDictionary:
517                         return tagDictionary[tagKey]
518                 return None
519
520         def getElementsByLocalName(self, localName):
521                 'Get the descendents which have the given local name.'
522                 return getElementsByLocalName(self.childNodes, localName)
523
524         def getFirstChildByLocalName(self, localName):
525                 'Get the first childNode which has the given class name.'
526                 for childNode in self.childNodes:
527                         if localName.lower() == childNode.getNodeName():
528                                 return childNode
529                 return None
530
531         def getIDSuffix(self, elementIndex=None):
532                 'Get the id suffix from the dictionary.'
533                 suffix = self.localName
534                 if 'id' in self.attributes:
535                         suffix = self.attributes['id']
536                 if elementIndex == None:
537                         return '_%s' % suffix
538                 return '_%s_%s' % (suffix, elementIndex)
539
540         def getImportNameChain(self, suffix=''):
541                 'Get the import name chain with the suffix at the end.'
542                 importName = self.getStrippedAttributesValue('_importName')
543                 if importName != None:
544                         suffix = '%s.%s' % (importName, suffix)
545                 return self.parentNode.getImportNameChain(suffix)
546
547         def getNodeName(self):
548                 'Get the node name.'
549                 return self.localName
550
551         def getNodeType(self):
552                 'Get the node type.'
553                 return 1
554
555         def getOwnerDocument(self):
556                 'Get the owner document.'
557                 return self.parentNode.getOwnerDocument()
558
559         def getParser(self):
560                 'Get the parser.'
561                 return self.getOwnerDocument()
562
563         def getPaths(self):
564                 'Get all paths.'
565                 if self.xmlObject == None:
566                         return []
567                 return self.xmlObject.getPaths()
568
569         def getPreviousElementNode(self):
570                 'Get previous ElementNode if it exists.'
571                 if self.parentNode == None:
572                         return None
573                 previousElementNodeIndex = self.parentNode.childNodes.index(self) - 1
574                 if previousElementNodeIndex < 0:
575                         return None
576                 return self.parentNode.childNodes[previousElementNodeIndex]
577
578         def getPreviousVertex(self, defaultVector3=None):
579                 'Get previous vertex if it exists.'
580                 if self.parentNode == None:
581                         return defaultVector3
582                 if self.parentNode.xmlObject == None:
583                         return defaultVector3
584                 if len(self.parentNode.xmlObject.vertexes) < 1:
585                         return defaultVector3
586                 return self.parentNode.xmlObject.vertexes[-1]
587
588         def getStrippedAttributesValue(self, keyString):
589                 'Get the stripped attribute value if the length is at least one, otherwise return None.'
590                 if keyString in self.attributes:
591                         strippedAttributesValue = self.attributes[keyString].strip()
592                         if len(strippedAttributesValue) > 0:
593                                 return strippedAttributesValue
594                 return None
595
596         def getSubChildWithID( self, idReference ):
597                 'Get the childNode which has the idReference.'
598                 for childNode in self.childNodes:
599                         if 'bf:id' in childNode.attributes:
600                                 if childNode.attributes['bf:id'] == idReference:
601                                         return childNode
602                         subChildWithID = childNode.getSubChildWithID( idReference )
603                         if subChildWithID != None:
604                                 return subChildWithID
605                 return None
606
607         def getTagKeys(self):
608                 'Get stripped tag keys.'
609                 if 'tags' not in self.attributes:
610                         return []
611                 tagKeys = []
612                 tagString = self.attributes['tags']
613                 if tagString.startswith('='):
614                         tagString = tagString[1 :]
615                 if tagString.startswith('['):
616                         tagString = tagString[1 :]
617                 if tagString.endswith(']'):
618                         tagString = tagString[: -1]
619                 for tagWord in tagString.split(','):
620                         tagKey = tagWord.strip()
621                         if tagKey != '':
622                                 tagKeys.append(tagKey)
623                 return tagKeys
624
625         def getTextContent(self):
626                 'Get the text from the child nodes.'
627                 if len(self.childNodes) == 0:
628                         return ''
629                 firstNode = self.childNodes[0]
630                 if firstNode.nodeType == 3:
631                         return firstNode.textContent
632                 return ''
633
634         def getValueByKey( self, key ):
635                 'Get value by the key.'
636                 if key in evaluate.globalElementValueDictionary:
637                         return evaluate.globalElementValueDictionary[key](self)
638                 if key in self.attributes:
639                         return evaluate.getEvaluatedLinkValue(self, self.attributes[key])
640                 return None
641
642         def getVertexes(self):
643                 'Get the vertexes.'
644                 if self.xmlObject == None:
645                         return []
646                 return self.xmlObject.getVertexes()
647
648         def getXMLProcessor(self):
649                 'Get the xmlProcessor.'
650                 return self.getDocumentElement().xmlProcessor
651
652         def linkObject(self, xmlObject):
653                 'Link self to xmlObject and add xmlObject to archivableObjects.'
654                 self.xmlObject = xmlObject
655                 self.xmlObject.elementNode = self
656                 self.parentNode.xmlObject.archivableObjects.append(self.xmlObject)
657
658         def printAllVariables(self):
659                 'Print all variables.'
660                 print('attributes')
661                 print(self.attributes)
662                 print('childNodes')
663                 print(self.childNodes)
664                 print('localName')
665                 print(self.localName)
666                 print('parentNode')
667                 print(self.parentNode.getNodeName())
668                 print('text')
669                 print(self.getTextContent())
670                 print('xmlObject')
671                 print(self.xmlObject)
672                 print('')
673
674         def printAllVariablesRoot(self):
675                 'Print all variables and the document element variables.'
676                 self.printAllVariables()
677                 documentElement = self.getDocumentElement()
678                 if documentElement != None:
679                         print('')
680                         print('Root variables:')
681                         documentElement.printAllVariables()
682
683         def removeChildNodesFromIDNameParent(self):
684                 'Remove the childNodes from the id and name dictionaries and the childNodes.'
685                 childNodesCopy = self.childNodes[:]
686                 for childNode in childNodesCopy:
687                         childNode.removeFromIDNameParent()
688
689         def removeFromIDNameParent(self):
690                 'Remove this from the id and name dictionaries and the childNodes of the parentNode.'
691                 self.removeChildNodesFromIDNameParent()
692                 idKey = self.getStrippedAttributesValue('id')
693                 if idKey != None:
694                         idDictionary = self.getOwnerDocument().idDictionary
695                         idKey = self.getImportNameChain() + idKey
696                         if idKey in idDictionary:
697                                 del idDictionary[idKey]
698                 nameKey = self.getStrippedAttributesValue('name')
699                 if nameKey != None:
700                         euclidean.removeElementFromListTable(self, self.getImportNameChain() + nameKey, self.getOwnerDocument().nameDictionary)
701                 for tagKey in self.getTagKeys():
702                         euclidean.removeElementFromListTable(self, tagKey, self.getOwnerDocument().tagDictionary)
703                 if self.parentNode != None:
704                         self.parentNode.childNodes.remove(self)
705
706         def setParentAddToChildNodes(self, parentNode):
707                 'Set the parentNode and add this to its childNodes.'
708                 self.parentNode = parentNode
709                 if self.parentNode != None:
710                         self.parentNode.childNodes.append(self)
711
712         def setTextContent(self, textContent=''):
713                 'Get the text from the child nodes.'
714                 if len(self.childNodes) == 0:
715                         self.childNodes.append(TextNode(self, textContent))
716                         return
717                 firstNode = self.childNodes[0]
718                 if firstNode.nodeType == 3:
719                         firstNode.textContent = textContent
720                 self.childNodes.append(TextNode(self, textContent))
721
722         nodeName = property(getNodeName)
723         nodeType = property(getNodeType)
724         ownerDocument = property(getOwnerDocument)
725         textContent = property(getTextContent)
726
727
728 class ElementReadMonad(object):
729         'A monad to read the attributes of the ElementNode tag.'
730         def __init__(self, elementNode):
731                 'Initialize.'
732                 self.elementNode = elementNode
733
734         def getNextMonad(self, character):
735                 'Get the next monad.'
736                 if character.isspace():
737                         return self
738                 if character == '/':
739                         self.elementNode.appendSelfToParent()
740                         return ElementEndMonad(self.elementNode.parentNode)
741                 if character == '>':
742                         self.elementNode.appendSelfToParent()
743                         return TextMonad(self.elementNode)
744                 return KeyMonad(character, self.elementNode)
745
746
747 class KeyMonad(object):
748         'A monad to set the key of an attribute of an ElementNode.'
749         def __init__(self, character, elementNode):
750                 'Initialize.'
751                 self.input = cStringIO.StringIO()
752                 self.input.write(character)
753                 self.elementNode = elementNode
754
755         def getNextMonad(self, character):
756                 'Get the next monad.'
757                 if character == '=':
758                         return ValueMonad(self.elementNode, self.input.getvalue().strip())
759                 self.input.write(character)
760                 return self
761
762
763 class OpenChooseMonad(ElementEndMonad):
764         'A monad to choose the next monad.'
765         def getNextMonad(self, character):
766                 'Get the next monad.'
767                 if character.isspace():
768                         return self
769                 if character == '?':
770                         input = cStringIO.StringIO()
771                         input.write('<?')
772                         return DocumentTypeMonad(input, self.parentNode)
773                 if character == '/':
774                         return ElementEndMonad(self.parentNode.parentNode)
775                 return ElementLocalNameMonad(character, self.parentNode)
776
777
778 class OpenMonad(ElementEndMonad):
779         'A monad to handle the open tag character.'
780         def getNextMonad(self, character):
781                 'Get the next monad.'
782                 if character == '<':
783                         return OpenChooseMonad(self.parentNode)
784                 return self
785
786
787 class TextMonad(object):
788         'A monad to handle the open tag character and set the text.'
789         def __init__(self, parentNode):
790                 'Initialize.'
791                 self.input = cStringIO.StringIO()
792                 self.parentNode = parentNode
793
794         def getNextMonad(self, character):
795                 'Get the next monad.'
796                 if character == '<':
797                         inputString = self.input.getvalue().strip()
798                         if len(inputString) > 0:
799                                 self.parentNode.childNodes.append(TextNode(self.parentNode, inputString))
800                         return OpenChooseMonad(self.parentNode)
801                 self.input.write(character)
802                 return self
803
804
805 class TextNode(CDATASectionNode):
806         'A text node.'
807         def addXML(self, depth, output):
808                 'Add xml for this text node.'
809                 pass
810
811         def getCopyShallow(self, attributes=None):
812                 'Copy the node and set its parentNode.'
813                 return TextNode(self.parentNode, self.textContent)
814
815         def getNodeName(self):
816                 'Get the node name.'
817                 return '#text'
818
819         def getNodeType(self):
820                 'Get the node type.'
821                 return 3
822
823         nodeName = property(getNodeName)
824         nodeType = property(getNodeType)
825
826
827 class ValueMonad(object):
828         'A monad to set the value of an attribute of an ElementNode.'
829         def __init__(self, elementNode, key):
830                 'Initialize.'
831                 self.elementNode = elementNode
832                 self.input = cStringIO.StringIO()
833                 self.key = key
834                 self.quoteCharacter = None
835
836         def getNextMonad(self, character):
837                 'Get the next monad.'
838                 if self.quoteCharacter == None:
839                         if character == '"' or character == "'":
840                                 self.quoteCharacter = character
841                         return self
842                 if self.quoteCharacter == character:
843                         self.elementNode.attributes[self.key] = self.input.getvalue()
844                         return ElementReadMonad(self.elementNode)
845                 self.input.write(character)
846                 return self
847