swh:1:snp:7d9f1bc35e120776766db9334626062f837c20ad
Raw File
Tip revision: 169eae30157f9f72819739567a80168687fecadd authored by Duncan Temple Lang on 22 April 2007, 00:00:00 UTC
version 1.7-2
Tip revision: 169eae3
xmlTree.R
xmlTree <-
function(tag = NULL, attrs = NULL, dtd=NULL, namespaces = list(),
          doc = newXMLDoc(dtd, namespaces))
  # Allows a DOCTYPE, etc. at the beginning by specifying dtd as 
  # a vector of 1, 2, 3 elements passed to newXMLDTDNode() or
  # as an XMLDTDNode directly.
  
  # With namespaces, we do the following....
  #
{
 currentNodes <- list(doc)
 
 isXML2 <- libxmlVersion()$major != "1" 

    # if we are given a DTD, add it to the document.
 if(!is.null(dtd)) {
   if(isXML2) {
     node = NULL
     if(is(dtd, "XMLDTDNode"))
       node = dtd
     else if(is.character(dtd) && dtd[1] != "")
       node = newXMLDTDNode(dtd, doc = doc)

     if(!is.null(node)) {
       addChildren(doc, node)
       currentNodes[[2]] <- node #???XXX
     }
   } else
     warning("DTDs not supported in R for libxml 1.*. Use libxml2 instead.")
 }
 
 definedNamespaces = list()
 defaultNamespace = NULL
 setActiveNamespace = function(ns) {
                         defaultNamespace <<- ns
                      }
 
 asXMLNode <- function(x) {
        if(is(x, "XMLInternalNode"))
          return(x)
        
        if(is.list(x)) {
          v <- lapply(x, asXMLNode)
        }  else {
          v <- newXMLTextNode(as.character(x), doc)
        }
        v 
      }


 
 setNamespace <- function(node, namespace = defaultNamespace) {
     if(length(namespace) == 0 || !(length(namespace) == 1 && is.null(names(namespace))))
       return(NULL)

     if(is.list(namespace))
       return(NULL)
     
     if(!is.na(match(namespace, names(namespaces))) && is.na(match(namespace, names(definedNamespaces)))) {
       ns <- .Call("R_xmlNewNs", node, namespaces[[namespace]], namespace)
       definedNamespaces[[namespace]] <<- ns
     }

     setInternalNamespace( node, definedNamespaces[[namespace]])
 }

 
 addTag <- function(name, ..., attrs = NULL, close = TRUE, namespace = defaultNamespace, .children = list(...) ) {

   if(!is.null(attrs))
      storage.mode(attrs) <- "character"

   node <- newXMLNode(name, attrs = attrs, namespace = namespace, doc = doc)

   setNamespace(node, namespace)

   if(length(currentNodes) > 1)
      addChildren(currentNodes[[1]], node)

   currentNodes <<- c(node, currentNodes)

   for(i in .children) 
      addChildren(node, asXMLNode(i))  # vectorize XXX

   if(close == TRUE)
     closeTag()
   
   invisible(return(node))
 }

 closeTag <- function(name="") {
  tmp <- currentNodes[[1]]
  currentNodes <<- currentNodes[-1]

  invisible(return(tmp))
 }


 add = function(node, parent = currentNodes[[1]]) {
        if(!is.null(parent))
            addChildren(currentNodes[[1]], node)
        invisible(node)
       }
 
 addComment <- function(...) {
   add(newXMLCommentNode(paste(as.character(list(...)), sep=""), doc))
 }


 addCData <- function(text) {
   add(newXMLCDataNode(text, doc))
 }

 addPI <- function(name, text) {
   add(newXMLPINode(name, text, doc))
 }


 if(!is.null(tag)) {

   if(is.character(tag)) {
     node = addTag(tag, attrs = attrs, namespace = namespaces, close = FALSE)
   } else if(is(tag, "XMLInternalNode")) {
     if(is.null(xmlParent(node))) # if we have a DTD node, need to add it to that or parallel to that?
       addChildren(doc, node)
   }
   

 }

 v <- list(
         addTag = addTag,
         addNode = addTag,           
         addCData = addCData,
         addPI = addPI,
         closeTag = closeTag,
         closeNode = closeTag,
         addComment = addComment,
         setNamespace = setActiveNamespace,
         value = function() doc,
         doc = function() doc,
         add = function(...){}
       )

 class(v) <- c("XMLInternalDOM", "XMLOutputStream")
 return(v)
}





back to top