Blame | Last modification | View Log | Download | RSS feed
setGeneric("simplifyNamespaces",function(doc, ...)standardGeneric("simplifyNamespaces"))setMethod("simplifyNamespaces", "character",function(doc, ...) {pdoc = xmlParseDoc(doc, NSCLEAN)simplifyNamespaces(pdoc, ...)})xmlCleanNamespaces =## @eg xmlParse("~/GitWorkingArea/XML/inst/exampleData/redundantNS.xml")## ?Should we write the result to a file if we are given a file?##function(doc, options = integer(), out = docName(doc), ...){if(is(doc, "XMLInternalDocument"))doc = saveXML(doc)options = unique(c(options, NSCLEAN))newDoc = xmlParse(doc, ..., options = options)if(is.logical(out))out = if(out) docName(doc) else character()if(is.character(out) && length(out))saveXML(newDoc, out)elsenewDoc}setMethod("simplifyNamespaces", "XMLInternalDocument",function(doc, alreadyCleaned = FALSE, ...) {# find all the nodes, but discard the root node.allNodes = getNodeSet(doc, "//node()") # [-1]root = xmlRoot(doc)# For each node, get its namespace definitions,# and then zoom in on the nodes that have namespace definitions.nsDefs = lapply(allNodes, xmlNamespaceDefinitions, simplify = TRUE)w = sapply(nsDefs, length) > 0tmp = structure(unlist(nsDefs[w]), names = sapply(nsDefs[w], names))d = data.frame(uri = tmp, prefix = names(tmp), stringsAsFactors = FALSE)multi = unlist(by(d, d$prefix, function(x) if(length(unique(x$uri)) == 1) character() else x$prefix[1]))if(length(multi))d = d[ ! (d$prefix %in% multi), ]# Now we can move these namespace definitions to the top.###by(d, nsDefs,function(x) {u = unique(x$prefix)})# remove thesapply(allNodes[w], removeXMLNamespaces)nsDefs})getNodeNamespace =# Figure out what namespace to use for this node and return a reference to that# namespace definition object in C (a xmlNsPtr)function(ns, nsDefs, node, namespace, noNamespace, namespaceDefinitions = NULL, parent = NULL,suppressNamespaceWarning = FALSE){if(noNamespace)return(NULL)if(is.character(namespace) && length(namespace) == 1L && !is.na(namespace) && namespace == "") {if(length(namespaceDefinitions) == 0)return(findNamespaceDefinition(node, ""))}if((is.list(namespace) || is.character(namespace)) && length(namespace) > 0) {# a single element with no name so this is the prefix.if(length(namespace) == 1 && length(names(namespace)) == 0) {if(namespace %in% namespaceDefinitions) {i = match(namespace, namespaceDefinitions)ns = nsPrefix = names(namespaceDefinitions)[i]} else if(namespace != "") {ns = nsPrefix = namespace}} else {# we have names and/or more than one element. So these are namespace definitionsif(length(names(namespace)) == 0)names(namespace) <- rep("", length(namespace))if(length(namespace) > 1 && !is.na(match(namespace[1], names(namespace)[-1]))) {if(length(ns))warning("ignoring first element of namespace and using prefix from node name, ", ns)else {ns = namespace[1]namespace = namespace[-1]}}if(length(namespace) > 1 && sum(names(namespace) == "") > 1)warning("more than one namespace to use as the default")nsDefs = lapply(seq(along = namespace),function(i) {prefix = names(namespace)[i]newNamespace(node, namespace[[i]], prefix)# Don't set the namespace. This is just a definition/declaration for# this node, but not necessarily the namespace to use for this node.# We set this below})names(nsDefs) = names(namespace)}}# Now handle the prefix for this node.if(length(ns)) {i = match(ns, names(nsDefs))if(is.na(i)) {if(!is.null(parent))ns = findNamespaceDefinition(node, ns)else {# raiseNsWarning(ns, suppressNamespaceWarning)# attr(node, "xml:namespace") = ns# ns = NULLns = newNamespace(node, character(), ns)}if(!inherits(ns, "XMLNamespaceRef"))ns <- newNamespace(node, ns, "")} elsens <- nsDefs[[i]]} else {i = match("", names(nsDefs))ns = if(is.na(i)) NULL else nsDefs[[i]]# if now namespace and we have a parent, use its namespace# if it has a namespaceif(!noNamespace && length(ns) == 0 && length(parent) > 0) {ns = xmlNamespaceRef(parent)if(!is.null(ns) && names(as(ns, "character")) != "")ns = NULL}}ns}raiseNsWarning =function(ns, suppressNamespaceWarning){if(is.character(suppressNamespaceWarning))f = get(suppressNamespaceWarning, mode = "function")else if(is.logical(suppressNamespaceWarning)) {if(!suppressNamespaceWarning)f = warningelsereturn(NULL)} elsef = function(...) {}f("cannot find namespace definition for '", ns, "' because the node is not in a document and there are no matching local namespace definitions for this node")}fixDummyNS =function(node, suppressNamespaceWarning = getOption('suppressXMLNamespaceWarning', FALSE)){return(NULL)nodes = getNodeSet(node, "//*[./namespace::*[. = '<dummy>']]", addFinalizer = FALSE)lapply(nodes, completeDummyNS, suppressNamespaceWarning = suppressNamespaceWarning)}completeDummyNS =function(node, suppressNamespaceWarning = getOption('suppressXMLNamespaceWarning', FALSE)){if(is.null(xmlParent(node)))return(FALSE)prefix = names(xmlNamespace(node))ns = findNamespaceDefinition(xmlParent(node), prefix, error = FALSE)if(is.null(ns))raiseNsWarning(prefix, suppressNamespaceWarning)# (if(suppressNamespaceWarning) warning else stop)("can't find namespace definition for prefix ", prefix)else {# remove the current namespace definition and kill it..Call("R_replaceDummyNS", node, ns, prefix, PACKAGE = "XML")# setXMLNamespace(node, ns)}}