Viewing file: Range.py (39.25 KB) -rw-r--r-- Select action/file-type: (+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) |
######################################################################## # # File Name: Range.py # # """ WWW: http://4suite.com/4DOM e-mail: support@4suite.com
Copyright (c) 2000 Fourthought Inc, USA. All Rights Reserved. See http://4suite.com/COPYRIGHT for license and copyright information """
from xml.dom import InvalidStateErr from xml.dom import InvalidNodeTypeErr from xml.dom import BadBoundaryPointsErr from xml.dom import IndexSizeErr from xml.dom import WrongDocumentErr
from xml.dom import Node
class Range: readOnly =['startContainer', 'startOffset', 'endContainer', 'endOffset', 'collapsed', 'commonAncestorContainer', ]
POSITION_EQUAL = 1 POSITION_LESS_THAN = 2 POSITION_GREATER_THAN = 3
START_TO_START = 0 START_TO_END = 1 END_TO_END = 2 END_TO_START = 3
def __init__(self,ownerDocument): self._ownerDocument = ownerDocument
self.__dict__['startContainer'] = ownerDocument self.__dict__['startOffset'] = 0 self.__dict__['endContainer'] = ownerDocument self.__dict__['endOffset'] = 0 self.__dict__['collapsed'] = 1 self.__dict__['commonAncestorContainer'] = ownerDocument
self.__dict__['detached'] = 0
def __setattr__(self,name,value): if name in self.readOnly: raise AttributeError, name self.__dict__[name] = value
def __getattr__(self,name): if name in self.readOnly: #Means we are detached raise InvalidStateErr() raise AttributeError, name
def cloneContents(self): """Clone the contents defined by this range"""
if self.detached: raise InvalidStateErr()
df = self._ownerDocument.createDocumentFragment()
if self.startContainer == self.endContainer: if self.startOffset == self.endOffset: return df if self.startContainer.nodeType in [Node.TEXT_NODE, Node.COMMENT_NODE, Node.PROCESSING_INSTRUCTION_NODE]: #Adjust the character data data = self.startContainer.substringData(self.startOffset,1+self.endOffset-self.startOffset) tx = self._ownerDocument.createTextNode(data) df.appendChild(tx)
else: #Clone a set number of children numDel = self.endOffset - self.startOffset+1 for ctr in range(numDel): c = self.startContainer.childNodes[self.startOffset+ctr].cloneNode(1) df.appendChild(c)
elif self.startContainer == self.commonAncestorContainer: #Clone up the endContainer #From the start to the end lastKids = [] copyData = None if self.endContainer.nodeType in [Node.TEXT_NODE, Node.COMMENT_NODE, Node.PROCESSING_INSTRUCTION_NODE]: #Adjust the character data copyData = self.endContainer.substringData(0,self.endOffset) else: numDel = self.endOffset for ctr in range(numDel): lastKids.append(self.endContainer.childNodes[ctr].cloneNode(1))
cur = self.endContainer while cur.parentNode != self.commonAncestorContainer:
#Clone all of the way up newCur = cur.cloneNode(0) if copyData: newCur.data = copyData copyData = None for k in lastKids: newCur.appendChild(k)
lastKids = [] index = cur.parentNode.childNodes.index(cur) for ctr in range(index): lastKids.append(cur.parentNode.childNodes[ctr].cloneNode(1)) lastKids.append(newCur) cur = cur.parentNode
newEnd = cur.cloneNode(0) for k in lastKids: newEnd.appendChild(k)
endAncestorChild = cur
#Extract up to the ancestor of end for c in self.startContainer.childNodes: if c == endAncestorChild: break df.appendChild(c.cloneNode(1)) df.appendChild(newEnd)
elif self.endContainer == self.commonAncestorContainer: lastKids = [] copyData = None if self.startContainer.nodeType in [Node.TEXT_NODE, Node.COMMENT_NODE, Node.PROCESSING_INSTRUCTION_NODE]: #Adjust the character data
copyData = self.startContainer.substringData(self.startOffset,1+len(self.startContainer.data)-self.startOffset) else: numDel = len(self.startContainer.childNodes) - self.startOffset for ctr in range(numDel): c = self.startContainer.childNodes[self.startOffset+ctr].cloneNode(1) lastKids.append(c)
cur = self.startContainer while cur.parentNode != self.commonAncestorContainer: #Clone all of the way up newCur = cur.cloneNode(0) if copyData: newCur.data = copyData copyData = None for k in lastKids: newCur.appendChild(k) lastKids = [newCur]
index = cur.parentNode.childNodes.index(cur) for ctr in range(index+1,len(cur.parentNode.childNodes)): lastKids.append(cur.parentNode.childNodes[ctr].cloneNode(1)) cur = cur.parentNode
startAncestorChild = cur newStart = cur.cloneNode(0) for k in lastKids: newStart.appendChild(k)
df.appendChild(newStart)
#Extract up to the ancestor of start startAncestorChild = cur startIndex = self.endContainer.childNodes.index(cur) lastAdded = None for ctr in range(startIndex+1,self.endOffset+1): c = self.endContainer.childNodes[ctr].cloneNode(1) df.insertBefore(c,lastAdded) lastAdded = c
else: #From the start to the end lastStartKids = [] startCopyData = None if self.startContainer.nodeType in [Node.TEXT_NODE, Node.COMMENT_NODE, Node.PROCESSING_INSTRUCTION_NODE]: #Adjust the character data
startCopyData = self.startContainer.substringData(self.startOffset,1+len(self.startContainer.data)-self.startOffset) else: numDel = len(self.startContainer.childNodes) - self.startOffset for ctr in range(numDel): c = self.startContainer.childNodes[self.startOffset+ctr].cloneNode(1) lastStartKids.append(c)
cur = self.startContainer while cur.parentNode != self.commonAncestorContainer: #Clone all of the way up newCur = cur.cloneNode(0) if startCopyData: newCur.data = startCopyData startCopyData = None for k in lastStartKids: newCur.appendChild(k) lastStartKids = [newCur]
index = cur.parentNode.childNodes.index(cur) for ctr in range(index+1,len(cur.parentNode.childNodes)): lastStartKids.append(cur.parentNode.childNodes[ctr].cloneNode(1)) cur = cur.parentNode
startAncestorChild = cur
newStart = cur.cloneNode(0) for k in lastStartKids: newStart.appendChild(k)
df.appendChild(newStart)
lastEndKids = [] endCopyData = None #Delete up the endContainer #From the start to the end if self.endContainer.nodeType in [Node.TEXT_NODE, Node.COMMENT_NODE, Node.PROCESSING_INSTRUCTION_NODE]: #Adjust the character data endCopyData = self.endContainer.substringData(0,self.endOffset) else: numDel = self.endOffset for ctr in range(numDel): c = self.endContainer.childNodes[ctr].cloneNode(1) lastEndKids.append(c)
cur = self.endContainer while cur.parentNode != self.commonAncestorContainer: newCur = cur.cloneNode(0) if endCopyData: newCur.data = endCopyData endCopyData = None for k in lastEndKids: newCur.appendChild(k)
lastEndKids = [] index = cur.parentNode.childNodes.index(cur) for ctr in range(index): lastEndKids.append(cur.parentNode.childNodes[ctr].cloneNode(1)) lastEndKids.append(newCur) cur = cur.parentNode
endAncestorChild = cur
newEnd = cur.cloneNode(0) for k in lastEndKids: newEnd.appendChild(k)
cur = startAncestorChild #Extract everything between us startIndex = startAncestorChild.parentNode.childNodes.index(startAncestorChild) endIndex = endAncestorChild.parentNode.childNodes.index(endAncestorChild) for ctr in range(startIndex+1,endIndex): c = startAncestorChild.parentNode.childNodes[ctr] df.appendChild(c.cloneNode(1)) df.appendChild(newEnd)
#Adjust the containers #FIXME What the heck is the spec talking about?? self.__dict__['endContainer'] = self.startContainer self.__dict__['endOffset'] = self.startContainer self.__dict__['commonAncestorContainer'] = self.startContainer self.__dict__['collapsed'] = 1
return df
def cloneRange(self): if self.detached: raise InvalidStateErr()
newRange = Range(self._ownerDocument) newRange.setStart(self.startContainer,self.startOffset) newRange.setEnd(self.endContainer,self.endOffset) return newRange
def collapse(self,toStart): """Collapse the range""" if self.detached: raise InvalidStateErr()
if toStart: self.__dict__['endContainer'] = self.startContainer self.__dict__['endOffset'] = self.startOffset else: self.__dict__['startContainer'] = self.endContainer self.__dict__['startOffset'] = self.endOffset
self.__dict__['collapsed'] = 1 self.__dict__['commonAncestorContainer'] = self.startContainer
def compareBoundaryPoints(self,how,sourceRange): if self.detached: raise InvalidStateErr()
if not hasattr(sourceRange,'_ownerDocument') or sourceRange._ownerDocument != self._ownerDocument or not isinstance(sourceRange,Range): raise WrongDocumentErr()
if how == self.START_TO_START: ac = self.startContainer ao = self.startOffset bc = sourceRange.startContainer bo = sourceRange.startOffset elif how == self.START_TO_END: ac = self.startContainer ao = self.startOffset bc = sourceRange.endContainer bo = sourceRange.endOffset elif how == self.END_TO_END: ac = self.endContainer ao = self.endOffset bc = sourceRange.endContainer bo = sourceRange.endOffset elif how == self.END_TO_START: ac = self.endContainer ao = self.endOffset bc = sourceRange.startContainer bo = sourceRange.startOffset else: raise TypeError, how
pos = self.__comparePositions(ac,ao,bc,bo) if pos == self.POSITION_EQUAL: return 0 elif pos == self.POSITION_LESS_THAN: return -1 return 1
def deleteContents(self): """Delete the contents defined by this range"""
#NOTE Use 4DOM ReleaseNode cause it is interface safe from xml.dom.ext import ReleaseNode
if self.detached: raise InvalidStateErr()
if self.startContainer == self.endContainer: if self.startOffset == self.endOffset: return if self.startContainer.nodeType in [Node.TEXT_NODE, Node.COMMENT_NODE, Node.PROCESSING_INSTRUCTION_NODE]: #Adjust the character data self.startContainer.deleteData(self.startOffset,1+self.endOffset-self.startOffset)
else: #Delete a set number of children numDel = self.endOffset - self.startOffset+1 for ctr in range(numDel): c = self.startContainer.removeChild(self.startContainer.childNodes[self.startOffset]) ReleaseNode(c)
self.__dict__['endContainer'] = self.startContainer self.__dict__['endOffset'] = self.endContainer self.__dict__['commonAncestorContainer'] = self.endContainer self.__dict__['collapsed'] = 1
elif self.startContainer == self.commonAncestorContainer: #Delete up the endContainer #From the start to the end if self.endContainer.nodeType in [Node.TEXT_NODE, Node.COMMENT_NODE, Node.PROCESSING_INSTRUCTION_NODE]: #Adjust the character data self.endContainer.deleteData(0,self.endOffset) else: numDel = self.endOffset for ctr in range(numDel): c = self.endContainer.removeChild(self.endContainer.childNodes[0]) ReleaseNode(c)
cur = self.endContainer while cur.parentNode != self.commonAncestorContainer: while cur.previousSibling: c = cur.parentNode.removeChild(cur.previousSibling) ReleaseNode(c) cur = cur.parentNode
#Delete up to the ancestor of end endAncestorChild = cur while self.startContainer.firstChild != endAncestorChild: c = self.startContainer.removeChild(self.startContainer.firstChild) ReleaseNode(c) elif self.endContainer == self.commonAncestorContainer: if self.startContainer.nodeType in [Node.TEXT_NODE, Node.COMMENT_NODE, Node.PROCESSING_INSTRUCTION_NODE]: #Adjust the character data self.startContainer.deleteData(self.startOffset,1+len(self.startContainer.data)-self.startOffset) else: numDel = len(self.startContainer.childNodes) - self.startOffset for ctr in range(numDel): c = self.startContainer.removeChild(self.startContainer.childNodes[self.startOffset]) ReleaseNode(c)
cur = self.startContainer while cur.parentNode != self.commonAncestorContainer: while cur.nextSibling: c = cur.parentNode.removeChild(cur.nextSibling) ReleaseNode(c) cur = cur.parentNode
startAncestorChild = cur
#Delete up to the ancestor of start startAncestorChild = cur startIndex = self.endContainer.childNodes.index(cur) numDel = self.endOffset - startIndex for ctr in range(numDel): c = self.endContainer.removeChild(startAncestorChild.nextSibling) ReleaseNode(c)
else: #From the start to the end if self.startContainer.nodeType in [Node.TEXT_NODE, Node.COMMENT_NODE, Node.PROCESSING_INSTRUCTION_NODE]: #Adjust the character data self.startContainer.deleteData(self.startOffset,1+len(self.startContainer.data)-self.startOffset) else: numDel = len(self.startContainer.childNodes) - self.startOffset for ctr in range(numDel): c = self.startContainer.removeChild(self.startContainer.childNodes[self.startOffset]) ReleaseNode(c)
cur = self.startContainer while cur.parentNode != self.commonAncestorContainer: while cur.nextSibling: c = cur.parentNode.removeChild(cur.nextSibling) ReleaseNode(c) cur = cur.parentNode
startAncestorChild = cur #Delete up the endContainer #From the start to the end if self.endContainer.nodeType in [Node.TEXT_NODE, Node.COMMENT_NODE, Node.PROCESSING_INSTRUCTION_NODE]: #Adjust the character data self.endContainer.deleteData(0,self.endOffset) else: numDel = self.endOffset for ctr in range(numDel): c = self.endContainer.removeChild(self.endContainer.childNodes[0]) ReleaseNode(c)
cur = self.endContainer while cur.parentNode != self.commonAncestorContainer: while cur.previousSibling: c = cur.parentNode.removeChild(cur.previousSibling) ReleaseNode(c) cur = cur.parentNode
endAncestorChild = cur
cur = startAncestorChild #Delete everything between us while cur.nextSibling != endAncestorChild: c = cur.parentNode.removeChild(cur.nextSibling) ReleaseNode(c)
#Adjust the containers #FIXME What the heck is the spec talking about?? self.__dict__['endContainer'] = self.startContainer self.__dict__['endOffset'] = self.startContainer self.__dict__['commonAncestorContainer'] = self.startContainer self.__dict__['collapsed'] = 1
return None
def detach(self): self.detached = 1 del self.startContainer del self.endContainer del self.startOffset del self.endOffset del self.collapsed del self.commonAncestorContainer
def extractContents(self): """Extract the contents defined by this range"""
if self.detached: raise InvalidStateErr()
df = self._ownerDocument.createDocumentFragment()
if self.startContainer == self.endContainer: if self.startOffset == self.endOffset: return df if self.startContainer.nodeType in [Node.TEXT_NODE, Node.COMMENT_NODE, Node.PROCESSING_INSTRUCTION_NODE]: #Adjust the character data data = self.startContainer.substringData(self.startOffset,1+self.endOffset-self.startOffset) self.startContainer.deleteData(self.startOffset,1+self.endOffset-self.startOffset)
tx = self._ownerDocument.createTextNode(data) df.appendChild(tx)
else: #Extrace a set number of children
numDel = self.endOffset - self.startOffset+1 for ctr in range(numDel): c = self.startContainer.removeChild(self.startContainer.childNodes[self.startOffset]) df.appendChild(c)
elif self.startContainer == self.commonAncestorContainer: #Delete up the endContainer #From the start to the end lastKids = [] copyData = None #Delete up the endContainer #From the start to the end if self.endContainer.nodeType in [Node.TEXT_NODE, Node.COMMENT_NODE, Node.PROCESSING_INSTRUCTION_NODE]: #Adjust the character data copyData = self.endContainer.substringData(0,self.endOffset) self.endContainer.deleteData(0,self.endOffset) else: numDel = self.endOffset for ctr in range(numDel): c = self.endContainer.removeChild(self.endContainer.childNodes[0]) lastKids.append(c)
cur = self.endContainer while cur.parentNode != self.commonAncestorContainer:
#Clone all of the way up newCur = cur.cloneNode(0) if copyData: newCur.data = copyData copyData = None for k in lastKids: newCur.appendChild(k) lastKids = [newCur]
while cur.previousSibling: c = cur.parentNode.removeChild(cur.previousSibling) lastKids = [c] + lastKids cur = cur.parentNode
newEnd = cur.cloneNode(0) for k in lastKids: newEnd.appendChild(k)
endAncestorChild = cur
#Extract up to the ancestor of end while self.startContainer.firstChild != endAncestorChild: c = self.startContainer.removeChild(self.startContainer.firstChild) df.appendChild(c) df.appendChild(newEnd)
elif self.endContainer == self.commonAncestorContainer: lastKids = [] copyData = None if self.startContainer.nodeType in [Node.TEXT_NODE, Node.COMMENT_NODE, Node.PROCESSING_INSTRUCTION_NODE]: #Adjust the character data
copyData = self.startContainer.substringData(self.startOffset,1+len(self.startContainer.data)-self.startOffset) self.startContainer.deleteData(self.startOffset,1+len(self.startContainer.data)-self.startOffset) else: numDel = len(self.startContainer.childNodes) - self.startOffset for ctr in range(numDel): c = self.startContainer.removeChild(self.startContainer.childNodes[self.startOffset]) lastKids.append(c)
cur = self.startContainer while cur.parentNode != self.commonAncestorContainer: #Clone all of the way up newCur = cur.cloneNode(0) if copyData: newCur.data = copyData copyData = None for k in lastKids: newCur.appendChild(k) lastKids = [newCur]
while cur.nextSibling: c = cur.parentNode.removeChild(cur.nextSibling) lastKids.append(c) cur = cur.parentNode
startAncestorChild = cur newStart = cur.cloneNode(0) for k in lastKids: newStart.appendChild(k)
df.appendChild(newStart)
#Extract up to the ancestor of start startAncestorChild = cur startIndex = self.endContainer.childNodes.index(cur) lastAdded = None numDel = self.endOffset - startIndex for ctr in range(numDel): c = self.endContainer.removeChild(startAncestorChild.nextSibling) df.insertBefore(c,lastAdded) lastAdded = c
else: #From the start to the end lastStartKids = [] startCopyData = None if self.startContainer.nodeType in [Node.TEXT_NODE, Node.COMMENT_NODE, Node.PROCESSING_INSTRUCTION_NODE]: #Adjust the character data
startCopyData = self.startContainer.substringData(self.startOffset,1+len(self.startContainer.data)-self.startOffset) self.startContainer.deleteData(self.startOffset,1+len(self.startContainer.data)-self.startOffset) else: numDel = len(self.startContainer.childNodes) - self.startOffset for ctr in range(numDel): c = self.startContainer.removeChild(self.startContainer.childNodes[self.startOffset]) lastStartKids.append(c)
cur = self.startContainer while cur.parentNode != self.commonAncestorContainer: #Clone all of the way up newCur = cur.cloneNode(0) if startCopyData: newCur.data = startCopyData startCopyData = None for k in lastStartKids: newCur.appendChild(k) lastStartKids = [newCur]
while cur.nextSibling: c = cur.parentNode.removeChild(cur.nextSibling) lastStartKids.append(c) cur = cur.parentNode
startAncestorChild = cur
newStart = cur.cloneNode(0) for k in lastStartKids: newStart.appendChild(k) if startCopyData: newStart.data = startCopyData startCopyData = None
df.appendChild(newStart)
lastEndKids = [] endCopyData = None #Delete up the endContainer #From the start to the end if self.endContainer.nodeType in [Node.TEXT_NODE, Node.COMMENT_NODE, Node.PROCESSING_INSTRUCTION_NODE]: #Adjust the character data endCopyData = self.endContainer.substringData(0,self.endOffset) self.endContainer.deleteData(0,self.endOffset) else: numDel = self.endOffset for ctr in range(numDel): c = self.endContainer.removeChild(self.endContainer.childNodes[0]) lastEndKids.append(c)
cur = self.endContainer while cur.parentNode != self.commonAncestorContainer: newCur = cur.cloneNode(0) if endCopyData: newCur.data = endCopyData endCopyData = None for k in lastEndKids: newCur.appendChild(k) lastEndKids = [newCur] while cur.previousSibling: c = cur.parentNode.removeChild(cur.previousSibling) lastEndKids = [c] + lastEndKids cur = cur.parentNode
endAncestorChild = cur
newEnd = cur.cloneNode(0) for k in lastEndKids: newEnd.appendChild(k) if endCopyData: newEnd.data = endCopyData endCopyData = None
cur = startAncestorChild #Extract everything between us while cur.nextSibling != endAncestorChild: c = cur.parentNode.removeChild(cur.nextSibling) df.appendChild(c) df.appendChild(newEnd)
#Adjust the containers #FIXME What the heck is the spec talking about?? self.__dict__['endContainer'] = self.startContainer self.__dict__['endOffset'] = self.startOffset self.__dict__['commonAncestorContainer'] = self.startContainer self.__dict__['collapsed'] = 1
return df
def insertNode(self,newNode): """Insert a node at the starting point"""
if self.detached: raise InvalidStateErr()
if newNode.nodeType in [Node.ATTRIBUTE_NODE, Node.ENTITY_NODE, Node.NOTATION_NODE, Node.DOCUMENT_NODE, ]: raise InvalidNodeTypeErr()
if self.startContainer.nodeType == Node.TEXT_NODE: #Split the text at the boundary. Insert the node after this otherText = self.startContainer.substringData(self.startOffset,len(self.startContainer.data)) self.startContainer.deleteData(self.startOffset,len(self.startContainer.data)) newText = self._ownerDocument.createTextNode(otherText) self.startContainer.parentNode.insertBefore(newText,self.startContainer.nextSibling)
newText.parentNode.insertBefore(newNode,newText) elif self.startContainer.nodeType in [Node.COMMENT_NODE, Node.PROCESSING_INSTRUCTION_NODE]: raise HierarchyRequestErr() else: curNode = self.startContainer.childNodes[self.startOffset] self.startContainer.insertBefore(newNode,curNode.nextSibling)
def selectNode(self,refNode): """Select a node""" if self.detached: raise InvalidStateErr()
self.__validateRefNode(refNode)
self.__dict__['startContainer'] = refNode.parentNode self.__dict__['endContainer'] = refNode.parentNode
index = refNode.parentNode.childNodes.index(refNode) self.__dict__['startOffset'] = index self.__dict__['endOffset'] = index+1
self.__dict__['collapsed'] = 0 self.__dict__['commonAncestorContainer'] = refNode.parentNode
def selectNodeContents(self,refNode): """Select a node""" if self.detached: raise InvalidStateErr()
self.__validateBoundary(refNode,0)
self.__dict__['startContainer'] = refNode self.__dict__['endContainer'] = refNode
self.__dict__['startOffset'] = 0 self.__dict__['endOffset'] = len(refNode.childNodes)
self.__dict__['collapsed'] = self.startOffset == self.endOffset self.__dict__['commonAncestorContainer'] = refNode
def setEnd(self,parent,offset): """Set the ranges end container and offset"""
#Check for errors if self.detached: raise InvalidStateErr()
self.__validateBoundary(parent,offset)
self.__dict__['endContainer'] = parent self.__dict__['endOffset'] = offset
self.__dict__['collapsed'] = 0
pos = self.__comparePositions(parent,offset,self.startContainer,self.startOffset) self.__dict__['collapsed'] = (pos == self.POSITION_EQUAL) if pos == self.POSITION_LESS_THAN: self.__dict__['startContainer'] = parent self.__dict__['startOffset'] = offset self.__dict__['collapsed'] = 1
self.__calculateCommonAncestor()
def setEndAfter(self,node):
self.__validateRefNode(node)
cont = node.parentNode index = cont.childNodes.index(node) self.setEnd(cont,index+1)
def setEndBefore(self,node):
self.__validateRefNode(node)
cont = node.parentNode index = cont.childNodes.index(node) self.setEnd(cont,index)
def setStart(self,parent,offset): """Set the ranges start container and offset"""
#Check for errors if self.detached: raise InvalidStateErr()
self.__validateBoundary(parent,offset)
self.__dict__['startContainer'] = parent self.__dict__['startOffset'] = offset
pos = self.__comparePositions(parent,offset,self.endContainer,self.endOffset) self.__dict__['collapsed'] = (pos == self.POSITION_EQUAL)
if pos == self.POSITION_GREATER_THAN: self.__dict__['endContainer'] = parent self.__dict__['endOffset'] = offset self.__dict__['collapsed'] = 1
self.__calculateCommonAncestor()
def setStartAfter(self,node):
self.__validateRefNode(node)
cont = node.parentNode index = cont.childNodes.index(node) self.setStart(cont,index+1)
def setStartBefore(self,node):
self.__validateRefNode(node)
cont = node.parentNode index = cont.childNodes.index(node) self.setStart(cont,index)
def surroundContents(self,newParent): """Surround the range with this node""" if self.detached: raise InvalidStateErr()
if newParent.nodeType in [Node.ATTRIBUTE_NODE, Node.ENTITY_NODE, Node.DOCUMENT_TYPE_NODE, Node.NOTATION_NODE, Node.DOCUMENT_NODE, Node.DOCUMENT_FRAGMENT_NODE]: raise InvalidNodeTypeErr()
#See is we have element nodes that are partially selected if self.startContainer.nodeType not in [Node.TEXT_NODE, Node.COMMENT_NODE, Node.PROCESSING_INSTRUCTION_NODE]: if self.commonAncestorContainer not in [self.startContainer,self.startContainer.parentNode]: #This is partially selected because our parent is not the common ancestor raise BadBoundaryPointsErr() if self.endContainer.nodeType not in [Node.TEXT_NODE, Node.COMMENT_NODE, Node.PROCESSING_INSTRUCTION_NODE]: if self.commonAncestorContainer not in [self.endContainer,self.endContainer.parentNode]: #This is partially selected because our parent is not the common ancestor raise BadBoundaryPointsErr()
#All good, do the insert #Remove children from newPArent for c in newParent.childNodes: newParent.removeChild(c)
df = self.extractContents()
self.insertNode(newParent)
newParent.appendChild(df)
self.selectNode(newParent)
def toString(self): if self.detached: raise InvalidStateErr()
df = self.cloneContents()
res = self.__recurseToString(df)
from xml.dom.ext import ReleaseNode ReleaseNode(df)
return res
#Internal Functions#
def __validateBoundary(self,node,offset): """Make sure the node is a legal boundary"""
if not hasattr(node,'nodeType'): raise InvalidNodeTypeErr()
#Check for proper node type curNode = node while curNode: if curNode.nodeType in [Node.ENTITY_NODE, Node.NOTATION_NODE, Node.DOCUMENT_TYPE_NODE, ]: raise InvalidNodeTypeErr() curNode = curNode.parentNode
#Check number of cild units if offset < 0: raise IndexSizeErr()
if node.nodeType in [Node.TEXT_NODE, Node.COMMENT_NODE, Node.PROCESSING_INSTRUCTION_NODE]: #Child units are characters if offset > len(node.data): raise IndexSizeErr() else: if offset > len(node.childNodes): raise IndexSizeErr()
def __validateRefNode(self,node):
if not hasattr(node,'nodeType'): raise InvalidNodeTypeErr()
cur = node while cur.parentNode: cur = cur.parentNode if cur.nodeType not in [Node.ATTRIBUTE_NODE, Node.DOCUMENT_NODE, Node.DOCUMENT_FRAGMENT_NODE, ]: raise InvalidNodeTypeErr()
if node.nodeType in [Node.DOCUMENT_NODE, Node.DOCUMENT_FRAGMENT_NODE, Node.ATTRIBUTE_NODE, Node.ENTITY_NODE, Node.NOTATION_NODE, ]:
raise InvalidNodeTypeErr()
def __comparePositions(self,aContainer,aOffset,bContainer,bOffset): """Compare Boundary Positions Section 2.5"""
if aContainer == bContainer: #CASE 1 if aOffset == bOffset: return self.POSITION_EQUAL elif aOffset < bOffset: return self.POSITION_LESS_THAN else: return self.POSITION_GREATER_THAN #CASE 2 bAncestors = [] cur = bContainer while cur: bAncestors.append(cur) cur = cur.parentNode
for ctr in range(len(aContainer.childNodes)): c = aContainer.childNodes[ctr] if c in bAncestors: if aOffset <= ctr: return self.POSITION_LESS_THAN else: return self.POSITION_GREATER_THAN
#CASE 3 aAncestors = [] cur = aContainer while cur: aAncestors.append(cur) cur = cur.parentNode
for ctr in range(len(bContainer.childNodes)): c = bContainer.childNodes[ctr] if c in aAncestors: if ctr < bOffset: return self.POSITION_LESS_THAN else: return self.POSITION_GREATER_THAN
#CASE 4 #Check the "Following axis" of A. #If B is in the axis, then A is before B
curr = aContainer while curr != aContainer.ownerDocument: sibling = curr.nextSibling while sibling: if curr == bContainer: return self.POSITION_LESS_THAN rt = self.__checkDescendants(sibling,bContainer) if rt: return self.POSITION_LESS_THAN sibling = sibling.nextSibling curr = ((curr.nodeType == Node.ATTRIBUTE_NODE) and curr.ownerElement or curr.parentNode)
#Not in the following, return POSITION_LESS_THAN return self.POSITION_GREATER_THAN
def __checkDescendants(self,sib,b): for c in sib.childNodes: if c == b: return 1 if self.__checkDescendants(c,b): return 1 return 0
def __calculateCommonAncestor(self):
if self.startContainer == self.endContainer: self.__dict__['commonAncestorContainer'] = self.startContainer
startAncestors = [] cur = self.startContainer while cur: startAncestors.append(cur) cur = cur.parentNode
cur = self.endContainer while cur: if cur in startAncestors: self.__dict__['commonAncestorContainer'] = cur return cur = cur.parentNode
#Hmm no ancestor raise BadBoundaryPointsErr()
def __recurseToString(self,node):
if node.nodeType in [Node.TEXT_NODE, Node.CDATA_SECTION_NODE]: return node.data else: res = "" for c in node.childNodes: res = res + self.__recurseToString(c) return res
|