00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040 __author__ = "Roland Leuthe <roland@leuthe-net.de>"
00041 __date__ = "08. August 2008"
00042 __version__ = "0.9.0"
00043
00044 import string
00045 import os
00046 import re
00047 import copy
00048 from types import TupleType, StringTypes
00049 from xml.dom import EMPTY_PREFIX, EMPTY_NAMESPACE
00050 from xmlifUtils import processWhitespaceAction, NsNameTupleFactory, splitQName, nsNameToQName, escapeCdata, escapeAttribute
00051
00052
00053
00054
00055
00056
00057
00058 class XmlInterfaceBase:
00059 """XML interface base class.
00060
00061 All not implemented methods have to be overloaded by the derived class!!
00062 """
00063
00064 def __init__(self, verbose, useCaching, processXInclude):
00065 """Constructor of class XmlInterfaceBase.
00066
00067 Input parameter:
00068 'verbose': 0 or 1: controls verbose print output for module genxmlif
00069 'useCaching': 0 or 1: controls usage of caching for module genxmlif
00070 'processXInclude': 0 or 1: controls XInclude processing during parsing
00071 """
00072
00073 self.verbose = verbose
00074 self.useCaching = useCaching
00075 self.processXInclude = processXInclude
00076
00077
00078 self.setTreeWrapperClass (XmlTreeWrapper)
00079 self.setElementWrapperClass (XmlElementWrapper)
00080
00081
00082 def createXmlTree (self, namespace, xmlRootTagName, attributeDict={}, publicId=None, systemId=None):
00083 """Create a new XML TreeWrapper object (wrapper for DOM document or elementtree).
00084
00085 Input parameter:
00086 'namespace': not yet handled (for future use)
00087 'xmlRootTagName': specifies the tag name of the root element
00088 'attributeDict': contains the attributes of the root node (optional)
00089 'publicId': forwarded to contained DOM tree (unused for elementtree)
00090 'systemId': forwarded to contained DOM tree (unused for elementtree)
00091 Returns the created XML tree wrapper object.
00092 Method has to be implemented by derived classes!
00093 """
00094
00095 raise NotImplementedError
00096
00097
00098 def parse (self, filePath, baseUrl="", ownerDoc=None):
00099 """Call the XML parser for 'file'.
00100
00101 Input parameter:
00102 'filePath': a file path or an URI
00103 'baseUrl': if specified, it is used e.g. as base path for schema files referenced inside the XML file.
00104 'ownerDoc': only used in case of 4DOM (forwarded to 4DOM parser).
00105 Returns the respective XML tree wrapper object for the parsed XML file.
00106 Method has to be implemented by derived classes!
00107 """
00108
00109 raise NotImplementedError
00110
00111
00112 def parseString (self, text, baseUrl="", ownerDoc=None):
00113 """Call the XML parser for 'text'.
00114
00115 Input parameter:
00116 'text': contains the XML string to be parsed
00117 'baseUrl': if specified, it is used e.g. as base path for schema files referenced inside the XML string.
00118 'ownerDoc': only used in case of 4DOM (forwarded to 4DOM parser).
00119 Returns the respective XML tree wrapper object for the parsed XML 'text' string.
00120 Method has to be implemented by derived classes!
00121 """
00122 raise NotImplementedError
00123
00124
00125 def setTreeWrapperClass (self, treeWrapperClass):
00126 """Set the tree wrapper class which shall be used by this interface.
00127
00128 Input parameter:
00129 treeWrapperClass: tree wrapper class
00130 """
00131 self.treeWrapperClass = treeWrapperClass
00132
00133
00134 def setElementWrapperClass (self, elementWrapperClass):
00135 """Set the element wrapper classes which shall be used by this interface.
00136
00137 Input parameter:
00138 elementWrapperClass: element wrapper class
00139 """
00140 self.elementWrapperClass = elementWrapperClass
00141
00142
00143 def getXmlIfType (self):
00144 """Retrieve the type of the XML interface."""
00145 return self.xmlIfType
00146
00147
00148
00149
00150
00151
00152 class XmlTreeWrapper:
00153 """XML tree wrapper API.
00154
00155 Contains a DOM tree or an elementtree (depending on used XML parser)
00156 """
00157
00158 def __init__(self, xmlIf, tree, useCaching):
00159 """Constructor of wrapper class XmlTreeWrapper.
00160
00161 Input parameter:
00162 'xmlIf': used XML interface class
00163 'tree': DOM tree or elementtree which is wrapped by this object
00164 'useCaching': 1 if caching shall be used inside genxmlif, otherwise 0
00165 """
00166 self.xmlIf = xmlIf
00167 self.__tree = tree
00168 self.__useCaching = useCaching
00169
00170
00171 def createElement (self, tupleOrLocalName, attributeDict=None, curNs=[]):
00172 """Create an ElementWrapper object.
00173
00174 Input parameter:
00175 tupleOrLocalName: tag name of element node to be created
00176 (tuple of namespace and localName or only localName if no namespace is used)
00177 attributeDict: attributes for this elements
00178 curNs: namespaces for scope of this element
00179 Returns an ElementWrapper object containing the created element node.
00180 """
00181 nsName = NsNameTupleFactory(tupleOrLocalName)
00182 elementNode = self.__tree.xmlIfExtCreateElement(nsName, attributeDict, curNs)
00183 return self.xmlIf.elementWrapperClass(elementNode, self, curNs)
00184
00185
00186 def cloneTree (self):
00187 """Creates a copy of a whole XML DOM tree."""
00188 rootElementWrapperCopy = self.getRootNode().cloneNode(deep=1)
00189 treeWrapperCopy = self.__class__(self.xmlIf,
00190 self.__tree.xmlIfExtCloneTree(rootElementWrapperCopy.element),
00191 self.__useCaching)
00192 for elementWrapper in rootElementWrapperCopy.getIterator():
00193 elementWrapper.treeWrapper = treeWrapperCopy
00194 return treeWrapperCopy
00195
00196
00197 def getRootNode (self):
00198 """Retrieve the wrapper object of the root element of the contained XML tree.
00199
00200 Returns the ElementWrapper object of the root element.
00201 """
00202 return self.__tree.xmlIfExtGetRootNode().xmlIfExtElementWrapper
00203
00204
00205 def getTree (self):
00206 """Retrieve the contained XML tree.
00207
00208 Returns the contained XML tree object (internal DOM tree wrapper or elementtree).
00209 """
00210 return self.__tree
00211
00212
00213 def printTree (self, prettyPrint=0, printElementValue=1, encoding=None):
00214 """Return the string representation of the contained XML tree.
00215
00216 Input parameter:
00217 'prettyPrint': aligns the columns of the attributes of childNodes
00218 'printElementValue': controls if the lement values are printed or not.
00219 Returns a string with the string representation of the whole XML tree.
00220 """
00221 if not encoding:
00222 encoding = "utf-8"
00223 if encoding != "utf-8" and encoding != "us-ascii":
00224 text = "<?xml version='1.0' encoding='%s'?>\n" % encoding
00225 else:
00226 text = ""
00227 return text + self.getRootNode().printNode(deep=1, prettyPrint=prettyPrint, printElementValue=printElementValue, encoding=encoding)
00228
00229
00230 def useCaching (self):
00231 """Return 1 if caching should be used for the contained XML tree."""
00232 return self.__useCaching
00233
00234
00235 def setExternalCacheUsage (self, used):
00236 """Set external cache usage for the whole tree
00237 unlink commands are ignored if used by an external cache
00238
00239 Input parameter:
00240 used: 0 or 1 (used by external cache)
00241 """
00242 self.getRootNode().setExternalCacheUsage (used, deep=1)
00243
00244
00245 def unlink (self):
00246 """Break circular references of the complete XML tree.
00247
00248 To be called if the XML tree is not longer used => garbage collection!
00249 """
00250 self.getRootNode().unlink()
00251
00252
00253 def __str__ (self):
00254 """Return the string representation of the contained XML tree."""
00255 return self.printTree()
00256
00257
00258
00259
00260
00261
00262
00263 class XmlElementWrapper:
00264 """XML element wrapper API.
00265
00266 Contains a XML element node
00267 All not implemented methods have to be overloaded by the derived class!!
00268 """
00269
00270 def __init__(self, element, treeWrapper, curNs=[], initAttrSeq=1):
00271 """Constructor of wrapper class XmlElementWrapper.
00272
00273 Input parameter:
00274 element: XML element node which is wrapped by this object
00275 treeWrapper: XML tree wrapper class the current element belongs to
00276 curNs: namespaces for scope of this element
00277 """
00278 self.element = element
00279 self.element.xmlIfExtElementWrapper = self
00280 self.treeWrapper = treeWrapper
00281 self.nodeUsedByExternalCache = 0
00282
00283 if self.__useCaching():
00284 self.__childrenCache = {}
00285 self.__firstChildCache = {}
00286 self.__qNameAttrCache = {}
00287
00288 self.baseUrl = None
00289 self.absUrl = None
00290 self.filePath = None
00291 self.startLineNumber = None
00292 self.endLineNumber = None
00293 self.curNs = curNs[:]
00294 self.attributeSequence = []
00295
00296 if initAttrSeq:
00297 self.attributeSequence = self.getAttributeDict().keys()
00298
00299
00300 def unlink (self):
00301 """Break circular references of this element and its children."""
00302 for childWrapper in self.getChildren():
00303 childWrapper.unlink()
00304 if not self.isUsedByExternalCache():
00305 self.element.xmlIfExtUnlink()
00306
00307
00308 def cloneNode (self, deep, cloneCallback=None):
00309 """Create a copy of the current element wrapper.
00310 The reference to the parent node is set to None!"""
00311 elementCopy = self.element.xmlIfExtCloneNode()
00312 elementWrapperCopy = self.__class__(elementCopy, self.treeWrapper, initAttrSeq=0)
00313 elementWrapperCopy.treeWrapper = None
00314 elementWrapperCopy.baseUrl = self.baseUrl
00315 elementWrapperCopy.absUrl = self.absUrl
00316 elementWrapperCopy.filePath = self.filePath
00317 elementWrapperCopy.startLineNumber = self.startLineNumber
00318 elementWrapperCopy.endLineNumber = self.endLineNumber
00319 elementWrapperCopy.curNs = self.curNs[:]
00320 elementWrapperCopy.attributeSequence = self.attributeSequence[:]
00321 if cloneCallback: cloneCallback(elementWrapperCopy)
00322 if deep:
00323 for childElement in self.element.xmlIfExtGetChildren():
00324 childWrapperElementCopy = childElement.xmlIfExtElementWrapper.cloneNode(deep, cloneCallback)
00325 childWrapperElementCopy.element.xmlIfExtSetParentNode(elementWrapperCopy.element)
00326 elementWrapperCopy.element.xmlIfExtAppendChild(childWrapperElementCopy.element)
00327 return elementWrapperCopy
00328
00329
00330 def clearNodeCache (self):
00331 """Clear all caches used by this element wrapper which contains element wrapper references."""
00332 self.__clearChildrenCache()
00333
00334
00335 def isUsedByExternalCache (self):
00336 """Check if this node is used by an external cache.
00337 unlink commands are ignored if used by an external cache"""
00338 return self.nodeUsedByExternalCache
00339
00340
00341 def setExternalCacheUsage (self, used, deep=1):
00342 """Set external cache usage for this node and its children
00343 unlink commands are ignored if used by an external cache
00344
00345 Input parameter:
00346 used: 0 or 1 (used by external cache)
00347 deep: 0 or 1: controls if the child elements are also marked as used by external cache
00348 """
00349 self.nodeUsedByExternalCache = used
00350 if deep:
00351 for childWrapper in self.getChildren():
00352 childWrapper.setExternalCacheUsage (used, deep)
00353
00354
00355
00356
00357
00358
00359 def __getitem__(self, tupleOrAttrName):
00360 """Attributes of the contained element node can be accessed via key operator.
00361
00362 Input parameter:
00363 tupleOrAttrName: name of the attribute (tuple of namespace and attributeName or only attributeName)
00364 Returns the attribute value.
00365 """
00366 attrValue = self.getAttribute (tupleOrAttrName)
00367 if attrValue != None:
00368 return attrValue
00369 else:
00370 raise AttributeError, "Attribute %s not found!" %(repr(tupleOrAttrName))
00371
00372
00373 def __setitem__(self, tupleOrAttrName, attributeValue):
00374 """Attributes of the contained element node can be accessed via key operator.
00375
00376 Input parameter:
00377 tupleOrAttrName: name of the attribute (tuple of namespace and attributeName or only attributeName)
00378 attributeValue: attribute value to be set
00379 """
00380 self.setAttribute (tupleOrAttrName, attributeValue)
00381
00382
00383
00384
00385 def getTagName (self):
00386 """Retrieve the (complete) tag name of the contained element node
00387
00388 Returns the (complete) tag name of the contained element node
00389 """
00390 return self.element.xmlIfExtGetTagName()
00391
00392
00393 def getLocalName (self):
00394 """Retrieve the local name (without namespace) of the contained element node
00395
00396 Returns the local name (without namespace) of the contained element node
00397 """
00398
00399 try:
00400 return self.__localNameCache
00401 except:
00402 prefix, localName = splitQName (self.getTagName())
00403 if self.__useCaching():
00404 self.__localNameCache = localName
00405 return localName
00406
00407
00408 def getNamespaceURI (self):
00409 """Retrieve the namespace URI of the contained element node
00410
00411 Returns the namespace URI of the contained element node (None if no namespace is used).
00412 """
00413 try:
00414 return self.__nsUriCache
00415 except:
00416 prefix = self.element.xmlIfExtGetNamespaceURI()
00417 if self.__useCaching():
00418 self.__nsUriCache = prefix
00419 return prefix
00420
00421
00422 def getNsName (self):
00423 """Retrieve a tuple (namespace, localName) of the contained element node
00424
00425 Returns a tuple (namespace, localName) of the contained element node (namespace is None if no namespace is used).
00426 """
00427 try:
00428 return self.__nsNameCache
00429 except:
00430 nsName = NsNameTupleFactory( (self.getNamespaceURI(), self.getLocalName()) )
00431 if self.__useCaching():
00432 self.__nsNameCache = nsName
00433 return nsName
00434
00435
00436 def getQName (self):
00437 """Retrieve a string prefix and localName of the contained element node
00438
00439 Returns a string "prefix:localName" of the contained element node
00440 """
00441 return self.nsName2QName(self.getNsName())
00442
00443
00444 def getPrefix (self):
00445 """Retrieve the namespace prefix of the contained element node
00446
00447 Returns the namespace prefix of the contained element node (None if no namespace is used).
00448 """
00449 return self.getNsPrefix(self.getNsName())
00450
00451
00452
00453
00454 def __str__ (self):
00455 """Retrieve the textual representation of the contained element node."""
00456 return self.printNode()
00457
00458
00459 def printNode (self, indent="", deep=0, prettyPrint=0, attrMaxLengthDict={}, printElementValue=1, encoding=None):
00460 """Retrieve the textual representation of the contained element node.
00461
00462 Input parameter:
00463 indent: indentation to be used for string representation
00464 deep: 0 or 1: controls if the child element nodes are also printed
00465 prettyPrint: aligns the columns of the attributes of childNodes
00466 attrMaxLengthDict: dictionary containing the length of the attribute values (used for prettyprint)
00467 printElementValue: 0 or 1: controls if the element value is printed
00468 Returns the string representation
00469 """
00470 patternXmlTagShort = '''\
00471 %(indent)s<%(qName)s%(attributeString)s/>%(tailText)s%(lf)s'''
00472
00473 patternXmlTagLong = '''\
00474 %(indent)s<%(qName)s%(attributeString)s>%(elementValueString)s\
00475 %(lf)s%(subTreeString)s\
00476 %(indent)s</%(qName)s>%(tailText)s%(lf)s'''
00477
00478 subTreeStringList = []
00479 tailText = ""
00480 addIndent = ""
00481 lf = ""
00482 if deep:
00483 childAttrMaxLengthDict = {}
00484 if prettyPrint:
00485 for childNode in self.getChildren():
00486 childNode.__updateAttrMaxLengthDict(childAttrMaxLengthDict)
00487 lf = "\n"
00488 addIndent = " "
00489 for childNode in self.getChildren():
00490 subTreeStringList.append (childNode.printNode(indent + addIndent, deep, prettyPrint, childAttrMaxLengthDict, printElementValue))
00491 tailText = escapeCdata(self.element.xmlIfExtGetElementTailText(), encoding)
00492
00493 attributeStringList = []
00494 for attrName in self.getAttributeList():
00495 attrValue = escapeAttribute(self.getAttribute(attrName), encoding)
00496 if prettyPrint:
00497 try:
00498 align = attrMaxLengthDict[attrName]
00499 except:
00500 align = len(attrValue)
00501 else:
00502 align = len(attrValue)
00503 qName = self.nsName2QName(attrName)
00504 attributeStringList.append (' %s="%s"%*s' %(qName, attrValue, align - len(attrValue), ""))
00505 attributeString = string.join (attributeStringList, "")
00506
00507 qName = self.getQName()
00508 if printElementValue:
00509 if deep:
00510 elementValueString = escapeCdata(self.element.xmlIfExtGetElementText(), encoding)
00511 else:
00512 elementValueString = escapeCdata(self.getElementValue(ignoreEmtpyStringFragments=1), encoding)
00513 else:
00514 elementValueString = ""
00515
00516 if subTreeStringList == [] and elementValueString == "":
00517 printPattern = patternXmlTagShort
00518 else:
00519 if subTreeStringList != []:
00520 subTreeString = string.join (subTreeStringList, "")
00521 else:
00522 subTreeString = ""
00523 printPattern = patternXmlTagLong
00524 return printPattern % vars()
00525
00526
00527
00528
00529 def getParentNode (self):
00530 """Retrieve the ElementWrapper object of the parent element node.
00531
00532 Returns the ElementWrapper object of the parent element node.
00533 """
00534 parent = self.element.xmlIfExtGetParentNode()
00535 if parent != None:
00536 return parent.xmlIfExtElementWrapper
00537 else:
00538 return None
00539
00540
00541
00542
00543
00544 def getChildren (self, tagFilter=None):
00545 """Retrieve the ElementWrapper objects of the children element nodes.
00546
00547 Input parameter:
00548 tagFilter: retrieve only the children with this tag name ('*' or None returns all children)
00549 Returns all children of this element node which match 'tagFilter' (list)
00550 """
00551 if tagFilter in (None, '*', (None, '*')):
00552 children = self.element.xmlIfExtGetChildren()
00553 elif tagFilter[1] == '*':
00554
00555 children = filter(lambda child:child.xmlIfExtElementWrapper.getNamespaceURI() == tagFilter[0],
00556 self.element.xmlIfExtGetChildren())
00557 else:
00558 nsNameFilter = NsNameTupleFactory(tagFilter)
00559 try:
00560 children = self.__childrenCache[nsNameFilter]
00561 except:
00562 children = self.element.xmlIfExtGetChildren(nsNameFilter)
00563 if self.__useCaching():
00564 self.__childrenCache[nsNameFilter] = children
00565
00566 return map(lambda child: child.xmlIfExtElementWrapper, children)
00567
00568
00569 def getChildrenNS (self, namespaceURI, tagFilter=None):
00570 """Retrieve the ElementWrapper objects of the children element nodes using a namespace.
00571
00572 Input parameter:
00573 namespaceURI: the namespace URI of the children or None
00574 tagFilter: retrieve only the children with this localName ('*' or None returns all children)
00575 Returns all children of this element node which match 'namespaceURI' and 'tagFilter' (list)
00576 """
00577 return self.getChildren((namespaceURI, tagFilter))
00578
00579
00580 def getChildrenWithKey (self, tagFilter=None, keyAttr=None, keyValue=None):
00581 """Retrieve the ElementWrapper objects of the children element nodes.
00582
00583 Input parameter:
00584 tagFilter: retrieve only the children with this tag name ('*' or None returns all children)
00585 keyAttr: name of the key attribute
00586 keyValue: value of the key
00587 Returns all children of this element node which match 'tagFilter' (list)
00588 """
00589 children = self.getChildren(tagFilter)
00590 return filter(lambda child:child[keyAttr]==keyValue, children)
00591
00592
00593 def getFirstChild (self, tagFilter=None):
00594 """Retrieve the ElementWrapper objects of the first child element node.
00595
00596 Input parameter:
00597 tagFilter: retrieve only the first child with this tag name ('*' or None: no filter)
00598 Returns the first child of this element node which match 'tagFilter'
00599 or None if no suitable child element was found
00600 """
00601 if tagFilter in (None, '*', (None, '*')):
00602 element = self.element.xmlIfExtGetFirstChild()
00603 elif tagFilter[1] == '*':
00604
00605 children = filter(lambda child:child.xmlIfExtElementWrapper.getNamespaceURI() == tagFilter[0],
00606 self.element.xmlIfExtGetChildren())
00607 try:
00608 element = children[0]
00609 except:
00610 element = None
00611 else:
00612 nsNameFilter = NsNameTupleFactory(tagFilter)
00613 try:
00614 element = self.__firstChildCache[nsNameFilter]
00615 except:
00616 element = self.element.xmlIfExtGetFirstChild(nsNameFilter)
00617 if self.__useCaching():
00618 self.__firstChildCache[nsNameFilter] = element
00619
00620 if element != None:
00621 return element.xmlIfExtElementWrapper
00622 else:
00623 return None
00624
00625
00626 def getFirstChildNS (self, namespaceURI, tagFilter=None):
00627 """Retrieve the ElementWrapper objects of the first child element node using a namespace.
00628
00629 Input parameter:
00630 namespaceURI: the namespace URI of the children or None
00631 tagFilter: retrieve only the first child with this localName ('*' or None: no filter)
00632 Returns the first child of this element node which match 'namespaceURI' and 'tagFilter'
00633 or None if no suitable child element was found
00634 """
00635 return self.getFirstChild ((namespaceURI, tagFilter))
00636
00637
00638 def getFirstChildWithKey (self, tagFilter=None, keyAttr=None, keyValue=None):
00639 """Retrieve the ElementWrapper objects of the children element nodes.
00640
00641 Input parameter:
00642 tagFilter: retrieve only the children with this tag name ('*' or None returns all children)
00643 keyAttr: name of the key attribute
00644 keyValue: value of the key
00645 Returns all children of this element node which match 'tagFilter' (list)
00646 """
00647 children = self.getChildren(tagFilter)
00648 childrenWithKey = filter(lambda child:child[keyAttr]==keyValue, children)
00649 if childrenWithKey != []:
00650 return childrenWithKey[0]
00651 else:
00652 return None
00653
00654
00655 def getElementsByTagName (self, tagFilter=None):
00656 """Retrieve all descendant ElementWrapper object of current node whose tag name match 'tagFilter'.
00657
00658 Input parameter:
00659 tagFilter: retrieve only the children with this tag name ('*' or None returns all descendants)
00660 Returns all descendants of this element node which match 'tagFilter' (list)
00661 """
00662 if tagFilter in (None, '*', (None, '*'), (None, None)):
00663 descendants = self.element.xmlIfExtGetElementsByTagName()
00664
00665 elif tagFilter[1] == '*':
00666
00667 descendants = filter(lambda desc:desc.xmlIfExtElementWrapper.getNamespaceURI() == tagFilter[0],
00668 self.element.xmlIfExtGetElementsByTagName())
00669 else:
00670 nsNameFilter = NsNameTupleFactory(tagFilter)
00671 descendants = self.element.xmlIfExtGetElementsByTagName(nsNameFilter)
00672
00673 return map(lambda descendant: descendant.xmlIfExtElementWrapper, descendants)
00674
00675
00676 def getElementsByTagNameNS (self, namespaceURI, tagFilter=None):
00677 """Retrieve all descendant ElementWrapper object of current node whose tag name match 'namespaceURI' and 'tagFilter'.
00678
00679 Input parameter:
00680 namespaceURI: the namespace URI of the descendants or None
00681 tagFilter: retrieve only the descendants with this localName ('*' or None returns all descendants)
00682 Returns all descendants of this element node which match 'namespaceURI' and 'tagFilter' (list)
00683 """
00684 return self.getElementsByTagName((namespaceURI, tagFilter))
00685
00686
00687 def getIterator (self, tagFilter=None):
00688 """Creates a tree iterator. The iterator loops over this element
00689 and all subelements, in document order, and returns all elements
00690 whose tag name match 'tagFilter'.
00691
00692 Input parameter:
00693 tagFilter: retrieve only the children with this tag name ('*' or None returns all descendants)
00694 Returns all element nodes which match 'tagFilter' (list)
00695 """
00696 if tagFilter in (None, '*', (None, '*'), (None, None)):
00697 matchingElements = self.element.xmlIfExtGetIterator()
00698 elif tagFilter[1] == '*':
00699
00700 matchingElements = filter(lambda desc:desc.xmlIfExtElementWrapper.getNamespaceURI() == tagFilter[0],
00701 self.element.xmlIfExtGetIterator())
00702 else:
00703 nsNameFilter = NsNameTupleFactory(tagFilter)
00704 matchingElements = self.element.xmlIfExtGetIterator(nsNameFilter)
00705
00706 return map(lambda e: e.xmlIfExtElementWrapper, matchingElements)
00707
00708
00709 def appendChild (self, tupleOrLocalNameOrElement, attributeDict={}):
00710 """Append an element node to the children of the current node.
00711
00712 Input parameter:
00713 tupleOrLocalNameOrElement: (namespace, localName) or tagName or ElementWrapper object of the new child
00714 attributeDict: attribute dictionary containing the attributes of the new child (optional)
00715 If not an ElementWrapper object is given, a new ElementWrapper object is created with tupleOrLocalName
00716 Returns the ElementWrapper object of the new child.
00717 """
00718 if not isinstance(tupleOrLocalNameOrElement, self.__class__):
00719 childElementWrapper = self.__createElement (tupleOrLocalNameOrElement, attributeDict)
00720 else:
00721 childElementWrapper = tupleOrLocalNameOrElement
00722 self.element.xmlIfExtAppendChild (childElementWrapper.element)
00723 self.__clearChildrenCache(childElementWrapper.getNsName())
00724 return childElementWrapper
00725
00726
00727 def insertBefore (self, tupleOrLocalNameOrElement, refChild, attributeDict={}):
00728 """Insert an child element node before the given reference child of the current node.
00729
00730 Input parameter:
00731 tupleOrLocalNameOrElement: (namespace, localName) or tagName or ElementWrapper object of the new child
00732 refChild: reference child ElementWrapper object
00733 attributeDict: attribute dictionary containing the attributes of the new child (optional)
00734 If not an ElementWrapper object is given, a new ElementWrapper object is created with tupleOrLocalName
00735 Returns the ElementWrapper object of the new child.
00736 """
00737 if not isinstance(tupleOrLocalNameOrElement, self.__class__):
00738 childElementWrapper = self.__createElement (tupleOrLocalNameOrElement, attributeDict)
00739 else:
00740 childElementWrapper = tupleOrLocalNameOrElement
00741 if refChild == None:
00742 self.appendChild (childElementWrapper)
00743 else:
00744 self.element.xmlIfExtInsertBefore(childElementWrapper.element, refChild.element)
00745 self.__clearChildrenCache(childElementWrapper.getNsName())
00746 return childElementWrapper
00747
00748
00749 def removeChild (self, childElementWrapper):
00750 """Remove the given child element node from the children of the current node.
00751
00752 Input parameter:
00753 childElementWrapper: ElementWrapper object to be removed
00754 """
00755 self.element.xmlIfExtRemoveChild(childElementWrapper.element)
00756 self.__clearChildrenCache(childElementWrapper.getNsName())
00757
00758
00759 def insertSubtree (self, refChildWrapper, subTreeWrapper, insertSubTreeRootNode=1):
00760 """Insert the given subtree before 'refChildWrapper' ('refChildWrapper' is not removed!)
00761
00762 Input parameter:
00763 refChildWrapper: reference child ElementWrapper object
00764 subTreeWrapper: subtree wrapper object which contains the subtree to be inserted
00765 insertSubTreeRootNode: if 1, root node of subtree is inserted into parent tree, otherwise not
00766 """
00767 if refChildWrapper != None:
00768 self.element.xmlIfExtInsertSubtree (refChildWrapper.element, subTreeWrapper.getTree(), insertSubTreeRootNode)
00769 else:
00770 self.element.xmlIfExtInsertSubtree (None, subTreeWrapper.getTree(), insertSubTreeRootNode)
00771 self.__clearChildrenCache()
00772
00773
00774
00775 def replaceChildBySubtree (self, childElementWrapper, subTreeWrapper, insertSubTreeRootNode=1):
00776 """Replace child element node by XML subtree (e.g. expanding included XML files)
00777
00778 Input parameter:
00779 childElementWrapper: ElementWrapper object to be replaced
00780 subTreeWrapper: XML subtree wrapper object to be inserted
00781 insertSubTreeRootNode: if 1, root node of subtree is inserted into parent tree, otherwise not
00782 """
00783 self.insertSubtree (childElementWrapper, subTreeWrapper, insertSubTreeRootNode)
00784 self.removeChild(childElementWrapper)
00785
00786
00787
00788
00789 def getAttributeDict (self):
00790 """Retrieve a dictionary containing all attributes of the current element node.
00791
00792 Returns a dictionary (copy) containing all attributes of the current element node.
00793 """
00794 return self.element.xmlIfExtGetAttributeDict()
00795
00796
00797 def getAttributeList (self):
00798 """Retrieve a list containing all attributes of the current element node
00799 in the sequence specified in the input XML file.
00800
00801 Returns a list (copy) containing all attributes of the current element node
00802 in the sequence specified in the input XML file (TODO: does currently not work for 4DOM/pyXML interface).
00803 """
00804 attrList = map(lambda a: NsNameTupleFactory(a), self.attributeSequence)
00805 return attrList
00806
00807
00808 def getAttribute (self, tupleOrAttrName):
00809 """Retrieve an attribute value of the current element node.
00810
00811 Input parameter:
00812 tupleOrAttrName: tuple '(namespace, attributeName)' or 'attributeName' if no namespace is used
00813 Returns the value of the specified attribute.
00814 """
00815 nsName = NsNameTupleFactory(tupleOrAttrName)
00816 return self.element.xmlIfExtGetAttribute(nsName)
00817
00818
00819 def getAttributeOrDefault (self, tupleOrAttrName, defaultValue):
00820 """Retrieve an attribute value of the current element node or the given default value if the attribute doesn't exist.
00821
00822 Input parameter:
00823 tupleOrAttrName: tuple '(namespace, attributeName)' or 'attributeName' if no namespace is used
00824 Returns the value of the specified attribute or the given default value if the attribute doesn't exist.
00825 """
00826 attributeValue = self.getAttribute (tupleOrAttrName)
00827 if attributeValue == None:
00828 attributeValue = defaultValue
00829 return attributeValue
00830
00831
00832 def getQNameAttribute (self, tupleOrAttrName):
00833 """Retrieve a QName attribute value of the current element node.
00834
00835 Input parameter:
00836 tupleOrAttrName: tuple '(namespace, attributeName)' or 'attributeName' if no namespace is used
00837 Returns the value of the specified QName attribute as tuple (namespace, localName),
00838 i.e. the prefix is converted into the corresponding namespace value.
00839 """
00840 nsNameAttrName = NsNameTupleFactory(tupleOrAttrName)
00841 try:
00842 return self.__qNameAttrCache[nsNameAttrName]
00843 except:
00844 qNameValue = self.getAttribute (nsNameAttrName)
00845 nsNameValue = self.qName2NsName(qNameValue, useDefaultNs=1)
00846 if self.__useCaching():
00847 self.__qNameAttrCache[nsNameAttrName] = nsNameValue
00848 return nsNameValue
00849
00850
00851 def hasAttribute (self, tupleOrAttrName):
00852 """Checks if the requested attribute exist for the current element node.
00853
00854 Returns 1 if the attribute exists, otherwise 0.
00855 """
00856 nsName = NsNameTupleFactory(tupleOrAttrName)
00857 attrValue = self.element.xmlIfExtGetAttribute(nsName)
00858 if attrValue != None:
00859 return 1
00860 else:
00861 return 0
00862
00863
00864 def setAttribute (self, tupleOrAttrName, attributeValue):
00865 """Sets an attribute value of the current element node.
00866 If the attribute does not yet exist, it will be created.
00867
00868 Input parameter:
00869 tupleOrAttrName: tuple '(namespace, attributeName)' or 'attributeName' if no namespace is used
00870 attributeValue: attribute value to be set
00871 """
00872 if not isinstance(attributeValue, StringTypes):
00873 raise TypeError, "%s (attribute %s) must be a string!" %(repr(attributeValue), repr(tupleOrAttrName))
00874
00875 nsNameAttrName = NsNameTupleFactory(tupleOrAttrName)
00876 if nsNameAttrName not in self.attributeSequence:
00877 self.attributeSequence.append(nsNameAttrName)
00878
00879 if self.__useCaching():
00880 if self.__qNameAttrCache.has_key(nsNameAttrName):
00881 del self.__qNameAttrCache[nsNameAttrName]
00882
00883 self.element.xmlIfExtSetAttribute(nsNameAttrName, attributeValue, self.getCurrentNamespaces())
00884
00885
00886 def setAttributeDefault (self, tupleOrAttrName, defaultValue):
00887 """Create attribute and set value to default if it does not yet exist for the current element node.
00888 If the attribute is already existing nothing is done.
00889
00890 Input parameter:
00891 tupleOrAttrName: tuple '(namespace, attributeName)' or 'attributeName' if no namespace is used
00892 defaultValue: default attribute value to be set
00893 """
00894 if not self.hasAttribute(tupleOrAttrName):
00895 self.setAttribute(tupleOrAttrName, defaultValue)
00896
00897
00898 def removeAttribute (self, tupleOrAttrName):
00899 """Removes an attribute from the current element node.
00900 No exception is raised if there is no matching attribute.
00901
00902 Input parameter:
00903 tupleOrAttrName: tuple '(namespace, attributeName)' or 'attributeName' if no namespace is used
00904 """
00905 nsNameAttrName = NsNameTupleFactory(tupleOrAttrName)
00906
00907 if self.__useCaching():
00908 if self.__qNameAttrCache.has_key(nsNameAttrName):
00909 del self.__qNameAttrCache[nsNameAttrName]
00910
00911 self.element.xmlIfExtRemoveAttribute(nsNameAttrName)
00912
00913
00914 def processWsAttribute (self, tupleOrAttrName, wsAction):
00915 """Process white space action for the specified attribute according to requested 'wsAction'.
00916
00917 Input parameter:
00918 tupleOrAttrName: tuple '(namespace, attributeName)' or 'attributeName' if no namespace is used
00919 wsAction: 'collapse': substitute multiple whitespace characters by a single ' '
00920 'replace': substitute each whitespace characters by a single ' '
00921 """
00922 attributeValue = self.getAttribute(tupleOrAttrName)
00923 newValue = processWhitespaceAction (attributeValue, wsAction)
00924 if newValue != attributeValue:
00925 self.setAttribute(tupleOrAttrName, newValue)
00926 return newValue
00927
00928
00929
00930
00931 def getElementValue (self, ignoreEmtpyStringFragments=0):
00932 """Retrieve the content of the current element node.
00933
00934 Returns the content of the current element node as string.
00935 The content of multiple text nodes / CDATA nodes are concatenated to one string.
00936
00937 Input parameter:
00938 ignoreEmtpyStringFragments: if 1, text nodes containing only whitespaces are ignored
00939 """
00940 return "".join (self.getElementValueFragments(ignoreEmtpyStringFragments))
00941
00942
00943 def getElementValueFragments (self, ignoreEmtpyStringFragments=0):
00944 """Retrieve the content of the current element node as value fragment list.
00945
00946 Returns the content of the current element node as list of string fragments.
00947 Each list element represents one text nodes / CDATA node.
00948
00949 Input parameter:
00950 ignoreEmtpyStringFragments: if 1, text nodes containing only whitespaces are ignored
00951
00952 Method has to be implemented by derived classes!
00953 """
00954 return self.element.xmlIfExtGetElementValueFragments (ignoreEmtpyStringFragments)
00955
00956
00957 def setElementValue (self, elementValue):
00958 """Set the content of the current element node.
00959
00960 Input parameter:
00961 elementValue: string containing the new element value
00962 If multiple text nodes / CDATA nodes are existing, 'elementValue' is set
00963 for the first text node / CDATA node. All other text nodes /CDATA nodes are set to ''.
00964 """
00965 self.element.xmlIfExtSetElementValue(elementValue)
00966
00967
00968 def processWsElementValue (self, wsAction):
00969 """Process white space action for the content of the current element node according to requested 'wsAction'.
00970
00971 Input parameter:
00972 wsAction: 'collapse': substitute multiple whitespace characters by a single ' '
00973 'replace': substitute each whitespace characters by a single ' '
00974 """
00975 self.element.xmlIfExtProcessWsElementValue(wsAction)
00976 return self.getElementValue()
00977
00978
00979
00980
00981
00982 def getStartLineNumber (self):
00983 """Retrieve the start line number of the current element node.
00984
00985 Returns the start line number of the current element node in the XML file
00986 """
00987 return self.startLineNumber
00988
00989
00990 def getEndLineNumber (self):
00991 """Retrieve the end line number of the current element node.
00992
00993 Returns the end line number of the current element node in the XML file
00994 """
00995 return self.endLineNumber
00996
00997
00998 def getAbsUrl (self):
00999 """Retrieve the absolute URL of the XML file the current element node belongs to.
01000
01001 Returns the absolute URL of the XML file the current element node belongs to.
01002 """
01003 return self.absUrl
01004
01005
01006 def getBaseUrl (self):
01007 """Retrieve the base URL of the XML file the current element node belongs to.
01008
01009 Returns the base URL of the XML file the current element node belongs to.
01010 """
01011 return self.baseUrl
01012
01013
01014 def getFilePath (self):
01015 """Retrieve the file path of the XML file the current element node belongs to.
01016
01017 Returns the file path of the XML file the current element node belongs to.
01018 """
01019 return self.filePath
01020
01021
01022 def getLocation (self, end=0, fullpath=0):
01023 """Retrieve a string containing file name and line number of the current element node.
01024
01025 Input parameter:
01026 end: 1 if end line number shall be shown, 0 for start line number
01027 fullpath: 1 if the full path of the XML file shall be shown, 0 for only the file name
01028 Returns a string containing file name and line number of the current element node.
01029 (e.g. to be used for traces or error messages)
01030 """
01031 lineMethod = (self.getStartLineNumber, self.getEndLineNumber)
01032 pathFunc = (os.path.basename, os.path.abspath)
01033 return "%s, %d" % (pathFunc[fullpath](self.getFilePath()), lineMethod[end]())
01034
01035
01036
01037
01038
01039 def getCurrentNamespaces (self):
01040 """Retrieve the namespace prefixes visible for the current element node
01041
01042 Returns a list of the namespace prefixes visible for the current node.
01043 """
01044 return self.curNs
01045
01046
01047 def qName2NsName (self, qName, useDefaultNs):
01048 """Convert a qName 'prefix:localName' to a tuple '(namespace, localName)'.
01049
01050 Input parameter:
01051 qName: qName to be converted
01052 useDefaultNs: 1 if default namespace shall be used
01053 Returns the corresponding tuple '(namespace, localName)' for 'qName'.
01054 """
01055 if qName != None:
01056 qNamePrefix, qNameLocalName = splitQName (qName)
01057 for prefix, namespaceURI in self.getCurrentNamespaces():
01058 if qNamePrefix == prefix:
01059 if prefix != EMPTY_PREFIX or useDefaultNs:
01060 nsName = (namespaceURI, qNameLocalName)
01061 break
01062 else:
01063 if qNamePrefix == None:
01064 nsName = (EMPTY_NAMESPACE, qNameLocalName)
01065 else:
01066 raise ValueError, "Namespace prefix '%s' not bound to a namespace!" % (qNamePrefix)
01067 else:
01068 nsName = (None, None)
01069 return NsNameTupleFactory(nsName)
01070
01071
01072 def nsName2QName (self, nsLocalName):
01073 """Convert a tuple '(namespace, localName)' to a string 'prefix:localName'
01074
01075 Input parameter:
01076 nsLocalName: tuple '(namespace, localName)' to be converted
01077 Returns the corresponding string 'prefix:localName' for 'nsLocalName'.
01078 """
01079 qName = nsNameToQName (nsLocalName, self.getCurrentNamespaces())
01080 if qName == "xmlns:None": qName = "xmlns"
01081 return qName
01082
01083
01084 def getNamespace (self, qName):
01085 """Retrieve namespace for a qName 'prefix:localName'.
01086
01087 Input parameter:
01088 qName: qName 'prefix:localName'
01089 Returns the corresponding namespace for the prefix of 'qName'.
01090 """
01091 if qName != None:
01092 qNamePrefix, qNameLocalName = splitQName (qName)
01093 for prefix, namespaceURI in self.getCurrentNamespaces():
01094 if qNamePrefix == prefix:
01095 namespace = namespaceURI
01096 break
01097 else:
01098 if qNamePrefix == None:
01099 namespace = EMPTY_NAMESPACE
01100 else:
01101 raise LookupError, "Namespace for QName '%s' not found!" % (qName)
01102 else:
01103 namespace = EMPTY_NAMESPACE
01104 return namespace
01105
01106
01107 def getNsPrefix (self, nsLocalName):
01108 """Retrieve prefix for a tuple '(namespace, localName)'.
01109
01110 Input parameter:
01111 nsLocalName: tuple '(namespace, localName)'
01112 Returns the corresponding prefix for the namespace of 'nsLocalName'.
01113 """
01114 ns = nsLocalName[0]
01115 for prefix, namespace in self.getCurrentNamespaces():
01116 if ns == namespace:
01117 return prefix
01118 else:
01119 if ns == None:
01120 return None
01121 else:
01122 raise LookupError, "Prefix for namespaceURI '%s' not found!" % (ns)
01123
01124
01125
01126
01127 def getXPath (self, xPath, namespaceRef=None, useDefaultNs=1, attrIgnoreList=[]):
01128 """Retrieve node list or attribute list for specified XPath
01129
01130 Input parameter:
01131 xPath: string containing xPath specification
01132 namespaceRef: scope for namespaces (default is own element node)
01133 useDefaultNs: 1, if default namespace shall be used if no prefix is available
01134 attrIgnoreList: list of attributes to be ignored if wildcard is specified for attributes
01135
01136 Returns all nodes which match xPath specification or
01137 list of attribute values if xPath specifies an attribute
01138 """
01139 return self.getXPathList(xPath, namespaceRef, useDefaultNs, attrIgnoreList)[0]
01140
01141
01142 def getXPathList (self, xPath, namespaceRef=None, useDefaultNs=1, attrIgnoreList=[]):
01143 """Retrieve node list or attribute list for specified XPath
01144
01145 Input parameter:
01146 xPath: string containing xPath specification
01147 namespaceRef: scope for namespaces (default is own element node)
01148 useDefaultNs: 1, if default namespace shall be used if no prefix is available
01149 attrIgnoreList: list of attributes to be ignored if wildcard is specified for attributes
01150
01151 Returns tuple (completeChildList, attrNodeList, attrNsNameFirst).
01152 completeChildList: contains all child node which match xPath specification or
01153 list of attribute values if xPath specifies an attribute
01154 attrNodeList: contains all child nodes where the specified attribute was found
01155 attrNsNameFirst: contains the name of the first attribute which was found
01156 TODO: Re-design namespace and attribute handling of this method
01157 """
01158 reChild = re.compile('child *::')
01159 reAttribute = re.compile('attribute *::')
01160 if namespaceRef == None: namespaceRef = self
01161 xPath = reChild.sub('./', xPath)
01162 xPath = reAttribute.sub('@', xPath)
01163 xPathList = string.split (xPath, "|")
01164 completeChildDict = {}
01165 completeChildList = []
01166 attrNodeList = []
01167 attrNsNameFirst = None
01168 for xRelPath in xPathList:
01169 xRelPath = string.strip(xRelPath)
01170 descendantOrSelf = 0
01171 if xRelPath[:3] == ".//":
01172 descendantOrSelf = 1
01173 xRelPath = xRelPath[3:]
01174 xPathLocalStepList = string.split (xRelPath, "/")
01175 childList = [self, ]
01176 for localStep in xPathLocalStepList:
01177 localStep = string.strip(localStep)
01178 stepChildList = []
01179 if localStep == "":
01180 raise IOError ("Invalid xPath '%s'!" %(xRelPath))
01181 elif localStep == ".":
01182 continue
01183 elif localStep[0] == '@':
01184 if len(localStep) == 1:
01185 raise ValueError ("Attribute name is missing in xPath!")
01186 if descendantOrSelf:
01187 childList = self.getElementsByTagName()
01188 attrName = localStep[1:]
01189 for childNode in childList:
01190 if attrName == '*':
01191 attrNodeList.append (childNode)
01192 attrDict = childNode.getAttributeDict()
01193 for attrIgnore in attrIgnoreList:
01194 if attrDict.has_key(attrIgnore):
01195 del attrDict[attrIgnore]
01196 stepChildList.extend(attrDict.values())
01197 try:
01198 attrNsNameFirst = attrDict.keys()[0]
01199 except:
01200 pass
01201 else:
01202 attrNsName = namespaceRef.qName2NsName (attrName, useDefaultNs=0)
01203 if attrNsName[1] == '*':
01204 for attr in childNode.getAttributeDict().keys():
01205 if attr[0] == attrNsName[0]:
01206 if attrNodeList == []:
01207 attrNsNameFirst = attrNsName
01208 attrNodeList.append (childNode)
01209 stepChildList.append (childNode.getAttribute(attr))
01210 elif childNode.hasAttribute(attrNsName):
01211 if attrNodeList == []:
01212 attrNsNameFirst = attrNsName
01213 attrNodeList.append (childNode)
01214 stepChildList.append (childNode.getAttribute(attrNsName))
01215 childList = stepChildList
01216 else:
01217 nsLocalName = namespaceRef.qName2NsName (localStep, useDefaultNs=useDefaultNs)
01218 if descendantOrSelf:
01219 descendantOrSelf = 0
01220 if localStep == "*":
01221 stepChildList = self.getElementsByTagName()
01222 else:
01223 stepChildList = self.getElementsByTagName(nsLocalName)
01224 else:
01225 for childNode in childList:
01226 if localStep == "*":
01227 stepChildList.extend (childNode.getChildren())
01228 else:
01229 stepChildList.extend (childNode.getChildrenNS(nsLocalName[0], nsLocalName[1]))
01230 childList = stepChildList
01231
01232 for child in childList:
01233 try:
01234 childKey = child.element
01235 except:
01236 childKey = child
01237 if not completeChildDict.has_key(childKey):
01238 completeChildList.append(child)
01239 completeChildDict[childKey] = 1
01240 return completeChildList, attrNodeList, attrNsNameFirst
01241
01242
01243
01244
01245
01246
01247 def __createElement (self, tupleOrLocalName, attributeDict):
01248 """Create a new ElementWrapper object.
01249
01250 Input parameter:
01251 tupleOrLocalName: tuple '(namespace, localName)' or 'localName' if no namespace is used
01252 attributeDict: dictionary which contains the attributes and their values of the element node to be created
01253 Returns the created ElementWrapper object
01254 """
01255 childElementWrapper = self.treeWrapper.createElement (tupleOrLocalName, attributeDict, self.curNs[:])
01256 childElementWrapper.element.xmlIfExtSetParentNode(self.element)
01257 return childElementWrapper
01258
01259
01260 def __updateAttrMaxLengthDict (self, attrMaxLengthDict):
01261 """Update dictionary which contains the maximum length of node attributes.
01262
01263 Used for pretty print to align the attributes of child nodes.
01264 attrMaxLengthDict is in/out parameter.
01265 """
01266 for attrName, attrValue in self.getAttributeDict().items():
01267 attrLength = len(attrValue)
01268 if not attrMaxLengthDict.has_key(attrName):
01269 attrMaxLengthDict[attrName] = attrLength
01270 else:
01271 attrMaxLengthDict[attrName] = max(attrMaxLengthDict[attrName], attrLength)
01272
01273
01274 def __clearChildrenCache (self, childNsName=None):
01275 """Clear children cache.
01276 """
01277 if self.__useCaching():
01278 if childNsName != None:
01279 if self.__childrenCache.has_key(childNsName):
01280 del self.__childrenCache[childNsName]
01281 if self.__firstChildCache.has_key(childNsName):
01282 del self.__firstChildCache[childNsName]
01283 else:
01284 self.__childrenCache.clear()
01285 self.__firstChildCache.clear()
01286
01287
01288 def __useCaching(self):
01289 return self.treeWrapper.useCaching()
01290
01291