diff options
author | Andreas Rumpf <rumpf_a@web.de> | 2014-08-01 02:28:51 +0200 |
---|---|---|
committer | Andreas Rumpf <rumpf_a@web.de> | 2014-08-01 02:28:51 +0200 |
commit | ee61a39cff88c361e8d5be978c570d50c4d991a5 (patch) | |
tree | 0913348067e7bdf17dbf5fa39e06b59e8d0ccdc9 /lib | |
parent | f43ec61568b42eb540fc5ee0f3e92ad12c7138b4 (diff) | |
parent | dc756a76187aa94c9eca18d070a9710ac4193218 (diff) | |
download | Nim-ee61a39cff88c361e8d5be978c570d50c4d991a5.tar.gz |
Merge pull request #1430 from def-/xmldom-nil
Add some nil checks for xmldom (and clean up a bit)
Diffstat (limited to 'lib')
-rw-r--r-- | lib/pure/xmldom.nim | 435 |
1 files changed, 231 insertions, 204 deletions
diff --git a/lib/pure/xmldom.nim b/lib/pure/xmldom.nim index 47e94243e..d63b6c5dd 100644 --- a/lib/pure/xmldom.nim +++ b/lib/pure/xmldom.nim @@ -45,7 +45,7 @@ const DocumentFragmentNode* = 11 # Nodes which are childless - Not sure about AttributeNode - childlessObjects = {DocumentNode, AttributeNode, TextNode, + childlessObjects = {DocumentNode, AttributeNode, TextNode, CDataSectionNode, ProcessingInstructionNode, CommentNode} # Illegal characters illegalChars = {'>', '<', '&', '"'} @@ -69,21 +69,21 @@ type FOwnerDocument: PDocument # Read-Only FParentNode: PNode # Read-Only prefix*: string # Setting this should change some values... TODO! - + PElement* = ref Element Element = object of Node FTagName: string # Read-only - + PCharacterData* = ref CharacterData CharacterData = object of Node data*: string - + PDocument* = ref Document Document = object of Node FImplementation: PDOMImplementation # Read-only FDocumentElement: PElement # Read-only - - PAttr* = ref Attr + + PAttr* = ref Attr Attr = object of Node FName: string # Read-only FSpecified: bool # Read-only @@ -95,13 +95,13 @@ type PText* = ref Text Text = object of CharacterData - + PComment* = ref comment Comment = object of CharacterData - + PCDataSection* = ref CDataSection CDataSection = object of Text - + PProcessingInstruction* = ref ProcessingInstruction ProcessingInstruction = object of Node data*: string @@ -111,8 +111,8 @@ type proc getDOM*(): PDOMImplementation = ## Returns a DOMImplementation new(result) - result.Features = @[(name: "core", version: "2.0"), - (name: "core", version: "1.0"), + result.Features = @[(name: "core", version: "2.0"), + (name: "core", version: "1.0"), (name: "XML", version: "2.0")] proc createDocument*(dom: PDOMImplementation, namespaceURI: string, qualifiedName: string): PDocument = @@ -121,28 +121,28 @@ proc createDocument*(dom: PDOMImplementation, namespaceURI: string, qualifiedNam new(doc) doc.FNamespaceURI = namespaceURI doc.FImplementation = dom - + var elTag: PElement new(elTag) elTag.FTagName = qualifiedName elTag.FNodeName = qualifiedName doc.FDocumentElement = elTag doc.FNodeType = DocumentNode - + return doc - + proc createDocument*(dom: PDOMImplementation, n: PElement): PDocument = ## Creates an XML Document object of the specified type with its document element. - + # This procedure is not in the specification, it's provided for the parser. var doc: PDocument new(doc) doc.FDocumentElement = n doc.FImplementation = dom doc.FNodeType = DocumentNode - + return doc - + proc hasFeature*(dom: PDOMImplementation, feature: string, version: string = ""): bool = ## Returns ``true`` if this ``version`` of the DomImplementation implements ``feature``, otherwise ``false`` for iName, iVersion in items(dom.Features): @@ -157,11 +157,11 @@ proc hasFeature*(dom: PDOMImplementation, feature: string, version: string = "") # Document # Attributes - + proc implementation*(doc: PDocument): PDOMImplementation = return doc.FImplementation - -proc documentElement*(doc: PDocument): PElement = + +proc documentElement*(doc: PDocument): PElement = return doc.FDocumentElement # Internal procedures @@ -175,13 +175,13 @@ proc findNodes(nl: PNode, name: string): seq[PNode] = if i.FNodeType == ElementNode: if i.FNodeName == name or name == "*": r.add(i) - + if not isNil(i.childNodes): if i.childNodes.len() != 0: r.add(findNodes(i, name)) - + return r - + proc findNodesNS(nl: PNode, namespaceURI: string, localName: string): seq[PNode] = # Made for getElementsByTagNameNS var r: seq[PNode] = @[] @@ -192,23 +192,23 @@ proc findNodesNS(nl: PNode, namespaceURI: string, localName: string): seq[PNode] if i.FNodeType == ElementNode: if (i.FNamespaceURI == namespaceURI or namespaceURI == "*") and (i.FLocalName == localName or localName == "*"): r.add(i) - + if not isNil(i.childNodes): if i.childNodes.len() != 0: r.add(findNodesNS(i, namespaceURI, localName)) - + return r - + #Procedures proc createAttribute*(doc: PDocument, name: string): PAttr = ## Creates an Attr of the given name. Note that the Attr instance can then be set on an Element using the setAttributeNode method. - ## To create an attribute with a qualified name and namespace URI, use the createAttributeNS method. - + ## To create an attribute with a qualified name and namespace URI, use the createAttributeNS method. + # Check if name contains illegal characters if illegalChars in name: raise newException(EInvalidCharacterErr, "Invalid character") - + var AttrNode: PAttr new(AttrNode) AttrNode.FName = name @@ -222,21 +222,21 @@ proc createAttribute*(doc: PDocument, name: string): PAttr = proc createAttributeNS*(doc: PDocument, namespaceURI: string, qualifiedName: string): PAttr = ## Creates an attribute of the given qualified name and namespace URI - + # Check if name contains illegal characters if illegalChars in namespaceURI or illegalChars in qualifiedName: raise newException(EInvalidCharacterErr, "Invalid character") # Exceptions if qualifiedName.contains(':'): - if namespaceURI == nil: + if isNil(namespaceURI): raise newException(ENamespaceErr, "When qualifiedName contains a prefix namespaceURI cannot be nil") elif qualifiedName.split(':')[0].toLower() == "xml" and namespaceURI != "http://www.w3.org/XML/1998/namespace": - raise newException(ENamespaceErr, + raise newException(ENamespaceErr, "When the namespace prefix is \"xml\" namespaceURI has to be \"http://www.w3.org/XML/1998/namespace\"") elif qualifiedName.split(':')[1].toLower() == "xmlns" and namespaceURI != "http://www.w3.org/2000/xmlns/": - raise newException(ENamespaceErr, + raise newException(ENamespaceErr, "When the namespace prefix is \"xmlns\" namespaceURI has to be \"http://www.w3.org/2000/xmlns/\"") - + var AttrNode: PAttr new(AttrNode) AttrNode.FName = qualifiedName @@ -250,7 +250,7 @@ proc createAttributeNS*(doc: PDocument, namespaceURI: string, qualifiedName: str AttrNode.prefix = nil AttrNode.FLocalName = qualifiedName AttrNode.value = "" - + AttrNode.FNodeType = AttributeNode return AttrNode @@ -265,12 +265,12 @@ proc createCDATASection*(doc: PDocument, data: string): PCDATASection = return CData proc createComment*(doc: PDocument, data: string): PComment = - ## Creates a Comment node given the specified string. + ## Creates a Comment node given the specified string. var Comm: PComment new(Comm) Comm.data = data Comm.nodeValue = data - + Comm.FNodeType = CommentNode return Comm @@ -282,11 +282,11 @@ proc createDocumentFragment*(doc: PDocument): PDocumentFragment = proc createElement*(doc: PDocument, tagName: string): PElement = ## Creates an element of the type specified. - + # Check if name contains illegal characters if illegalChars in tagName: raise newException(EInvalidCharacterErr, "Invalid character") - + var elNode: PElement new(elNode) elNode.FTagName = tagName @@ -296,24 +296,24 @@ proc createElement*(doc: PDocument, tagName: string): PElement = elNode.FNamespaceURI = nil elNode.childNodes = @[] elNode.attributes = @[] - + elNode.FNodeType = ElementNode - + return elNode proc createElementNS*(doc: PDocument, namespaceURI: string, qualifiedName: string): PElement = ## Creates an element of the given qualified name and namespace URI. if qualifiedName.contains(':'): - if namespaceURI == nil: + if isNIl(namespaceURI): raise newException(ENamespaceErr, "When qualifiedName contains a prefix namespaceURI cannot be nil") elif qualifiedName.split(':')[0].toLower() == "xml" and namespaceURI != "http://www.w3.org/XML/1998/namespace": - raise newException(ENamespaceErr, + raise newException(ENamespaceErr, "When the namespace prefix is \"xml\" namespaceURI has to be \"http://www.w3.org/XML/1998/namespace\"") - + # Check if name contains illegal characters if illegalChars in namespaceURI or illegalChars in qualifiedName: raise newException(EInvalidCharacterErr, "Invalid character") - + var elNode: PElement new(elNode) elNode.FTagName = qualifiedName @@ -327,18 +327,18 @@ proc createElementNS*(doc: PDocument, namespaceURI: string, qualifiedName: strin elNode.FNamespaceURI = namespaceURI elNode.childNodes = @[] elNode.attributes = @[] - + elNode.FNodeType = ElementNode - + return elNode -proc createProcessingInstruction*(doc: PDocument, target: string, data: string): PProcessingInstruction = - ## Creates a ProcessingInstruction node given the specified name and data strings. - +proc createProcessingInstruction*(doc: PDocument, target: string, data: string): PProcessingInstruction = + ## Creates a ProcessingInstruction node given the specified name and data strings. + #Check if name contains illegal characters if illegalChars in target: raise newException(EInvalidCharacterErr, "Invalid character") - + var PI: PProcessingInstruction new(PI) PI.FTarget = target @@ -347,13 +347,13 @@ proc createProcessingInstruction*(doc: PDocument, target: string, data: string): return PI proc createTextNode*(doc: PDocument, data: string): PText = #Propably TextNode - ## Creates a Text node given the specified string. + ## Creates a Text node given the specified string. var txtNode: PText new(txtNode) txtNode.data = data txtNode.nodeValue = data txtNode.FNodeName = "#text" - + txtNode.FNodeType = TextNode return txtNode @@ -363,22 +363,22 @@ discard """proc getElementById*(doc: PDocument, elementId: string): PElement = proc getElementsByTagName*(doc: PDocument, tagName: string): seq[PNode] = ## Returns a NodeList of all the Elements with a given tag name in - ## the order in which they are encountered in a preorder traversal of the Document tree. + ## the order in which they are encountered in a preorder traversal of the Document tree. var result: seq[PNode] = @[] if doc.FDocumentElement.FNodeName == tagName or tagName == "*": result.add(doc.FDocumentElement) - + result.add(doc.FDocumentElement.findNodes(tagName)) return result - + proc getElementsByTagNameNS*(doc: PDocument, namespaceURI: string, localName: string): seq[PNode] = ## Returns a NodeList of all the Elements with a given localName and namespaceURI - ## in the order in which they are encountered in a preorder traversal of the Document tree. + ## in the order in which they are encountered in a preorder traversal of the Document tree. var result: seq[PNode] = @[] if doc.FDocumentElement.FLocalName == localName or localName == "*": if doc.FDocumentElement.FNamespaceURI == namespaceURI or namespaceURI == "*": result.add(doc.FDocumentElement) - + result.add(doc.FDocumentElement.findNodesNS(namespaceURI, localName)) return result @@ -406,7 +406,7 @@ proc importNode*(doc: PDocument, importedNode: PNode, deep: bool): PNode = if deep: for i in low(tmp.len())..high(tmp.len()): n.childNodes.add(importNode(doc, tmp[i], deep)) - + return n of ElementNode: var n: PNode @@ -414,7 +414,7 @@ proc importNode*(doc: PDocument, importedNode: PNode, deep: bool): PNode = n = importedNode n.FOwnerDocument = doc n.FParentNode = nil - + var tmpA: seq[PAttr] = n.attributes n.attributes = @[] # Import the Element node's attributes @@ -426,7 +426,7 @@ proc importNode*(doc: PDocument, importedNode: PNode, deep: bool): PNode = if deep: for i in low(tmp.len())..high(tmp.len()): n.childNodes.add(importNode(doc, tmp[i], deep)) - + return n of ProcessingInstructionNode, TextNode, CDataSectionNode, CommentNode: var n: PNode @@ -437,27 +437,27 @@ proc importNode*(doc: PDocument, importedNode: PNode, deep: bool): PNode = return n else: raise newException(ENotSupportedErr, "The type of node being imported is not supported") - + # Node # Attributes - + proc firstChild*(n: PNode): PNode = ## Returns this node's first child - if n.childNodes.len() > 0: + if not isNil(n.childNodes) and n.childNodes.len() > 0: return n.childNodes[0] else: return nil - + proc lastChild*(n: PNode): PNode = ## Returns this node's last child - if n.childNodes.len() > 0: + if not isNil(n.childNodes) and n.childNodes.len() > 0: return n.childNodes[n.childNodes.len() - 1] else: return nil - + proc localName*(n: PNode): string = ## Returns this nodes local name @@ -465,15 +465,17 @@ proc localName*(n: PNode): string = proc namespaceURI*(n: PNode): string = ## Returns this nodes namespace URI - + return n.FNamespaceURI - -proc `namespaceURI=`*(n: PNode, value: string) = + +proc `namespaceURI=`*(n: PNode, value: string) = n.FNamespaceURI = value proc nextSibling*(n: PNode): PNode = ## Returns the next sibling of this node + if isNil(n.FParentNode) or isNil(n.FParentNode.childNodes): + return nil var nLow: int = low(n.FParentNode.childNodes) var nHigh: int = high(n.FParentNode.childNodes) for i in nLow..nHigh: @@ -500,17 +502,19 @@ proc parentNode*(n: PNode): PNode = ## Returns the parent node of this node return n.FParentNode - + proc previousSibling*(n: PNode): PNode = ## Returns the previous sibling of this node + if isNil(n.FParentNode) or isNil(n.FParentNode.childNodes): + return nil var nLow: int = low(n.FParentNode.childNodes) var nHigh: int = high(n.FParentNode.childNodes) for i in nLow..nHigh: if n.FParentNode.childNodes[i] == n: return n.FParentNode.childNodes[i - 1] return nil - + proc `prefix=`*(n: PNode, value: string) = ## Modifies the prefix of this node @@ -519,13 +523,13 @@ proc `prefix=`*(n: PNode, value: string) = if illegalChars in value: raise newException(EInvalidCharacterErr, "Invalid character") - if n.FNamespaceURI == nil: + if isNil(n.FNamespaceURI): raise newException(ENamespaceErr, "namespaceURI cannot be nil") elif value.toLower() == "xml" and n.FNamespaceURI != "http://www.w3.org/XML/1998/namespace": - raise newException(ENamespaceErr, + raise newException(ENamespaceErr, "When the namespace prefix is \"xml\" namespaceURI has to be \"http://www.w3.org/XML/1998/namespace\"") elif value.toLower() == "xmlns" and n.FNamespaceURI != "http://www.w3.org/2000/xmlns/": - raise newException(ENamespaceErr, + raise newException(ENamespaceErr, "When the namespace prefix is \"xmlns\" namespaceURI has to be \"http://www.w3.org/2000/xmlns/\"") elif value.toLower() == "xmlns" and n.FNodeType == AttributeNode: raise newException(ENamespaceErr, "An AttributeNode cannot have a prefix of \"xmlns\"") @@ -543,33 +547,33 @@ proc `prefix=`*(n: PNode, value: string) = proc appendChild*(n: PNode, newChild: PNode) = ## Adds the node newChild to the end of the list of children of this node. ## If the newChild is already in the tree, it is first removed. - + # Check if n contains newChild - if not IsNil(n.childNodes): + if not isNil(n.childNodes): for i in low(n.childNodes)..high(n.childNodes): if n.childNodes[i] == newChild: raise newException(EHierarchyRequestErr, "The node to append is already in this nodes children.") - + # Check if newChild is from this nodes document if n.FOwnerDocument != newChild.FOwnerDocument: raise newException(EWrongDocumentErr, "This node belongs to a different document, use importNode.") - + if n == newChild: raise newException(EHierarchyRequestErr, "You can't add a node into itself") - + if n.nodeType in childlessObjects: raise newException(ENoModificationAllowedErr, "Cannot append children to a childless node") - + if isNil(n.childNodes): n.childNodes = @[] - + newChild.FParentNode = n for i in low(n.childNodes)..high(n.childNodes): if n.childNodes[i] == newChild: n.childNodes[i] = newChild - + n.childNodes.add(newChild) -proc cloneNode*(n: PNode, deep: bool): PNode = +proc cloneNode*(n: PNode, deep: bool): PNode = ## Returns a duplicate of this node, if ``deep`` is `true`, Element node's children are copied case n.FNodeType of AttributeNode: @@ -586,7 +590,7 @@ proc cloneNode*(n: PNode, deep: bool): PNode = # Import the childNodes var tmp: seq[PNode] = n.childNodes n.childNodes = @[] - if deep: + if deep and not isNil(tmp): for i in low(tmp.len())..high(tmp.len()): n.childNodes.add(cloneNode(tmp[i], deep)) return newNode @@ -597,34 +601,39 @@ proc cloneNode*(n: PNode, deep: bool): PNode = return newNode proc hasAttributes*(n: PNode): bool = - ## Returns whether this node (if it is an element) has any attributes. - return n.attributes.len() > 0 + ## Returns whether this node (if it is an element) has any attributes. + return not isNil(n.attributes) and n.attributes.len() > 0 -proc hasChildNodes*(n: PNode): bool = +proc hasChildNodes*(n: PNode): bool = ## Returns whether this node has any children. - return n.childNodes.len() > 0 + return not isNil(n.childNodes) and n.childNodes.len() > 0 proc insertBefore*(n: PNode, newChild: PNode, refChild: PNode): PNode = ## Inserts the node ``newChild`` before the existing child node ``refChild``. ## If ``refChild`` is nil, insert ``newChild`` at the end of the list of children. - + # Check if newChild is from this nodes document if n.FOwnerDocument != newChild.FOwnerDocument: raise newException(EWrongDocumentErr, "This node belongs to a different document, use importNode.") - + + if isNil(n.childNodes): + n.ChildNodes = @[] + for i in low(n.childNodes)..high(n.childNodes): if n.childNodes[i] == refChild: n.childNodes.insert(newChild, i - 1) - return + return + + n.ChildNodes.add(newChild) proc isSupported*(n: PNode, feature: string, version: string): bool = - ## Tests whether the DOM implementation implements a specific - ## feature and that feature is supported by this node. + ## Tests whether the DOM implementation implements a specific + ## feature and that feature is supported by this node. return n.FOwnerDocument.FImplementation.hasFeature(feature, version) proc isEmpty(s: string): bool = - if s == "" or s == nil: + if isNil(s) or s == "": return True for i in items(s): if i != ' ': @@ -635,18 +644,18 @@ proc normalize*(n: PNode) = ## Merges all seperated TextNodes together, and removes any empty TextNodes var curTextNode: PNode = nil var i: int = 0 - + var newChildNodes: seq[PNode] = @[] while True: - if i >= n.childNodes.len: + if isNil(n.childNodes) or i >= n.childNodes.len: break if n.childNodes[i].nodeType == TextNode: - + #If the TextNode is empty, remove it if PText(n.childNodes[i]).data.isEmpty(): inc(i) - - if curTextNode == nil: + + if isNil(curTextNode): curTextNode = n.childNodes[i] else: PText(curTextNode).data.add(PText(n.childNodes[i]).data) @@ -656,35 +665,37 @@ proc normalize*(n: PNode) = newChildNodes.add(curTextNode) newChildNodes.add(n.childNodes[i]) curTextNode = nil - + inc(i) n.childNodes = newChildNodes proc removeChild*(n: PNode, oldChild: PNode): PNode = ## Removes the child node indicated by ``oldChild`` from the list of children, and returns it. - for i in low(n.childNodes)..high(n.childNodes): - if n.childNodes[i] == oldChild: - result = n.childNodes[i] - n.childNodes.delete(i) - return result - + if not isNil(n.childNodes): + for i in low(n.childNodes)..high(n.childNodes): + if n.childNodes[i] == oldChild: + result = n.childNodes[i] + n.childNodes.delete(i) + return result + raise newException(ENotFoundErr, "Node not found") - + proc replaceChild*(n: PNode, newChild: PNode, oldChild: PNode): PNode = ## Replaces the child node ``oldChild`` with ``newChild`` in the list of children, and returns the ``oldChild`` node. - + # Check if newChild is from this nodes document if n.FOwnerDocument != newChild.FOwnerDocument: raise newException(EWrongDocumentErr, "This node belongs to a different document, use importNode.") - - for i in low(n.childNodes)..high(n.childNodes): - if n.childNodes[i] == oldChild: - result = n.childNodes[i] - n.childNodes[i] = newChild - return result - + + if not isNil(n.childNodes): + for i in low(n.childNodes)..high(n.childNodes): + if n.childNodes[i] == oldChild: + result = n.childNodes[i] + n.childNodes[i] = newChild + return result + raise newException(ENotFoundErr, "Node not found") - + # NamedNodeMap proc getNamedItem*(NList: seq[PNode], name: string): PNode = @@ -693,22 +704,22 @@ proc getNamedItem*(NList: seq[PNode], name: string): PNode = if i.nodeName() == name: return i return nil - + proc getNamedItem*(NList: seq[PAttr], name: string): PAttr = ## Retrieves a node specified by ``name``. If this node cannot be found returns ``nil`` for i in items(NList): if i.nodeName() == name: return i return nil - + proc getNamedItemNS*(NList: seq[PNode], namespaceURI: string, localName: string): PNode = ## Retrieves a node specified by ``localName`` and ``namespaceURI``. If this node cannot be found returns ``nil`` for i in items(NList): if i.namespaceURI() == namespaceURI and i.localName() == localName: return i return nil - -proc getNamedItemNS*(NList: seq[PAttr], namespaceURI: string, localName: string): PAttr = + +proc getNamedItemNS*(NList: seq[PAttr], namespaceURI: string, localName: string): PAttr = ## Retrieves a node specified by ``localName`` and ``namespaceURI``. If this node cannot be found returns ``nil`` for i in items(NList): if i.NamespaceURI() == namespaceURI and i.LocalName() == localName: @@ -716,7 +727,7 @@ proc getNamedItemNS*(NList: seq[PAttr], namespaceURI: string, localName: string) return nil proc item*(NList: seq[PNode], index: int): PNode = - ## Returns the ``index`` th item in the map. + ## Returns the ``index`` th item in the map. ## If ``index`` is greater than or equal to the number of nodes in this map, this returns ``nil``. if index >= NList.len(): return nil else: return NList[index] @@ -729,9 +740,9 @@ proc removeNamedItem*(NList: var seq[PNode], name: string): PNode = result = NList[i] NList.delete(i) return result - + raise newException(ENotFoundErr, "Node not found") - + proc removeNamedItemNS*(NList: var seq[PNode], namespaceURI: string, localName: string): PNode = ## Removes a node specified by local name and namespace URI for i in low(NList)..high(NList): @@ -739,7 +750,7 @@ proc removeNamedItemNS*(NList: var seq[PNode], namespaceURI: string, localName: result = NList[i] NList.delete(i) return result - + raise newException(ENotFoundErr, "Node not found") proc setNamedItem*(NList: var seq[PNode], arg: PNode): PNode = @@ -751,9 +762,9 @@ proc setNamedItem*(NList: var seq[PNode], arg: PNode): PNode = if NList[0].FOwnerDocument != arg.FOwnerDocument: raise newException(EWrongDocumentErr, "This node belongs to a different document, use importNode.") #Exceptions End - + var item: PNode = NList.getNamedItem(arg.NodeName()) - if item == nil: + if isNil(item): NList.add(arg) return nil else: @@ -765,22 +776,22 @@ proc setNamedItem*(NList: var seq[PNode], arg: PNode): PNode = break NList[index] = arg return item # Return the replaced node - + proc setNamedItem*(NList: var seq[PAttr], arg: PAttr): PAttr = ## Adds ``arg`` as a ``Node`` to the ``NList`` ## If a node with the same name is already present in this map, it is replaced by the new one. - if not IsNil(NList): + if not isNil(NList): if NList.len() > 0: # Check if newChild is from this nodes document if NList[0].FOwnerDocument != arg.FOwnerDocument: raise newException(EWrongDocumentErr, "This node belongs to a different document, use importNode.") - - if arg.FOwnerElement != nil: + + if not isNil(arg.FOwnerElement): raise newException(EInuseAttributeErr, "This attribute is in use by another element, use cloneNode") - + # Exceptions end var item: PAttr = NList.getNamedItem(arg.nodeName()) - if item == nil: + if isNil(item): NList.add(arg) return nil else: @@ -792,18 +803,18 @@ proc setNamedItem*(NList: var seq[PAttr], arg: PAttr): PAttr = break NList[index] = arg return item # Return the replaced node - + proc setNamedItemNS*(NList: var seq[PNode], arg: PNode): PNode = ## Adds a node using its ``namespaceURI`` and ``localName`` - if not IsNil(NList): + if not isNil(NList): if NList.len() > 0: # Check if newChild is from this nodes document if NList[0].FOwnerDocument != arg.FOwnerDocument: raise newException(EWrongDocumentErr, "This node belongs to a different document, use importNode.") #Exceptions end - + var item: PNode = NList.getNamedItemNS(arg.namespaceURI(), arg.localName()) - if item == nil: + if isNil(item): NList.add(arg) return nil else: @@ -815,7 +826,7 @@ proc setNamedItemNS*(NList: var seq[PNode], arg: PNode): PNode = break NList[index] = arg return item # Return the replaced node - + proc setNamedItemNS*(NList: var seq[PAttr], arg: PAttr): PAttr = ## Adds a node using its ``namespaceURI`` and ``localName`` if not isNil(NList): @@ -823,13 +834,13 @@ proc setNamedItemNS*(NList: var seq[PAttr], arg: PAttr): PAttr = # Check if newChild is from this nodes document if NList[0].FOwnerDocument != arg.FOwnerDocument: raise newException(EWrongDocumentErr, "This node belongs to a different document, use importNode.") - - if arg.FOwnerElement != nil: + + if not isNil(arg.FOwnerElement): raise newException(EInuseAttributeErr, "This attribute is in use by another element, use cloneNode") - + # Exceptions end var item: PAttr = NList.getNamedItemNS(arg.namespaceURI(), arg.localName()) - if item == nil: + if isNil(item): NList.add(arg) return nil else: @@ -841,8 +852,8 @@ proc setNamedItemNS*(NList: var seq[PAttr], arg: PAttr): PAttr = break NList[index] = arg return item # Return the replaced node - -# CharacterData - Decided to implement this, + +# CharacterData - Decided to implement this, # Didn't add the procedures, because you can just edit .data # Attr @@ -851,13 +862,13 @@ proc name*(a: PAttr): string = ## Returns the name of the Attribute return a.FName - + proc specified*(a: PAttr): bool = ## Specifies whether this attribute was specified in the original document return a.FSpecified - -proc ownerElement*(a: PAttr): PElement = + +proc ownerElement*(a: PAttr): PElement = ## Returns this Attributes owner element return a.FOwnerElement @@ -873,27 +884,35 @@ proc tagName*(el: PElement): string = # Procedures proc getAttribute*(el: PElement, name: string): string = ## Retrieves an attribute value by ``name`` + if isNil(el.attributes): + return nil var attribute = el.attributes.getNamedItem(name) - if attribute != nil: + if not isNil(attribute): return attribute.value else: return nil proc getAttributeNS*(el: PElement, namespaceURI: string, localName: string): string = ## Retrieves an attribute value by ``localName`` and ``namespaceURI`` + if isNil(el.attributes): + return nil var attribute = el.attributes.getNamedItemNS(namespaceURI, localName) - if attribute != nil: + if not isNil(attribute): return attribute.value else: return nil - + proc getAttributeNode*(el: PElement, name: string): PAttr = ## Retrieves an attribute node by ``name`` ## To retrieve an attribute node by qualified name and namespace URI, use the `getAttributeNodeNS` method + if isNil(el.attributes): + return nil return el.attributes.getNamedItem(name) proc getAttributeNodeNS*(el: PElement, namespaceURI: string, localName: string): PAttr = ## Retrieves an `Attr` node by ``localName`` and ``namespaceURI`` + if isNil(el.attributes): + return nil return el.attributes.getNamedItemNS(namespaceURI, localName) proc getElementsByTagName*(el: PElement, name: string): seq[PNode] = @@ -909,103 +928,110 @@ proc getElementsByTagNameNS*(el: PElement, namespaceURI: string, localName: stri result = el.findNodesNS(namespaceURI, localName) proc hasAttribute*(el: PElement, name: string): bool = - ## Returns ``true`` when an attribute with a given ``name`` is specified - ## on this element , ``false`` otherwise. - return el.attributes.getNamedItem(name) != nil + ## Returns ``true`` when an attribute with a given ``name`` is specified + ## on this element , ``false`` otherwise. + if isNil(el.attributes): + return false + return not isNil(el.attributes.getNamedItem(name)) proc hasAttributeNS*(el: PElement, namespaceURI: string, localName: string): bool = ## Returns ``true`` when an attribute with a given ``localName`` and - ## ``namespaceURI`` is specified on this element , ``false`` otherwise - return el.attributes.getNamedItemNS(namespaceURI, localName) != nil + ## ``namespaceURI`` is specified on this element , ``false`` otherwise + if isNil(el.attributes): + return false + return not isNil(el.attributes.getNamedItemNS(namespaceURI, localName)) proc removeAttribute*(el: PElement, name: string) = ## Removes an attribute by ``name`` - for i in low(el.attributes)..high(el.attributes): - if el.attributes[i].FName == name: - el.attributes.delete(i) - + if not isNil(el.attributes): + for i in low(el.attributes)..high(el.attributes): + if el.attributes[i].FName == name: + el.attributes.delete(i) + proc removeAttributeNS*(el: PElement, namespaceURI: string, localName: string) = ## Removes an attribute by ``localName`` and ``namespaceURI`` - for i in low(el.attributes)..high(el.attributes): - if el.attributes[i].FNamespaceURI == namespaceURI and - el.attributes[i].FLocalName == localName: - el.attributes.delete(i) - + if not isNil(el.attributes): + for i in low(el.attributes)..high(el.attributes): + if el.attributes[i].FNamespaceURI == namespaceURI and + el.attributes[i].FLocalName == localName: + el.attributes.delete(i) + proc removeAttributeNode*(el: PElement, oldAttr: PAttr): PAttr = ## Removes the specified attribute node ## If the attribute node cannot be found raises ``ENotFoundErr`` - for i in low(el.attributes)..high(el.attributes): - if el.attributes[i] == oldAttr: - result = el.attributes[i] - el.attributes.delete(i) - return result - + if not isNil(el.attributes): + for i in low(el.attributes)..high(el.attributes): + if el.attributes[i] == oldAttr: + result = el.attributes[i] + el.attributes.delete(i) + return result + raise newException(ENotFoundErr, "oldAttr is not a member of el's Attributes") proc setAttributeNode*(el: PElement, newAttr: PAttr): PAttr = ## Adds a new attribute node, if an attribute with the same `nodeName` is ## present, it is replaced by the new one and the replaced attribute is ## returned, otherwise ``nil`` is returned. - + # Check if newAttr is from this nodes document if el.FOwnerDocument != newAttr.FOwnerDocument: - raise newException(EWrongDocumentErr, + raise newException(EWrongDocumentErr, "This node belongs to a different document, use importNode.") - - if newAttr.FOwnerElement != nil: - raise newException(EInuseAttributeErr, + + if not isNil(newAttr.FOwnerElement): + raise newException(EInuseAttributeErr, "This attribute is in use by another element, use cloneNode") # Exceptions end - + if isNil(el.attributes): el.attributes = @[] return el.attributes.setNamedItem(newAttr) - + proc setAttributeNodeNS*(el: PElement, newAttr: PAttr): PAttr = - ## Adds a new attribute node, if an attribute with the localName and + ## Adds a new attribute node, if an attribute with the localName and ## namespaceURI of ``newAttr`` is present, it is replaced by the new one ## and the replaced attribute is returned, otherwise ``nil`` is returned. - + # Check if newAttr is from this nodes document if el.FOwnerDocument != newAttr.FOwnerDocument: - raise newException(EWrongDocumentErr, + raise newException(EWrongDocumentErr, "This node belongs to a different document, use importNode.") - - if newAttr.FOwnerElement != nil: - raise newException(EInuseAttributeErr, + + if not isNil(newAttr.FOwnerElement): + raise newException(EInuseAttributeErr, "This attribute is in use by another element, use cloneNode") # Exceptions end - + if isNil(el.attributes): el.attributes = @[] return el.attributes.setNamedItemNS(newAttr) proc setAttribute*(el: PElement, name: string, value: string) = ## Adds a new attribute, as specified by ``name`` and ``value`` - ## If an attribute with that name is already present in the element, its + ## If an attribute with that name is already present in the element, its ## value is changed to be that of the value parameter - ## Raises the EInvalidCharacterErr if the specified ``name`` contains + ## Raises the EInvalidCharacterErr if the specified ``name`` contains ## illegal characters var AttrNode = el.FOwnerDocument.createAttribute(name) # Check if name contains illegal characters if illegalChars in name: raise newException(EInvalidCharacterErr, "Invalid character") - + discard el.setAttributeNode(AttrNode) # Set the info later, the setAttributeNode checks # if FOwnerElement is nil, and if it isn't it raises an exception AttrNode.FOwnerElement = el AttrNode.FSpecified = True AttrNode.value = value - + proc setAttributeNS*(el: PElement, namespaceURI, localName, value: string) = - ## Adds a new attribute, as specified by ``namespaceURI``, ``localName`` + ## Adds a new attribute, as specified by ``namespaceURI``, ``localName`` ## and ``value``. - + # Check if name contains illegal characters if illegalChars in namespaceURI or illegalChars in localName: raise newException(EInvalidCharacterErr, "Invalid character") - + var AttrNode = el.FOwnerDocument.createAttributeNS(namespaceURI, localName) - + discard el.setAttributeNodeNS(AttrNode) # Set the info later, the setAttributeNode checks # if FOwnerElement is nil, and if it isn't it raises an exception @@ -1013,19 +1039,19 @@ proc setAttributeNS*(el: PElement, namespaceURI, localName, value: string) = AttrNode.FSpecified = True AttrNode.value = value -# Text +# Text proc splitData*(TextNode: PText, offset: int): PText = - ## Breaks this node into two nodes at the specified offset, + ## Breaks this node into two nodes at the specified offset, ## keeping both in the tree as siblings. - + if offset > TextNode.data.len(): raise newException(EIndexSizeErr, "Index out of bounds") - + var left: string = TextNode.data.substr(0, offset) TextNode.data = left var right: string = TextNode.data.substr(offset, TextNode.data.len()) - - if TextNode.FParentNode != nil: + + if not isNil(TextNode.FParentNode) and not isNil(TextNode.FParentNode.childNodes): for i in low(TextNode.FParentNode.childNodes)..high(TextNode.FParentNode.childNodes): if TextNode.FParentNode.childNodes[i] == TextNode: var newNode: PText = TextNode.FOwnerDocument.createTextNode(right) @@ -1042,10 +1068,10 @@ proc target*(PI: PProcessingInstruction): string = return PI.FTarget - + # --Other stuff-- # Writer -proc addEscaped(s: string): string = +proc addEscaped(s: string): string = result = "" for c in items(s): case c @@ -1057,10 +1083,11 @@ proc addEscaped(s: string): string = proc nodeToXml(n: PNode, indent: int = 0): string = result = repeatChar(indent, ' ') & "<" & n.nodeName - for i in items(n.Attributes): - result.add(" " & i.name & "=\"" & addEscaped(i.value) & "\"") - - if n.childNodes.len() == 0: + if not isNil(n.attributes): + for i in items(n.attributes): + result.add(" " & i.name & "=\"" & addEscaped(i.value) & "\"") + + if isNil(n.childNodes) or n.childNodes.len() == 0: result.add("/>") # No idea why this doesn't need a \n :O else: # End the beginning of this tag |