Blame | Last modification | View Log | Download | RSS feed
xmlTree <-## Create an XML document using internal nodes and help to manage# the state for the user rather than requiring them to manage# the individual nodes. For the most part, the two approaches# are relatively similar in complexity.##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.#{currentNodes <- list(doc) # the stack of nodesisXML2 <- libxmlVersion()$major != "1"# if we are given a DTD, add it to the document.if(!is.null(dtd)) {if(isXML2) {node = NULLif(inherits(dtd, "XMLDTDNode"))node = dtdelse if(is.character(dtd) && dtd[1] != "")node = newXMLDTDNode(dtd, doc = doc)if(!is.null(node)) {addChildren(doc, node)currentNodes[[2]] <- node #???XXX}} elsewarning("DTDs not supported in R for libxml 1.*. Use libxml2 instead.")}definedNamespaces = list()defaultNamespace = NULLaddNamespaceDefinitions = is.null(tag)setActiveNamespace = function(ns) {defaultNamespace <<- ns}asXMLNode <- function(x) {if(inherits(x, "XMLInternalNode"))return(x)v = if(is.list(x))lapply(x, asXMLNode)elsenewXMLTextNode(as.character(x), doc = doc, escapeEntities = is(x, "AsIs"))v}setNamespace <- function(node, namespace = defaultNamespace) {# if there is no namespace or if we have one and no names on the namespaceif(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, PACKAGE = "XML")definedNamespaces[[namespace]] <<- ns}setXMLNamespace(node, definedNamespaces[[namespace]])#old setInternalNamespace( node, definedNamespaces[[namespace]])}# namespace is intended to be the namespace for this node# and not any definitions.# How do we define new namespaces with this function?# Can we add them to attrs. No!addTag <- function(name, ..., attrs = NULL,close = TRUE, namespace = defaultNamespace, .children = list(...) ){if(inherits(name, "XMLInternalNode")) {addChildren(currentNodes[[1]], name)currentNodes <<- c(node, currentNodes)addChildren(node, kids = .children)if(close)currentNodes <<- currentNodes[-1]return(name)}# if the user gives us something like "r" for the namespace as opposed to# c(r = "http:...") then we try to match the prefix in an earlier node# ??? Should we use the defined namespaces in the document?if(FALSE) {if(length(namespace) == 1 && length(names(namespace)) == 0) {tmp = namespaceif(length(currentNodes)) {defs = namespaceDeclarations(currentNodes[[1]], TRUE)i = match(namespace, names(defs))if(!is.na(i))namespace = defs[[i]]}}}if(!is.null(attrs))storage.mode(attrs) <- "character"if(inherits(name, "XMLInternalNode"))node = nameelse {parent = if(length(currentNodes) > 1)currentNodes[[1]]elsexmlRoot(currentNodes[[1]])node <- newXMLNode(name, attrs = attrs, namespace = namespace,doc = doc, parent = parent,namespaceDefinitions = if(addNamespaceDefinitions) namespaces else NULL)if(addNamespaceDefinitions) {# lapply(seq(along = namespaces),# function(i)# setXMLNamespace(node, namespaces[[i]], names(namespaces)[i]))addNamespaceDefinitions <<- FALSE}}# if(length(currentNodes) > 1)# addChildren(currentNodes[[1]], node)currentNodes <<- c(node, currentNodes)# if(!inherits(name, "XMLInternalNode"))# setNamespace(node, namespace)for(i in .children)addChildren(node, asXMLNode(i)) # vectorize XXXif(close == TRUE)closeTag()invisible(node)}closeTag <- function(name="") {if(nargs() == 0) {tmp <- currentNodes[[1]]currentNodes <<- currentNodes[-1]} else if( is.character(name) ) {w = sapply(currentNodes, inherits, "XMLInternalElementNode")useNamespace = length(grep(":", name)) > 0ids = sapply(currentNodes[ w ], xmlName, useNamespace)tmp = list()for(id in name) {i = which(id == ids)if(length(i) == 0)stop("Cannot close tag for node with name ", id, " - no such node open")tmp = c(tmp, currentNodes[1:i])currentNodes <<- currentNodes[-c(1:i)]ids = ids[-(1:i)]}} else if(inherits(name, "numeric")) {num = nameif(is.na(num) || num == -1)# close all of the nodes, except the document node.w = seq(along = currentNodes[- length(currentNodes)])else if(length(num) == 1)w = 1:numelsew = numtmp = currentNodes[ w ]currentNodes <<- currentNodes[ - w ]}invisible(tmp)}add = function(node, parent = currentNodes[[1]], close = TRUE) {if(!is.null(parent)) {addChildren(parent, node)if(!close)currentNodes <<- c(node, currentNodes)}invisible(node)}addComment <- function(...) {add(newXMLCommentNode(paste(as.character(list(...)), sep=""), doc = doc))}addCData <- function(text) {add(newXMLCDataNode(text, doc = doc))}addPI <- function(name, text) {add(newXMLPINode(name, text, doc = doc), NULL)}# deal with the top-level node the user may have supplied.if(!is.null(tag)) {if(is.character(tag)) {node = addTag(tag, attrs = attrs, namespace = namespaces, close = FALSE)} else if(inherits(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")# vans = new("XMLInternalDOM", v)names(ans) = names(v)ans}setAs("XMLInternalNode", "XMLNode",function(from)asRXMLNode(from))xmlRoot.XMLInternalDOM =function(x, skip = TRUE, ...){xmlRoot(x$doc(), skip = skip)}#??? This was XMLInternalElement and not ...NodexmlRoot.XMLInternalElement = xmlRoot.XMLInternalNode =function(x, skip = TRUE, ...){doc = as(x, "XMLInternalDocument")if(is.null(doc))getRootNode(x) # skip = skip - getRootNode doesn't have a skip argumentelsexmlRoot(doc, skip = skip)}# Get the name of the file/URI for the document.setGeneric("docName", function(doc, ...) standardGeneric("docName"))setMethod("docName", "NULL",function(doc, ...)as.character(NA))setMethod("docName", "XMLNode",function(doc, ...)as.character(NA))setMethod("docName", "XMLHashTreeNode",function(doc, ...)docName(doc$env, ...))docName.XMLInternalDocument =function(doc, ...){.Call("RS_XML_getDocumentName", doc, PACKAGE = "XML")}setMethod("docName", "XMLInternalDocument", docName.XMLInternalDocument)docName.XMLInternalNode =function(doc, ...){docName(as(doc, "XMLInternalDocument"))}setMethod("docName", "XMLInternalNode", docName.XMLInternalNode)docName.XMLDocument =function(doc, ...){doc$doc$file}setMethod("docName", "XMLDocument", docName.XMLDocument)docName.XMLDocumentContent =function(doc, ...){doc$file}setOldClass("XMLDocumentContent")setMethod("docName", "XMLDocumentContent", docName.XMLDocumentContent)setGeneric("docName<-", function(x, value)standardGeneric("docName<-"))setMethod("docName<-", "XMLInternalDocument",function(x, value){.Call("RS_XML_setDocumentName", x, value, PACKAGE = "XML")x})# See hashTree.RsetMethod("docName<-", "XMLHashTree",function(x, value){assign(".doc", value, x)x})parseXMLAndAdd =function(txt, parent = NULL, top = "tmp", nsDefs = character()){txt = paste(txt, collapse = "")if(!inherits(txt, "AsIs") && length(top) > 0) {open = sprintf("%s%s", top,paste(sprintf(' xmlns%s%s="%s"', ifelse(names(nsDefs) != "", ":", ""),names(nsDefs),nsDefs),collapse = ""))tmp = sprintf("<%s>%s</%s>", open, txt, top)} elsetmp = txtdoc = xmlParse(tmp, asText = TRUE)if(!is.null(parent))invisible(.Call("R_insertXMLNode", xmlChildren(xmlRoot(doc)), parent, -1L, FALSE, PACKAGE = "XML"))elsexmlRoot(doc)}