summary refs log tree commit diff stats
path: root/lib/pure/xmldom.nim
diff options
context:
space:
mode:
Diffstat (limited to 'lib/pure/xmldom.nim')
-rwxr-xr-xlib/pure/xmldom.nim1094
1 files changed, 0 insertions, 1094 deletions
diff --git a/lib/pure/xmldom.nim b/lib/pure/xmldom.nim
deleted file mode 100755
index 47e94243e..000000000
--- a/lib/pure/xmldom.nim
+++ /dev/null
@@ -1,1094 +0,0 @@
-#
-#
-#            Nimrod's Runtime Library
-#        (c) Copyright 2010 Dominik Picheta
-#
-#    See the file "copying.txt", included in this
-#    distribution, for details about the copyright.
-#
-
-
-import strutils
-## This module implements XML DOM Level 2 Core specification(http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/core.html)
-
-
-#http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/core.html
-
-#Exceptions
-type
-  EDOMException* = object of EInvalidValue ## Base exception object for all DOM Exceptions
-  EDOMStringSizeErr* = object of EDOMException ## If the specified range of text does not fit into a DOMString
-                                               ## Currently not used(Since DOMString is just string)
-  EHierarchyRequestErr* = object of EDOMException ## If any node is inserted somewhere it doesn't belong
-  EIndexSizeErr* = object of EDOMException ## If index or size is negative, or greater than the allowed value
-  EInuseAttributeErr* = object of EDOMException ## If an attempt is made to add an attribute that is already in use elsewhere
-  EInvalidAccessErr* = object of EDOMException ## If a parameter or an operation is not supported by the underlying object.
-  EInvalidCharacterErr* = object of EDOMException ## This exception is raised when a string parameter contains an illegal character
-  EInvalidModificationErr* = object of EDOMException ## If an attempt is made to modify the type of the underlying object.
-  EInvalidStateErr* = object of EDOMException ## If an attempt is made to use an object that is not, or is no longer, usable.
-  ENamespaceErr* = object of EDOMException ## If an attempt is made to create or change an object in a way which is incorrect with regard to namespaces.
-  ENotFoundErr* = object of EDOMException ## If an attempt is made to reference a node in a context where it does not exist
-  ENotSupportedErr* = object of EDOMException ## If the implementation does not support the requested type of object or operation.
-  ENoDataAllowedErr* = object of EDOMException ## If data is specified for a node which does not support data
-  ENoModificationAllowedErr* = object of EDOMException ## If an attempt is made to modify an object where modifications are not allowed
-  ESyntaxErr* = object of EDOMException ## If an invalid or illegal string is specified.
-  EWrongDocumentErr* = object of EDOMException ## If a node is used in a different document than the one that created it (that doesn't support it)
-
-const
-  ElementNode* = 1
-  AttributeNode* = 2
-  TextNode* = 3
-  CDataSectionNode* = 4
-  ProcessingInstructionNode* = 7
-  CommentNode* = 8
-  DocumentNode* = 9
-  DocumentFragmentNode* = 11
-
-  # Nodes which are childless - Not sure about AttributeNode
-  childlessObjects = {DocumentNode, AttributeNode, TextNode, 
-    CDataSectionNode, ProcessingInstructionNode, CommentNode}
-  # Illegal characters
-  illegalChars = {'>', '<', '&', '"'}
-
-
-type
-  Feature = tuple[name: string, version: string]
-  PDOMImplementation* = ref DOMImplementation
-  DOMImplementation = object
-    Features: seq[Feature] # Read-Only
-
-  PNode* = ref Node
-  Node = object of TObject
-    attributes*: seq[PAttr]
-    childNodes*: seq[PNode]
-    FLocalName: string # Read-only
-    FNamespaceURI: string # Read-only
-    FNodeName: string # Read-only
-    nodeValue*: string
-    FNodeType: int # Read-only
-    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  
-  Attr = object of Node
-    FName: string # Read-only
-    FSpecified: bool # Read-only
-    value*: string
-    FOwnerElement: PElement # Read-only
-
-  PDocumentFragment* = ref DocumentFragment
-  DocumentFragment = object of Node
-
-  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
-    FTarget: string # Read-only
-
-# DOMImplementation
-proc getDOM*(): PDOMImplementation =
-  ## Returns a DOMImplementation
-  new(result)
-  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 =
-  ## Creates an XML Document object of the specified type with its document element.
-  var doc: PDocument
-  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):
-    if iName == feature:
-      if version == "":
-        return True
-      else:
-        if iVersion == version:
-          return True
-  return False
-
-
-# Document
-# Attributes
-  
-proc implementation*(doc: PDocument): PDOMImplementation =
-  return doc.FImplementation
-  
-proc documentElement*(doc: PDocument): PElement = 
-  return doc.FDocumentElement
-
-# Internal procedures
-proc findNodes(nl: PNode, name: string): seq[PNode] =
-  # Made for getElementsByTagName
-  var r: seq[PNode] = @[]
-  if isNil(nl.childNodes): return @[]
-  if nl.childNodes.len() == 0: return @[]
-
-  for i in items(nl.childNodes):
-    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] = @[]
-  if isNil(nl.childNodes): return @[]
-  if nl.childNodes.len() == 0: return @[]
-
-  for i in items(nl.childNodes):
-    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. 
-  
-  # Check if name contains illegal characters
-  if illegalChars in name:
-    raise newException(EInvalidCharacterErr, "Invalid character")
-  
-  var AttrNode: PAttr
-  new(AttrNode)
-  AttrNode.FName = name
-  AttrNode.FNodeName = name
-  AttrNode.FLocalName = nil
-  AttrNode.prefix = nil
-  AttrNode.FNamespaceURI = nil
-  AttrNode.value = ""
-  AttrNode.FSpecified = False
-  return AttrNode
-
-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:
-      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, 
-        "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, 
-        "When the namespace prefix is \"xmlns\" namespaceURI has to be \"http://www.w3.org/2000/xmlns/\"")
-  
-  var AttrNode: PAttr
-  new(AttrNode)
-  AttrNode.FName = qualifiedName
-  AttrNode.FNodeName = qualifiedName
-  AttrNode.FSpecified = False
-  AttrNode.FNamespaceURI = namespaceURI
-  if qualifiedName.contains(':'):
-    AttrNode.prefix = qualifiedName.split(':')[0]
-    AttrNode.FLocalName = qualifiedName.split(':')[1]
-  else:
-    AttrNode.prefix = nil
-    AttrNode.FLocalName = qualifiedName
-  AttrNode.value = ""
-  
-  AttrNode.FNodeType = AttributeNode
-  return AttrNode
-
-proc createCDATASection*(doc: PDocument, data: string): PCDATASection =
-  ## Creates a CDATASection node whose value is the specified string.
-  var CData: PCDATASection
-  new(CData)
-  CData.data = data
-  CData.nodeValue = data
-  CData.FNodeName = "#text" # Not sure about this, but this is technically a TextNode
-  CData.FNodeType = CDataSectionNode
-  return CData
-
-proc createComment*(doc: PDocument, data: string): PComment =
-  ## Creates a Comment node given the specified string. 
-  var Comm: PComment
-  new(Comm)
-  Comm.data = data
-  Comm.nodeValue = data
-  
-  Comm.FNodeType = CommentNode
-  return Comm
-
-proc createDocumentFragment*(doc: PDocument): PDocumentFragment =
-  ## Creates an empty DocumentFragment object.
-  var DF: PDocumentFragment
-  new(DF)
-  return DF
-
-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
-  elNode.FNodeName = tagName
-  elNode.FLocalName = nil
-  elNode.prefix = nil
-  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:
-      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, 
-        "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
-  elNode.FNodeName = qualifiedName
-  if qualifiedName.contains(':'):
-    elNode.prefix = qualifiedName.split(':')[0]
-    elNode.FLocalName = qualifiedName.split(':')[1]
-  else:
-    elNode.prefix = nil
-    elNode.FLocalName = qualifiedName
-  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. 
-  
-  #Check if name contains illegal characters
-  if illegalChars in target:
-    raise newException(EInvalidCharacterErr, "Invalid character")
-    
-  var PI: PProcessingInstruction
-  new(PI)
-  PI.FTarget = target
-  PI.data = data
-  PI.FNodeType = ProcessingInstructionNode
-  return PI
-
-proc createTextNode*(doc: PDocument, data: string): PText = #Propably TextNode
-  ## 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
-
-discard """proc getElementById*(doc: PDocument, elementId: string): PElement =
-  ##Returns the ``Element`` whose ID is given by ``elementId``. If no such element exists, returns ``nil``
-  #TODO"""
-
-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. 
-  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. 
-  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
-
-proc importNode*(doc: PDocument, importedNode: PNode, deep: bool): PNode =
-  ## Imports a node from another document to this document
-  case importedNode.FNodeType
-  of AttributeNode:
-    var nAttr: PAttr = PAttr(importedNode)
-    nAttr.FOwnerDocument = doc
-    nAttr.FParentNode = nil
-    nAttr.FOwnerElement = nil
-    nAttr.FSpecified = True
-    return nAttr
-  of DocumentFragmentNode:
-    var n: PNode
-    new(n)
-    n = importedNode
-    n.FOwnerDocument = doc
-    n.FParentNode = nil
-
-    n.FOwnerDocument = doc
-    n.FParentNode = nil
-    var tmp: seq[PNode] = n.childNodes
-    n.childNodes = @[]
-    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
-    new(n)
-    n = importedNode
-    n.FOwnerDocument = doc
-    n.FParentNode = nil
-    
-    var tmpA: seq[PAttr] = n.attributes
-    n.attributes = @[]
-    # Import the Element node's attributes
-    for i in low(tmpA.len())..high(tmpA.len()):
-      n.attributes.add(PAttr(importNode(doc, tmpA[i], deep)))
-    # Import the childNodes
-    var tmp: seq[PNode] = n.childNodes
-    n.childNodes = @[]
-    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
-    new(n)
-    n = importedNode
-    n.FOwnerDocument = doc
-    n.FParentNode = nil
-    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:
-    return n.childNodes[0]
-  else:
-    return nil
-  
-proc lastChild*(n: PNode): PNode =
-  ## Returns this node's last child
-
-  if n.childNodes.len() > 0:
-    return n.childNodes[n.childNodes.len() - 1]
-  else:
-    return nil
-  
-proc localName*(n: PNode): string =
-  ## Returns this nodes local name
-
-  return n.FLocalName
-
-proc namespaceURI*(n: PNode): string =
-  ## Returns this nodes namespace URI
-  
-  return n.FNamespaceURI
-  
-proc `namespaceURI=`*(n: PNode, value: string) = 
-  n.FNamespaceURI = value
-
-proc nextSibling*(n: PNode): PNode =
-  ## Returns the next sibling of this node
-
-  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 nodeName*(n: PNode): string =
-  ## Returns the name of this node
-
-  return n.FNodeName
-
-proc nodeType*(n: PNode): int =
-  ## Returns the type of this node
-
-  return n.FNodeType
-
-proc ownerDocument*(n: PNode): PDocument =
-  ## Returns the owner document of this node
-
-  return n.FOwnerDocument
-
-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
-
-  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
-
-  # Setter
-  # Check if name contains illegal characters
-  if illegalChars in value:
-    raise newException(EInvalidCharacterErr, "Invalid character")
-
-  if n.FNamespaceURI == nil:
-    raise newException(ENamespaceErr, "namespaceURI cannot be nil")
-  elif value.toLower() == "xml" and n.FNamespaceURI != "http://www.w3.org/XML/1998/namespace":
-    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, 
-      "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\"")
-
-  n.FNodeName = value & ":" & n.FLocalName
-  if n.nodeType == ElementNode:
-    var el: PElement = PElement(n)
-    el.FTagName = value & ":" & n.FLocalName
-
-  elif n.nodeType == AttributeNode:
-    var attr: PAttr = PAttr(n)
-    attr.FName = value & ":" & n.FLocalName
-
-# Procedures
-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):
-    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 = 
-  ## Returns a duplicate of this node, if ``deep`` is `true`, Element node's children are copied
-  case n.FNodeType
-  of AttributeNode:
-    var newNode: PAttr
-    new(newNode)
-    newNode = PAttr(n)
-    newNode.FSpecified = True
-    newNode.FOwnerElement = nil
-    return newNode
-  of ElementNode:
-    var newNode: PElement
-    new(newNode)
-    newNode = PElement(n)
-    # Import the childNodes
-    var tmp: seq[PNode] = n.childNodes
-    n.childNodes = @[]
-    if deep:
-      for i in low(tmp.len())..high(tmp.len()):
-        n.childNodes.add(cloneNode(tmp[i], deep))
-    return newNode
-  else:
-    var newNode: PNode
-    new(newNode)
-    newNode = n
-    return newNode
-
-proc hasAttributes*(n: PNode): bool =
-  ## Returns whether this node (if it is an element) has any attributes. 
-  return n.attributes.len() > 0
-
-proc hasChildNodes*(n: PNode): bool = 
-  ## Returns whether this node has any children.
-  return 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.")
-    
-  for i in low(n.childNodes)..high(n.childNodes):
-    if n.childNodes[i] == refChild:
-      n.childNodes.insert(newChild, i - 1)
-    return
-
-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. 
-  return n.FOwnerDocument.FImplementation.hasFeature(feature, version)
-
-proc isEmpty(s: string): bool =
-
-  if s == "" or s == nil:
-    return True
-  for i in items(s):
-    if i != ' ':
-      return False
-  return True
-
-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:
-      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:
-        curTextNode = n.childNodes[i]
-      else:
-        PText(curTextNode).data.add(PText(n.childNodes[i]).data)
-        curTextNode.nodeValue.add(PText(n.childNodes[i]).data)
-        inc(i)
-    else:
-      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
-      
-  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
-  
-  raise newException(ENotFoundErr, "Node not found")
-  
-# NamedNodeMap
-
-proc getNamedItem*(NList: seq[PNode], name: string): PNode =
-  ## 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 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 = 
-  ## 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 item*(NList: seq[PNode], index: int): PNode =
-  ## 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]
-
-proc removeNamedItem*(NList: var seq[PNode], name: string): PNode =
-  ## Removes a node specified by ``name``
-  ## Raises the ``ENotFoundErr`` exception, if the node was not found
-  for i in low(NList)..high(NList):
-    if NList[i].FNodeName == name:
-      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):
-    if NList[i].FLocalName == localName and NList[i].FNamespaceURI == namespaceURI:
-      result = NList[i]
-      NList.delete(i)
-      return result
-  
-  raise newException(ENotFoundErr, "Node not found")
-
-proc setNamedItem*(NList: var seq[PNode], arg: PNode): PNode =
-  ## 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 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.getNamedItem(arg.NodeName())
-  if item == nil:
-    NList.add(arg)
-    return nil
-  else:
-    # Node with the same name exists
-    var index: int = 0
-    for i in low(NList)..high(NList):
-      if NList[i] == item:
-        index = i
-        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 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:
-    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:
-    NList.add(arg)
-    return nil
-  else:
-    # Node with the same name exists
-    var index: int = 0
-    for i in low(NList)..high(NList):
-      if NList[i] == item:
-        index = i
-        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 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:
-    NList.add(arg)
-    return nil
-  else:
-    # Node with the same name exists
-    var index: int = 0
-    for i in low(NList)..high(NList):
-      if NList[i] == item:
-        index = i
-        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):
-    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:
-    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:
-    NList.add(arg)
-    return nil
-  else:
-    # Node with the same name exists
-    var index: int = 0
-    for i in low(NList)..high(NList):
-      if NList[i] == item:
-        index = i
-        break
-    NList[index] = arg
-    return item # Return the replaced node
-    
-# CharacterData - Decided to implement this, 
-# Didn't add the procedures, because you can just edit .data
-
-# Attr
-# Attributes
-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 = 
-  ## Returns this Attributes owner element
-
-  return a.FOwnerElement
-
-# Element
-# Attributes
-
-proc tagName*(el: PElement): string =
-  ## Returns the Element Tag Name
-
-  return el.FTagName
-
-# Procedures
-proc getAttribute*(el: PElement, name: string): string =
-  ## Retrieves an attribute value by ``name``
-  var attribute = el.attributes.getNamedItem(name)
-  if attribute != nil:
-    return attribute.value
-  else:
-    return nil
-
-proc getAttributeNS*(el: PElement, namespaceURI: string, localName: string): string =
-  ## Retrieves an attribute value by ``localName`` and ``namespaceURI``
-  var attribute = el.attributes.getNamedItemNS(namespaceURI, localName)
-  if attribute != nil:
-    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
-  return el.attributes.getNamedItem(name)
-
-proc getAttributeNodeNS*(el: PElement, namespaceURI: string, localName: string): PAttr =
-  ## Retrieves an `Attr` node by ``localName`` and ``namespaceURI``
-  return el.attributes.getNamedItemNS(namespaceURI, localName)
-
-proc getElementsByTagName*(el: PElement, name: string): seq[PNode] =
-  ## Returns a `NodeList` of all descendant `Elements` of ``el`` with a given tag ``name``,
-  ## in the order in which they are encountered in a preorder traversal of this `Element` tree
-  ## If ``name`` is `*`, returns all descendant of ``el``
-  result = el.findNodes(name)
-
-proc getElementsByTagNameNS*(el: PElement, namespaceURI: string, localName: string): seq[PNode] =
-  ## Returns a `NodeList` of all the descendant Elements with a given
-  ## ``localName`` and ``namespaceURI`` in the order in which they are
-  ## encountered in a preorder traversal of this Element tree
-  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
-
-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
-
-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)
-      
-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)
-  
-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
-  
-  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, 
-      "This node belongs to a different document, use importNode.")
-        
-  if newAttr.FOwnerElement != nil:
-    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 
-  ## 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, 
-      "This node belongs to a different document, use importNode.")
-        
-  if newAttr.FOwnerElement != nil:
-    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 
-  ## value is changed to be that of the value parameter
-  ## 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`` 
-  ## 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
-  AttrNode.FOwnerElement = el
-  AttrNode.FSpecified = True
-  AttrNode.value = value
-
-# Text  
-proc splitData*(TextNode: PText, offset: int): PText =
-  ## 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:
-    for i in low(TextNode.FParentNode.childNodes)..high(TextNode.FParentNode.childNodes):
-      if TextNode.FParentNode.childNodes[i] == TextNode:
-        var newNode: PText = TextNode.FOwnerDocument.createTextNode(right)
-        TextNode.FParentNode.childNodes.insert(newNode, i)
-        return newNode
-  else:
-    var newNode: PText = TextNode.FOwnerDocument.createTextNode(right)
-    return newNode
-
-
-# ProcessingInstruction
-proc target*(PI: PProcessingInstruction): string =
-  ## Returns the Processing Instructions target
-
-  return PI.FTarget
-
-    
-# --Other stuff--
-# Writer
-proc addEscaped(s: string): string = 
-  result = ""
-  for c in items(s):
-    case c
-    of '<': result.add("&lt;")
-    of '>': result.add("&gt;")
-    of '&': result.add("&amp;")
-    of '"': result.add("&quot;")
-    else: result.add(c)
-
-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:
-    result.add("/>") # No idea why this doesn't need a \n :O
-  else:
-    # End the beginning of this tag
-    result.add(">\n")
-    for i in items(n.childNodes):
-      case i.nodeType
-      of ElementNode:
-        result.add(nodeToXml(i, indent + 2))
-      of TextNode:
-        result.add(repeatChar(indent * 2, ' '))
-        result.add(addEscaped(i.nodeValue))
-      of CDataSectionNode:
-        result.add(repeatChar(indent * 2, ' '))
-        result.add("<![CDATA[" & i.nodeValue & "]]>")
-      of ProcessingInstructionNode:
-        result.add(repeatChar(indent * 2, ' '))
-        result.add("<?" & PProcessingInstruction(i).target & " " &
-                          PProcessingInstruction(i).data & " ?>")
-      of CommentNode:
-        result.add(repeatChar(indent * 2, ' '))
-        result.add("<!-- " & i.nodeValue & " -->")
-      else:
-        continue
-      result.add("\n")
-    # Add the ending tag - </tag>
-    result.add(repeatChar(indent, ' ') & "</" & n.nodeName & ">")
-
-proc `$`*(doc: PDocument): string =
-  ## Converts a PDocument object into a string representation of it's XML
-  result = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n"
-  result.add(nodeToXml(doc.documentElement))