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