I'm trying to build an XML structure in R that looks like this. Note the default namespace, the other namespaces, and the inner Name
object which is in an alternate namespace:
<?xml version = "1.0" encoding="UTF-8"?>
<sld xmlns="http://www.o.net/sld"
xmlns:ogc="http://www.o.net/ogc"
xmlns:se="http://www.o.net/se"
version="1.1.0" >
<layer>
<se:Name>My Layer</se:Name>
</layer>
</sld>
This code comes close, having the namespaces on the tags okay, but no default namespace in the root tag:
require(XML)
makesimple = function(){
z = xmlTree("sld",
namespaces=list(
"ogc"="http://www.o.net/ogc",
"se"="http://www.o.net/se"),
attrs=list(version="1.1.0")
)
z$addNode("layer", close=FALSE)
z$setNamespace("se")
z$addNode("Name","My Layer")
z$closeTag()
z
}
> cat(saveXML(makesimple()))
gives
<?xml version="1.0"?>
<sld
xmlns:ogc="http://www.o.net/ogc"
xmlns:se="http://www.o.net/se"
version="1.1.0">
<layer>
<se:Name>My Layer</se:Name>
</layer>
</sld>
But if I add a default (unnamed) namespace then setting the namespace for the inner element does nothing. Change one line above to:
z = xmlTree("sld",
namespaces=list("http://www.o.net/sld",
"ogc"="http://www.o.net/ogc",
"se"="http://www.o.net/se"),
attrs=list(version="1.1.0")
)
and that gives me:
<?xml version="1.0"?>
<sld
xmlns="http://www.o.net/sld"
xmlns:ogc="http://www.o.net/ogc"
xmlns:se="http://www.o.net/se"
version="1.1.0">
<layer>
<Name>My Layer</Name>
</layer>
</sld>
which has all the namespaces correct in the root element but the namespace I wanted for the inner element has gone.
Note I started working on this with newXMLDoc
and newXMLNode
functions, until I read the docs which said:
While the functions are available, their direct use is not encouraged. Instead, use ‘xmlTree’ as the functions need to be used within a strict regime to avoid corrupting C level structures.
I'm at the point of giving up constructing these things with package::XML
and just building them with a template system (package::brew
, probably).
Here's a slight variant that also retains the default namespace. FWIW I think XML::newXMLNode()
(in my code) and z$addNode
(in the other answer) are acting counter to the docs and examples in DTL's book (?). You are supposed to be able to specify the "se" namespace here and have it resolve through the namespace definitions in the ancestors. But that doesn't seem to be the case.
library(XML)
makesimple <- function() {
z <- newXMLNode("sld", newXMLNode("layer"), attrs = list(version="1.1.0"),
namespaceDefinitions = c("http://www.o.net/sld",
ogc = "http://www.o.net/ogc",
se = "http://www.o.net/se"))
z_doc <- newXMLDoc(node = z)
Name <- newXMLNode("Name", "My Layer", parent = z[["layer"]])
setXMLNamespace(Name, "se")
z_doc
}
cat(saveXML(makesimple()))
#> <?xml version="1.0"?>
#> <sld xmlns="http://www.o.net/sld" xmlns:ogc="http://www.o.net/ogc" xmlns:se="http://www.o.net/se" version="1.1.0">
#> <layer>
#> <se:Name>My Layer</se:Name>
#> </layer>
#> </sld>
It seems another way to force the namespace resolution is to specify a namespace prefix at the time of node creation, but to NOT specify the parent. Then when the node is added as a child, the namespace does get resolved correctly from the ancestors.
library(XML)
makesimple2 <- function() {
z <- newXMLNode("sld", newXMLNode("layer"), attrs=list(version="1.1.0"),
namespaceDefinitions = c("http://www.o.net/sld",
ogc = "http://www.o.net/ogc",
se = "http://www.o.net/se"))
z_doc <- newXMLDoc(node = z)
Name <- newXMLNode("se:Name", "My Layer")
addChildren(z[["layer"]], Name)
z_doc
}
cat(saveXML(makesimple2()))
#> <?xml version="1.0"?>
#> <sld xmlns="http://www.o.net/sld" xmlns:ogc="http://www.o.net/ogc" xmlns:se="http://www.o.net/se" version="1.1.0">
#> <layer>
#> <se:Name>My Layer</se:Name>
#> </layer>
#> </sld>
Looks like the namespace
argument to addNode
is ignored for this purpose, but here's a work-around:
require(XML)
makesimple = function(){
z = xmlTree("sld",
namespaces=list("http://www.o.net/sld",
"ogc"="http://www.o.net/ogc",
"se"="http://www.o.net/se"),
attrs=list(version="1.1.0")
)
z$addNode("layer", close=FALSE)
# addNode returns the node invisibly, assign so we can use it
nameNode <- z$addNode("Name","My Layer")
setXMLNamespace(nameNode, "se")
z$closeTag()
z
}
cat(saveXML(makesimple()))
# <?xml version="1.0"?>
#
# <sld xmlns:ogc="http://www.o.net/ogc" xmlns:se="http://www.o.net/se" version="1.1.0">
# <layer>
# <se:Name>My Layer</se:Name>
# </layer>
# </sld>
Basically, we use the fact that addNode
returns the node invisibly. We assign that value to a temporary object, so we can use the setXMLNamespace
function on that object.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With