-
Notifications
You must be signed in to change notification settings - Fork 81
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
IN_PROGRESS: Mutating/Creating nodes #76
Conversation
19a94ca
to
3a3b324
Compare
@hadley I think this is mostly in a good state now and modifying existing nodes has most of the features I think we want (with possible exception of setting the namespace of a node). I wrote a simple vignette to explain the functionality but you can also look at the tests to get a feel for the API. Questions
|
#' then the node will be moved from it's current location. | ||
#' @param value node or nodeset to replace with. | ||
#' @export | ||
`xml_replace<-` <- function(x, copy = TRUE, value) UseMethod("xml_replace<-") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think these look better with {}
For creation, I'm imagining something like: xml_new_node("nodename", child1, child2, attr1 = "foo", attr3 = "bar") I'm not sure how namespaces would work here. One option would be to have special name and attribute constructors: xml_new_node(nsName("url", "nodename"), child1, child2, nsAttr("attr1", "url", "foo")) And instead of url could you use a prefix, if you also supplied the ns map. |
Need to check that we can solve http://stackoverflow.com/questions/32939229/creating-xml-in-r-with-namespaces/32941524#32941524 reasonably elegantly. |
After a81f82c you can now do the following to get the desired XML from the SO post. Maybe it would be nicer to have the second argument to d <- xml_new_document(xml_new_node("sld", version = "1.1.0", xml_new_node("layer", xml_new_node("Name"))))
sld <- xml_find_one(d, "//sld")
name <- xml_find_one(d, "//Name")
xml_new_namespace(sld, "http://www.o.net/sld")
xml_new_namespace(sld, "http://www.o.net/ogc", "ogc")
xml_new_namespace(sld, "http://www.o.net/se", "se")
xml_set_namespace(name, "se")
cat(as.character(d))
#> <?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/></layer></sld> |
Yeah, I like the idea to add multiple namespaces at once. Could we make something like this work? xml_new_document() %>%
xml_add_child("sld", version = "1.1.0") %>%
xml_add_namespace(
"http://www.o.net/sld",
ogc = "http://www.o.net/ogc",
se = "http://www.o.net/se"
) %>%
xml_add_child("layer") %>%
xml_add_child("se:Name") |
Or maybe even: xml_new_document() %>%
xml_add_child("sld",
version = "1.1.0"
ns = "http://www.o.net/sld",
"ns:ogc" = "http://www.o.net/ogc",
"ns:se" = "http://www.o.net/se"
) %>%
xml_add_child("layer") %>%
xml_add_child("se:Name") (That would require more work on the backend to parse the attribute names and create ns objects where necessary) |
Yeah I can get that working. The main issue is the current I think a format like the following will be possible ( xml_new_document() %>%
xml_add_child("sld",
version = "1.1.0"
.ns = c("http://www.o.net/sld",
ogc = "http://www.o.net/ogc",
se = "http://www.o.net/se")
) %>%
xml_add_child("layer") %>%
xml_add_child("se:Name") |
Doing S3 dispatch on character vs. |
How do you create an attribute named 'ns' otherwise? The argument would
|
Oh yeah, I meant |
as of c2fcf36 you can now do d1 <- xml_new_document(
xml_new_node("sld",
version = "1.1.0",
xmlns = "http://www.o.net/sld",
"xmlns:ogc" = "http://www.o.net/ogc",
"xmlns:se" = "http://www.o.net/se") %>%
xml_add_child("layer") %>%
xml_add_child("se:Name"))
as.character(d1)
#> [1] "<?xml version=\"1.0\"?>\n<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/></sld>\n" Using the exact syntax from above for |
As of 2c3c002 you can use the following d1 <- xml_new_document()
xml_add_child(d1, "sld",
version = "1.1.0",
xmlns = "http://www.o.net/sld",
"xmlns:ogc" = "http://www.o.net/ogc",
"xmlns:se" = "http://www.o.net/se") %>%
xml_add_child("layer") %>%
xml_add_child("se:Name")
#> {xml_node}
#> <Name>
as.character(d1)
#> [1] "<?xml version=\"1.0\"?>\n<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/></layer></sld>\n" The only thing preventing you doing a full chain like the original example is that |
Perfect!! @jennybc how does this look to you? |
I will try this out in the next day or two. |
Current coverage is 59.45%@@ master #76 diff @@
==========================================
Files 29 30 +1
Lines 852 1233 +381
Methods 0 0
Messages 0 0
Branches 0 0
==========================================
+ Hits 426 733 +307
- Misses 426 500 +74
Partials 0 0
|
Is there an equivalent of It feels like Am I overlooking some suitably wrapped version of the unexported function |
@jennybc we removed support for creating free nodes, as it makes it impossible to assign a namespace to the nodes on creation. For your use case can't you just If you can point to your XML example code I can also take a look at how it would be converted. |
@jennybc Can you do something like the following? ``` r
mtcars$name <- gsub(" ", "-", row.names(mtcars))
d <- xml_add_child(xml_new_document(), "cars")
add_child <- function(...) {
x <- purrr::map(list(...), as.character)
purrr::invoke(xml_add_child,
c(list(.x = d, .value = x$name), x[names(x) != 'name']))
}
purrr::pwalk(mtcars, add_child)
d
#> {xml_document}
#> <cars>
#> [1] <Mazda-RX4 mpg="21" cyl="6" disp="160" hp="110" drat="3.9" wt="2.62 ...
#> [2] <Mazda-RX4-Wag mpg="21" cyl="6" disp="160" hp="110" drat="3.9" wt=" ...
#> [3] <Datsun-710 mpg="22.8" cyl="4" disp="108" hp="93" drat="3.85" wt="2 ...
#> [4] <Hornet-4-Drive mpg="21.4" cyl="6" disp="258" hp="110" drat="3.08" ...
#> [5] <Hornet-Sportabout mpg="18.7" cyl="8" disp="360" hp="175" drat="3.1 ...
#> [6] <Valiant mpg="18.1" cyl="6" disp="225" hp="105" drat="2.76" wt="3.4 ...
#> [7] <Duster-360 mpg="14.3" cyl="8" disp="360" hp="245" drat="3.21" wt=" ...
#> [8] <Merc-240D mpg="24.4" cyl="4" disp="146.7" hp="62" drat="3.69" wt=" ...
#> [9] <Merc-230 mpg="22.8" cyl="4" disp="140.8" hp="95" drat="3.92" wt="3 ...
#> [10] <Merc-280 mpg="19.2" cyl="6" disp="167.6" hp="123" drat="3.92" wt=" ...
#> [11] <Merc-280C mpg="17.8" cyl="6" disp="167.6" hp="123" drat="3.92" wt= ...
#> [12] <Merc-450SE mpg="16.4" cyl="8" disp="275.8" hp="180" drat="3.07" wt ...
#> [13] <Merc-450SL mpg="17.3" cyl="8" disp="275.8" hp="180" drat="3.07" wt ...
#> [14] <Merc-450SLC mpg="15.2" cyl="8" disp="275.8" hp="180" drat="3.07" w ...
#> [15] <Cadillac-Fleetwood mpg="10.4" cyl="8" disp="472" hp="205" drat="2. ...
#> [16] <Lincoln-Continental mpg="10.4" cyl="8" disp="460" hp="215" drat="3 ...
#> [17] <Chrysler-Imperial mpg="14.7" cyl="8" disp="440" hp="230" drat="3.2 ...
#> [18] <Fiat-128 mpg="32.4" cyl="4" disp="78.7" hp="66" drat="4.08" wt="2. ...
#> [19] <Honda-Civic mpg="30.4" cyl="4" disp="75.7" hp="52" drat="4.93" wt= ...
#> [20] <Toyota-Corolla mpg="33.9" cyl="4" disp="71.1" hp="65" drat="4.22" ...
#> ... |
I am trying to whittle my problem down to something I can either (a) solve or (b) inflict on you @jimhester. |
I choose (b) let @jimhester figure it out. Sorry this is not very minimal, but the examples above and the tests, etc., really don't get into the bits that feel hard about my actual problem. So I present in its full glory. https://gist.github.com/jennybc/37398c989852aa0c7abd9c5cea75e4f6 There's an R script, corresponding md, input as csv, and XML output. |
Some features of the XML creation style of
I think anyone translating from |
Also some small tweaks to reproduce @jennybc's example at https://gist.github.com/jennybc/37398c989852aa0c7abd9c5cea75e4f6
Relying on the finalizer was too error prone.
Clearly this work isn't done, but this PR will be a good place for discussion.