Rev 7747 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed
# These are functions that examine an XML node and# defines a class for each complex type.## Need to make this work recursively#xmlToS4List =function(from, class = xmlName(from), type = gsub("s$", "", xmlName(from))){new(class, xmlApply(from, as, type))}setGeneric("xmlToS4",function(node, obj = new(xmlName(node)), ...)standardGeneric("xmlToS4"))setMethod("xmlToS4", "XMLInternalNode",function(node, obj = new(xmlName(node)), ...){if(is(obj, "character") && !isS4(obj))obj = new(obj)# if(xmlSize(node) == 1 && node[[1]])# return(as())ids = names(node)nodes = xmlChildren(node)obj = addXMLAttributes(obj, xmlAttrs(node, addNamespacePrefix = TRUE))slotIds = slotNames(obj)slots = getClass(class(obj))@slotsif(any(duplicated(ids))) {# experimenting with a different way of doing this.# Group the nodes with the same names and the process those.groupedNodes = split(nodes, ids)ids = intersect(names(groupedNodes), slotIds)for(i in ids) {tmp = groupedNodes[[i]]slot = slots[[i]]if(length(tmp) > 1) {val = lapply(tmp, convertNode, slot)val = if(isAtomicType(slot))unlist(val)elseas(val, slot) # may be a specific sub-type of list} else {el = tmp[[1]]val = convertNode(el, slot)}slot(obj, i) <- val}} else {# This was the original mechanism but it doesn't handle multiple nodes of the same name.for(i in seq(along = nodes)) {if(ids[i] %in% slotIds) {val = if(slots[[ids[i]]] == "character")xmlValue(nodes[[i]])elsetryCatch(as(nodes[[i]], slots[[ids[i]]]),error = function(e)xmlToS4(nodes[[i]]))slot(obj, ids[i]) <- val # xmlToS4(nodes[[i]])}# obj = addAttributes(obj, xmlAttrs(nodes[[i]]))}}obj})convertNode =function(el, slot){if(slot == "character")xmlValue(el)elsetryCatch(as(el, slot),error = function(e)xmlToS4(el))}isAtomicType =## check if className refers to a primitive/atomic type# or not.function(className){atomicTypes = c("logical", "integer", "numeric", "character")if(className %in% atomicTypes)return(TRUE)k = getClassDef(className)length(intersect(names(k@contains), atomicTypes)) > 0}addXMLAttributes =function(obj, attrs){slots = getClass(class(obj))@slotsi = match(names(attrs), names(slots))# handle any namespace prefixif(any(is.na(i))) {w = grepl(":", names(attrs)) & is.na(i)if(any(w))i[which(w)] = match(gsub(".*:", "", names(attrs)[which(w)]), names(slots))}m = iif(any(!is.na(i))) {vals = structure(attrs[!is.na(i)], names = names(slots)[i [!is.na(i)] ])for(i in names(vals))slot(obj, i) <- as(vals[i], slots[[i]])}obj}makeClassTemplate =## Get the class representation information to represent the contents of# an XML node.##function(xnode, types = character(), default = "ANY", className = xmlName(xnode),where = globalenv()){user.types = typesslots = names(xnode)types =xmlSApply(xnode, function(x) {if(xmlSize(x) == 0)defaultelse if(xmlSize(x) == 1 || is(x, "XMLInternalTextNode"))"character"elsexmlName(x)})names(types) = slotstypes[names(xmlAttrs(xnode))] = "character"if(length(user.types))types[names(user.types)] = user.typescoerce = sprintf("setAs('XMLAbstractNode', '%s', function(from) xmlToS4(from))", className)def = if(length(types))sprintf("setClass('%s',\n representation(%s))", className,paste(sQuote(names(types)), sQuote(types), sep = " = ", collapse = ",\n\t"))elsesprintf("setClass('%s')", className)if(!is.null(where) && !(is.logical(where) && !where)) {eval(parse(text = def), envir = where)eval(parse(text = coerce), envir = where)}list(name = className, slots = types,def = def, coerce = coerce)}setAs("XMLAbstractNode", "integer",function(from)as.integer(xmlValue(from)))setAs("XMLAbstractNode", "numeric",function(from)as.numeric(xmlValue(from)))setAs("XMLAbstractNode", "character",function(from)xmlValue(from))setAs("XMLAbstractNode", "URL",function(from)new("URL", xmlValue(from)))setAs("XMLAbstractNode", "logical",function(from)as.logical(xmlValue(from)))setAs("XMLAbstractNode", "Date",function(from)as.Date(xmlValue(from), "%Y-%m-%d"))setAs("XMLAbstractNode", "POSIXct",function(from)as.POSIXct(strptime(xmlValue(from), "%Y-%m-%d %H:%M:%S")))makeXMLClasses =function(doc, omit = character(), eval = FALSE){a = getNodeSet(doc, "//*")ids = unique(sapply(a, xmlName))if(length(omit))ids = setdiff(ids, omit)lapply(ids, function(id) makeClassTemplate(getNodeSet(doc, sprintf("//%s", id))[[1]], where = eval))}